namespace Riddle { public class SharedKeyRiddle : Riddle { private uint8[] shared_key { get; set; } private uint8[] token { get; set; } private const int TOKEN_SIZE = 5120; public InetSocketAddress app_socket_address { get; set; } public SharedKeyRiddle(uint8[] shared_key) { this.shared_key = shared_key; token = new uint8[TOKEN_SIZE]; Sodium.Random.random_bytes (token); } public static uint8[] generate_key() { return Sodium.Symmetric.generate_key(); } protected override uint8[] generate (uint8[] secret) { var nonce = new uint8[Sodium.Symmetric.NONCE_BYTES]; Sodium.Random.random_bytes (nonce); var message = join_data (token, secret); var cyphertext = Sodium.Symmetric.encrypt (message, shared_key, nonce); return join_data (nonce, cyphertext); } protected override GLib.InetSocketAddress? validate (uint8[] solution) { for(int i = 0; i < solution.length && i < TOKEN_SIZE; i++) { if(token[i] != solution[i]) { return null; } } return app_socket_address; } public override Solution? solve (uint8[] riddle) { var nonce = riddle[0:Sodium.Symmetric.NONCE_BYTES]; var cyphertext = riddle[Sodium.Symmetric.NONCE_BYTES:]; var message = Sodium.Symmetric.decrypt (cyphertext, shared_key, nonce); var token = message[0:TOKEN_SIZE]; var secret = message[TOKEN_SIZE:]; print(@"Token starts with $(token[0])\n"); return new Solution (secret, token); } } }