Skip to content

Instantly share code, notes, and snippets.

@EionRobb
Last active November 28, 2017 10:17
Show Gist options
  • Save EionRobb/2c49ad508bb263f9c6499b41d2c6f3ab to your computer and use it in GitHub Desktop.
Save EionRobb/2c49ad508bb263f9c6499b41d2c6f3ab to your computer and use it in GitHub Desktop.
<?php
if (!is_callable('sodium_crypto_sign_detached')) {
function sodium_crypto_sign_detached($message, $key) {
return substr(sodium_crypto_sign($message, $key), 0, 64);
}
}
function encode_base64($data) {
return rtrim(base64_encode($data), '=');
}
function ksort_recursive(&$array, $sort_flags = SORT_REGULAR) {
if (!is_array($array) && !is_object($array)) return false;
if (empty((array) $array)) return false; // Don't convert empty objects to arrays
$array = (array) $array;
ksort($array, $sort_flags);
foreach ($array as &$arr) {
ksort_recursive($arr, $sort_flags);
}
return true;
}
function sign_json($json_object, $signing_key, $signing_name)
{
if (is_array($json_object)) {
if (isset($json_object['signatures'])) {
$signatures = $json_object['signatures'];
unset($json_object['signatures']);
}
if (isset($json_object['unsigned'])) {
$unsigned = $json_object['unsigned'];
unset($json_object['unsigned']);
}
} else {
if (isset($json_object->signatures)) {
$signatures = $json_object->signatures;
unset($json_object->signatures);
}
if (isset($json_object->unsigned)) {
$unsigned = $json_object->unsigned;
unset($json_object->unsigned);
}
}
ksort_recursive($json_object);
$signed = sodium_crypto_sign_detached(json_encode($json_object, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $signing_key['key']);
$signature_base64 = encode_base64($signed);
$key_id = $signing_key['alg'] . ':' . $signing_key['version'];
$signatures[$signing_name][$key_id] = $signature_base64;
if (is_array($json_object)) {
$json_object["signatures"] = $signatures;
if (!empty($unsigned)) {
$json_object["unsigned"] = $unsigned;
}
} else {
$json_object->signatures = $signatures;
if (!empty($unsigned)) {
$json_object->unsigned = $unsigned;
}
}
return $json_object;
}
$signing_key = @json_decode(file_get_contents('./signing_key.json'), true);
if (empty($signing_key) || !$signing_key['seed']) {
$seed = random_bytes(32);
$keypair = sodium_crypto_sign_seed_keypair($seed);
$keypair_secret = sodium_crypto_sign_secretkey($keypair);
$keypair_public = sodium_crypto_sign_publickey($keypair);
$signing_key = array(
'key' => $keypair_secret,
'public' => $keypair_public,
'alg' => 'ed25519',
'version' => '2',
);
$json = '{"seed":"' . bin2hex($seed) . '","key":"' . bin2hex($keypair_secret) . '","public":"' . bin2hex($keypair_public) . '","alg":"ed25519","version":"2"}';
file_put_contents('./signing_key.json', $json);
} else {
$signing_key['key'] = hex2bin($signing_key['key']);
$signing_key['public'] = hex2bin($signing_key['public']);
}
$data = array();
$data['server_name'] = $config['server_name'];
$data['verify_keys'] = array(
$signing_key['alg'] . ':' . $signing_key['version'] =>
array(
'key' => encode_base64($signing_key['public']),
),
);
$data['old_verify_keys'] = new StdClass();
$data['tls_fingerprints'] = array();
$data['valid_until_ts'] = (strtotime('midnight +10 days')) * 1000;
header('Content-Type: application/json');
echo json_encode(sign_json($data, $signing_key, $config['server_name']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment