1 module drypt.nacl.api; 2 3 public import dcrypt.nacl.secretbox; 4 public import dcrypt.nacl.box; 5 public import dcrypt.exceptions: InvalidCipherTextException; 6 7 public import dcrypt.random.random: randombytes = nextBytes; 8 public import dcrypt.util: wipe; 9 10 public alias secretbox crypto_secretbox; 11 public alias secretbox_open crypto_secretbox_open; 12 public alias box crypto_box; 13 public alias box_open crypto_box_open; 14 public alias box_pubkey crypto_box_pubkey; 15 public alias box_keypair crypto_box_keypair; 16 17 /// Encrypt and decrypt a message using symmetric authenticated encryption. 18 unittest { 19 ubyte[32] secret_key; 20 ubyte[24] nonce; 21 22 /// Generate a random key. 23 randombytes(secret_key); 24 25 /// Generate a unique nonce. 26 /// Don't use the same nonce together with the same key more than once. 27 randombytes(nonce); 28 29 const ubyte[] msg = cast (const ubyte[]) "Hi Bob!"; 30 31 /// Let's encrypt! 32 ubyte[] boxed = crypto_secretbox(msg, nonce, secret_key); /// This can now be transmitted over a insecure channel. 33 34 ubyte[] recv_msg; 35 // Decrypt the message. 36 try { 37 recv_msg = crypto_secretbox_open(boxed, nonce, secret_key); 38 assert(recv_msg == msg, "Decryption produced unexpected result."); 39 } catch(InvalidCipherTextException e) { 40 /// An exception is thrown if the cipher text is not valid. 41 /// This is the case if either the ciphertext is not the result 42 /// of crypto_secretbox with the same key and nonce. 43 assert(false); 44 } 45 46 /// Possibly someone tries to maliciously modify the encrypted message ... 47 ubyte[] tampered = boxed.dup; 48 tampered[$-1] ^= 1; 49 50 /// ... then decryption fails. 51 bool exceptionThrown = false; 52 try { 53 recv_msg = crypto_secretbox_open(tampered, nonce, secret_key); 54 } catch(InvalidCipherTextException e) { 55 exceptionThrown = true; 56 } 57 assert(exceptionThrown, "Tampered message has not been rejected!"); 58 } 59 60 61 /// Encrypt and decrypt a message using asymmetric authenticated encryption. 62 unittest { 63 64 ubyte[32] alice_sk, bob_sk, alice_pk, bob_pk; 65 66 /// Make sure sensitive data gets erased on scope exit. 67 scope(exit) { 68 wipe(alice_sk); 69 wipe(bob_sk); 70 } 71 72 /// Generate two random keypairs. 73 crypto_box_keypair(alice_sk, alice_pk); 74 crypto_box_keypair(bob_sk, bob_pk); 75 76 /// If you already have your secret key, that's the way to get the public key: 77 /// alice_pk = crypto_box_pubkey(alice_sk); /// Alice's public key 78 /// bob_pk = crypto_box_pubkey(bob_sk); /// Bob's public key 79 80 ubyte[24] shared_nonce; /// A shared nonce. Can be transmitted in plaintext. 81 randombytes(shared_nonce); 82 83 /// Alice sends a message to Bob. 84 const ubyte[] msg = cast (const ubyte[]) "Hi Bob!"; 85 ubyte[] boxed = crypto_box(msg, shared_nonce, alice_sk, bob_pk); 86 87 /// Bob receives two messages, one has been modified by Eve. 88 ubyte[] tampered = boxed.dup; 89 tampered[$-1] ^= 1; 90 91 /// Bob decrypts the messages 92 93 ubyte[] recv_msg; 94 95 // The message as sent by alice 96 try { 97 recv_msg = crypto_box_open(boxed, shared_nonce, bob_sk, alice_pk); 98 assert(recv_msg == msg, "Decryption produced unexpected result."); 99 } catch(InvalidCipherTextException e) { 100 assert(false); 101 } 102 103 // Try to decrypt the forged message. 104 bool exceptionThrown = false; 105 try { 106 recv_msg = crypto_box_open(tampered, shared_nonce, bob_sk, alice_pk); 107 assert(false, "Tampered message has not been rejected!"); 108 } catch(InvalidCipherTextException e) { 109 exceptionThrown = true; 110 } 111 assert(exceptionThrown, "Tampered message has not been rejected!"); 112 } 113 114 /// Generate a keypair. 115 public void box_keypair(out ubyte[32] sk, out ubyte[32] pk) nothrow @safe @nogc { 116 randombytes(sk); 117 pk = box_pubkey(sk[]); 118 } 119