1 // Written in the D programming language. 2 3 module wrapper.sodium.crypto_secretbox; 4 5 import wrapper.sodium.core; // assure sodium got initialized 6 7 public 8 import deimos.sodium.crypto_secretbox : crypto_secretbox_KEYBYTES, 9 crypto_secretbox_keybytes, 10 crypto_secretbox_NONCEBYTES, 11 crypto_secretbox_noncebytes, 12 crypto_secretbox_MACBYTES, 13 crypto_secretbox_macbytes, 14 crypto_secretbox_PRIMITIVE, 15 /* crypto_secretbox_primitive, 16 crypto_secretbox_easy, 17 crypto_secretbox_open_easy, 18 crypto_secretbox_detached, 19 crypto_secretbox_open_detached, */ 20 crypto_secretbox_keygen; 21 /* crypto_secretbox_ZEROBYTES, 22 crypto_secretbox_zerobytes, 23 crypto_secretbox_BOXZEROBYTES, 24 crypto_secretbox_boxzerobytes, 25 crypto_secretbox, 26 crypto_secretbox_open; */ 27 28 import std.exception : assertThrown; 29 import nogc.exception: enforce; 30 31 32 string crypto_secretbox_primitive() pure nothrow @nogc @trusted 33 { 34 import std..string : fromStringz; 35 static import deimos.sodium.crypto_secretbox; 36 return fromStringz(deimos.sodium.crypto_secretbox.crypto_secretbox_primitive()); // strips terminating \0 37 } 38 39 // overloading some functions between module deimos.sodium.crypto_secretbox and this module 40 41 alias crypto_secretbox_easy = deimos.sodium.crypto_secretbox.crypto_secretbox_easy; 42 43 bool crypto_secretbox_easy(scope ubyte[] c, 44 scope const ubyte[] m, 45 const ubyte[crypto_secretbox_NONCEBYTES] nonce, 46 const ubyte[crypto_secretbox_KEYBYTES] key) @nogc @trusted 47 { 48 const c_expect_len = m.length + crypto_secretbox_MACBYTES; 49 // enforce(c.length == c_expect_len, "Expected c.length: ", c.length, " to be equal to m.length + crypto_secretbox_MACBYTES: ", c_expect_len); 50 enforce(c.length == c_expect_len, "Expected c.length is not equal to m.length + crypto_secretbox_MACBYTES"); 51 return crypto_secretbox_easy(c.ptr, m.ptr, m.length, nonce.ptr, key.ptr) == 0; // __attribute__ ((nonnull(1, 4, 5))); 52 } 53 54 alias crypto_secretbox_open_easy = deimos.sodium.crypto_secretbox.crypto_secretbox_open_easy; 55 56 bool crypto_secretbox_open_easy(scope ubyte[] m, 57 scope const ubyte[] c, 58 const ubyte[crypto_secretbox_NONCEBYTES] nonce, 59 const ubyte[crypto_secretbox_KEYBYTES] key) @nogc @trusted 60 { 61 // enforce(c.length >= crypto_secretbox_MACBYTES, "Expected c.length: ", c.length, " to be greater_equal to crypto_secretbox_MACBYTES: ", crypto_secretbox_MACBYTES); 62 enforce(c.length >= crypto_secretbox_MACBYTES, "Expected c.length is not greater_equal to crypto_secretbox_MACBYTES"); 63 const m_expect_len = c.length - crypto_secretbox_MACBYTES; 64 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to c.length - crypto_secretbox_MACBYTES: ", m_expect_len); 65 enforce(m.length == m_expect_len, "Expected m.length is not equal to c.length - crypto_secretbox_MACBYTES"); 66 return crypto_secretbox_open_easy(m.ptr, c.ptr, c.length, nonce.ptr, key.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); 67 } 68 69 alias crypto_secretbox_detached = deimos.sodium.crypto_secretbox.crypto_secretbox_detached; 70 71 bool crypto_secretbox_detached(scope ubyte[] c, 72 out ubyte[crypto_secretbox_MACBYTES] mac, 73 scope const ubyte[] m, 74 const ubyte[crypto_secretbox_NONCEBYTES] nonce, const ubyte[crypto_secretbox_KEYBYTES] key) @nogc @trusted 75 { 76 // enforce(c.length == m.length, "Expected c.length: ", c.length, " to be equal to m.length: ", m.length); 77 enforce(c.length == m.length, "Expected c.length is not equal to m.length"); 78 return crypto_secretbox_detached(c.ptr, mac.ptr, m.ptr, m.length, nonce.ptr, key.ptr) == 0; // __attribute__ ((nonnull(1, 2, 5, 6))); 79 } 80 81 alias crypto_secretbox_open_detached = deimos.sodium.crypto_secretbox.crypto_secretbox_open_detached; 82 83 bool crypto_secretbox_open_detached(scope ubyte[] m, 84 scope const ubyte[] c, 85 const ubyte[crypto_secretbox_MACBYTES] mac, 86 const ubyte[crypto_secretbox_NONCEBYTES] nonce, 87 const ubyte[crypto_secretbox_KEYBYTES] key) @nogc @trusted 88 { 89 // enforce(m.length == c.length, "Expected m.length: ", m.length, " to be equal to c.length: ", c.length); 90 enforce(m.length == c.length, "Expected m.length is not equal to c.length"); 91 return crypto_secretbox_open_detached(m.ptr, c.ptr, mac.ptr, c.length, nonce.ptr, key.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6))); 92 } 93 94 /* No overloads for -- NaCl compatibility interface ; Requires padding -- */ 95 96 @system 97 unittest { 98 import std.stdio : writeln; 99 import wrapper.sodium.randombytes : randombytes; 100 import deimos.sodium.crypto_secretbox; 101 102 writeln("unittest block 1 from sodium.crypto_secretbox.d"); 103 104 ubyte[crypto_secretbox_NONCEBYTES] nonce = void; 105 ubyte[crypto_secretbox_KEYBYTES] key = void; 106 randombytes(nonce); 107 randombytes(key); 108 109 enum message_len = 4; 110 ubyte[crypto_secretbox_ZEROBYTES + message_len] message, ciphertext, decrypted; 111 message[crypto_secretbox_ZEROBYTES..crypto_secretbox_ZEROBYTES+message_len] = [116, 101, 115, 116]; 112 assert(crypto_secretbox (ciphertext.ptr, message.ptr, message.length, nonce.ptr, key.ptr) == 0); 113 assert(crypto_secretbox_open(decrypted.ptr, ciphertext.ptr, ciphertext.length, nonce.ptr, key.ptr) == 0); 114 assert(decrypted == message); 115 // writeln("decrypted: ", decrypted[crypto_secretbox_ZEROBYTES..crypto_secretbox_ZEROBYTES+message_len]); // decrypted: [116, 101, 115, 116] 116 } 117 118 @safe 119 unittest { 120 import std..string : representation; 121 import std.stdio : writeln; 122 import wrapper.sodium.randombytes : randombytes; 123 import wrapper.sodium.utils : sodium_increment; 124 125 debug writeln("unittest block 2 from sodium.crypto_secretbox.d"); 126 127 assert(crypto_secretbox_keybytes() == crypto_secretbox_KEYBYTES); 128 assert(crypto_secretbox_noncebytes() == crypto_secretbox_NONCEBYTES); 129 assert(crypto_secretbox_macbytes() == crypto_secretbox_MACBYTES); 130 assert(crypto_secretbox_primitive() == crypto_secretbox_PRIMITIVE); 131 132 auto message = representation("test"); 133 // avoid heap allocation, like in the example code 134 enum MESSAGE_LEN = 4; 135 enum CIPHERTEXT_LEN = (crypto_secretbox_MACBYTES + MESSAGE_LEN); 136 137 ubyte[crypto_secretbox_NONCEBYTES] nonce = void; 138 ubyte[crypto_secretbox_KEYBYTES] key = void; 139 ubyte[CIPHERTEXT_LEN] ciphertext = void; 140 141 randombytes(nonce); 142 crypto_secretbox_keygen(key); 143 assertThrown(crypto_secretbox_easy(ciphertext[0..$-1], message, nonce, key)); 144 assert(crypto_secretbox_easy(ciphertext, message, nonce, key)); 145 version(none) { 146 import std.array : appender; 147 import std.base64 : Base64; 148 auto app = appender!string(); 149 app.put("Message (plaintext): test\n"); 150 app.put("Ciphertext (base64): "); 151 const(char)[] encoded = Base64.encode(ciphertext); 152 app.put(encoded~"\n"); 153 app.put("Nonce (base64): "); 154 encoded = Base64.encode(nonce); 155 app.put(encoded~"\n"); 156 app.put("Key (base64): "); 157 encoded = Base64.encode(key); 158 app.put(encoded~"\n"); 159 writeln(app.data); 160 /* taking this from a previous run: 161 Message (plaintext): test 162 Ciphertext (base64): tNV0M68PZea7+XKsfTeiJuOxVfU= 163 Nonce (base64): 0gkPP63C0it0WeeO1LIQk4BDLpHFD58Z 164 Key (base64): AtN67ZJklRbVVJ7R9QwVbKFpZivWXFHq9YlwVbM9n6s= 165 */ 166 //ubyte[] decoded = Base64.decode("FPucA9l+"); 167 ubyte[crypto_secretbox_KEYBYTES] key_ = Base64.decode("AtN67ZJklRbVVJ7R9QwVbKFpZivWXFHq9YlwVbM9n6s="); 168 ubyte[crypto_secretbox_NONCEBYTES] nonce_ = Base64.decode("0gkPP63C0it0WeeO1LIQk4BDLpHFD58Z"); 169 ubyte[CIPHERTEXT_LEN] ciphertext1 = Base64.decode("tNV0M68PZea7+XKsfTeiJuOxVfU="); 170 ubyte[MESSAGE_LEN] decrypted_ = void; 171 assert(crypto_secretbox_open_easy(decrypted_, ciphertext1, nonce_, key_), "message forged!"); 172 assert(decrypted_ == message); 173 } 174 ubyte[MESSAGE_LEN] decrypted = void; 175 assertThrown(crypto_secretbox_open_easy(decrypted, ciphertext[0..$-1-crypto_secretbox_MACBYTES], nonce, key)); 176 assertThrown(crypto_secretbox_open_easy(decrypted[0..$-1], ciphertext, nonce, key)); 177 assert(crypto_secretbox_open_easy(decrypted, ciphertext, nonce, key), "message forged!"); 178 assert(decrypted == message); 179 180 ubyte[crypto_secretbox_MACBYTES] mac = void; 181 ubyte[MESSAGE_LEN] ciphertext2; 182 decrypted = decrypted.init; 183 sodium_increment(nonce); 184 assertThrown(crypto_secretbox_detached(ciphertext2[0..$-1], mac, message, nonce, key)); 185 assert(crypto_secretbox_detached(ciphertext2, mac, message, nonce, key)); 186 187 assertThrown(crypto_secretbox_open_detached(decrypted[0..$-1], ciphertext2, mac, nonce, key)); 188 assert(crypto_secretbox_open_detached(decrypted, ciphertext2, mac, nonce, key), "message forged!"); 189 assert(decrypted == message); 190 }