1 module box; 2 3 import random; 4 5 extern (C) { 6 size_t crypto_box_seedbytes(); 7 size_t crypto_box_publickeybytes(); 8 size_t crypto_box_secretkeybytes(); 9 size_t crypto_box_beforenmbytes(); 10 size_t crypto_box_noncebytes(); 11 size_t crypto_box_zerobytes(); 12 size_t crypto_box_boxzerobytes(); 13 size_t crypto_box_macbytes(); 14 15 char *crypto_box_primitive(); 16 17 int crypto_box_seed_keypair(ref ubyte[32] pk, ref ubyte[32] sk); 18 int crypto_box_keypair(ref ubyte[32] pk, ref ubyte[32] sk); 19 int crypto_box_easy(ubyte *c, ubyte *m, ulong mlen, ref ubyte[24] n, ref ubyte[32] pk, ref ubyte[32] sk); 20 int crypto_box_open_easy(ubyte *m, ubyte *c, ulong clen, ref ubyte[24] n, ref ubyte[32] pk, ref ubyte[32] sk); 21 } 22 23 struct EncryptedBoxMessage { 24 ubyte[] message; 25 ubyte[24] nonce; 26 } 27 28 class BoxKeyPair { 29 ubyte[32] public_key; 30 ubyte[32] secret_key; 31 32 this() { 33 assert(crypto_box_keypair(this.public_key, this.secret_key) == 0); 34 } 35 36 this(ubyte[32] pkey, ubyte[32] skey) { 37 this.public_key = pkey; 38 this.secret_key = skey; 39 } 40 41 EncryptedBoxMessage encrypt(string data, BoxKeyPair other) { 42 return this.encrypt(cast(ubyte[])data, other); 43 } 44 45 EncryptedBoxMessage encrypt(ubyte[] data, BoxKeyPair other) { 46 ubyte[24] nonce; 47 randombytes_buf(&nonce[0], 24); 48 return this.encrypt(data, nonce, other); 49 } 50 51 EncryptedBoxMessage encrypt(ubyte[] data, ubyte[24] nonce, BoxKeyPair other) { 52 ubyte[] output = new ubyte[data.length + crypto_box_macbytes()]; 53 54 assert(crypto_box_easy(&output[0], &data[0], data.length, nonce, other.public_key, this.secret_key) == 0); 55 return EncryptedBoxMessage(output, nonce); 56 } 57 58 ubyte[] decrypt(EncryptedBoxMessage msg, BoxKeyPair other) { 59 ubyte[] output = new ubyte[msg.message.length - crypto_box_macbytes()]; 60 assert(crypto_box_open_easy(&output[0], &msg.message[0], msg.message.length, msg.nonce, other.public_key, this.secret_key) == 0); 61 return output; 62 } 63 64 } 65 66 unittest { 67 auto jim = new BoxKeyPair; 68 auto alex = new BoxKeyPair; 69 70 // Test that encryption works 71 EncryptedBoxMessage emsg = jim.encrypt("hey alex, your password is 1", alex); 72 assert(alex.decrypt(emsg, jim) == "hey alex, your password is 1"); 73 74 // Test that encryption with custom nonce works 75 ubyte[24] nonce = cast(ubyte[24])"nonce"; 76 ubyte[] msg = cast(ubyte[])"test"; 77 EncryptedBoxMessage noncemsg = jim.encrypt(msg, nonce, alex); 78 assert(alex.decrypt(noncemsg, jim) == msg); 79 assert(noncemsg.nonce == nonce); 80 }