Skip to content

Instantly share code, notes, and snippets.

@wiktor-k
Last active October 8, 2018 15:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wiktor-k/e31c54bb073267ff49e633e2f7577ed2 to your computer and use it in GitHub Desktop.
Save wiktor-k/e31c54bb073267ff49e633e2f7577ed2 to your computer and use it in GitHub Desktop.
const { sign } = require('tweetnacl');
var PORT = 2002 ;
var HOST = 'roughtime.cloudflare.com';
function unbase64(s) {
return Uint8Array.from(Buffer.from(s, 'base64'))
}
function bytes(s) {
return Uint8Array.from(s.split('').map(c => c.charCodeAt(0)))
}
var PUBKEY = unbase64('gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo=');
const certificateContext = bytes('RoughTime v1 delegation signature--\x00')
const signedResponseContext = bytes('RoughTime v1 response signature\x00')
var dgram = require('dgram');
var message = Buffer.from(new Uint8Array(1024));
// num_tags
message[0] = 2;
message[1] = 0;
message[2] = 0;
message[3] = 0;
message[4] = 64;
message[5] = 0;
message[6] = 0;
message[7] = 0;
message[8] = 'NONC'.charCodeAt(0);
message[9] = 'NONC'.charCodeAt(1);
message[10] = 'NONC'.charCodeAt(2);
message[11] = 'NONC'.charCodeAt(3);
message[12] = 'PAD\xff'.charCodeAt(0);
message[13] = 'PAD\xff'.charCodeAt(1);
message[14] = 'PAD\xff'.charCodeAt(2);
message[15] = 'PAD\xff'.charCodeAt(3);
message[16] = 10;
function parseMessage(message, nested = []) {
const numTags = message.readUInt32LE();
const offsets = [];
let base = 4;
for (let i = 1; i < numTags; i++, base += 4) {
offsets.push(message.readUInt32LE(base));
}
const tags = [];
for (let i = 0; i < numTags; i++, base += 4) {
const tag = String.fromCharCode(...message.slice(base, base + 4));
tags.push(tag);
}
const values = Object.create(null);
let previous = base;
for (const offset of offsets) {
const tag = tags.shift();
const value = message.slice(previous, base + offset);
if (nested.includes(tag)) {
values[tag] = parseMessage(value, nested);
values[tag][Symbol.iterator] = value[Symbol.iterator].bind(value);
} else {
values[tag] = value;
}
previous = base + offset;
}
const tag = tags.shift();
const value = message.slice(previous);
if (nested.includes(tag)) {
values[tag] = parseMessage(value, nested);
values[tag][Symbol.iterator] = value[Symbol.iterator].bind(value);
} else {
values[tag] = value;
}
return values;
}
//console.log(parseMessage(Buffer.from('050000004000000040000000a40000003c01000053494700504154485352455043455254494e4458261d3916458e4ecbcdc541ffe9f26d72948ab8854be68e86fad78340acb6a839ac31bafa8f834954a8240f45a685cbf87ed9f5cdd1ea8d105f5cca534c536c0e03000000040000000c000000524144494d494450524f4f5440420f0018a9f0cb2a770500112c9e2da17139fdc47bfcdfe1cc7bba13b2cdb52704e806097d2dfb6de12151287c0cf1c7af071ae833b76825c539d858ad8f87c57b89a955a6536593a4832902000000400000005349470044454c457599c5fcace0b5e88679894b37ac55850a4c2d45b91081c961bf99db25aca23faa0b83fe6eecb0195b1e1f416202c574c2b20005d48a9985955f7741ba0a5a060300000020000000280000005055424b4d494e544d415854a5ae11d78af929abef9c8c52338459ccf92bdf843eba7d5eb19b540c68336ebc0000000000000000ffffffffffffffff00000000', 'hex'), ['SREP', 'CERT', 'DELE']));
//process.exit(1);
//console.log(message.toString('hex'));
var client = dgram.createSocket('udp4');
client.on('listening', function () {
console.log('UDP Server listening');
});
client.on('message', function (message, remote) {
console.log(remote.address + ':' + remote.port +' - ' + message.toString('utf8'));
console.log(message.length);
const msg = parseMessage(message, ['SREP', 'CERT', 'DELE']);
console.log(msg);
verifySig(Uint8Array.from(
[...msg.CERT['SIG\00'], ...certificateContext, ...msg.CERT.DELE]
), PUBKEY);
verifySig(Uint8Array.from(
[...msg['SIG\00'], ...signedResponseContext, ...msg.SREP]
), msg.CERT.DELE.PUBK);
const midp = BigInt(msg.SREP.MIDP.readUInt32LE(4)) * 0xffffffffn
+ BigInt(msg.SREP.MIDP.readUInt32LE());
console.log(new Date(Number(midp / 1000n)));
client.close();
});
function verifySig(signature, key) {
let res = sign.open(signature, key);
console.log('!-->SIG VALID?: ' + (res !== null));
}
client.on('error', console.error.bind(console));
client.on('close', () => console.log('close'))
client.send(message, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT + ': ' + bytes);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment