1 // Written in the D programming language. 2 3 module wrapper.sodium.crypto_aead_chacha20poly1305; 4 5 import wrapper.sodium.core; // assure sodium got initialized 6 7 public 8 import deimos.sodium.crypto_aead_chacha20poly1305 : crypto_aead_chacha20poly1305_ietf_KEYBYTES, 9 crypto_aead_chacha20poly1305_ietf_keybytes, 10 crypto_aead_chacha20poly1305_ietf_NSECBYTES, 11 crypto_aead_chacha20poly1305_ietf_nsecbytes, 12 crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 13 crypto_aead_chacha20poly1305_ietf_npubbytes, 14 crypto_aead_chacha20poly1305_ietf_ABYTES, 15 crypto_aead_chacha20poly1305_ietf_abytes, 16 crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 17 crypto_aead_chacha20poly1305_ietf_messagebytes_max, 18 /* crypto_aead_chacha20poly1305_ietf_encrypt, 19 crypto_aead_chacha20poly1305_ietf_decrypt, 20 crypto_aead_chacha20poly1305_ietf_encrypt_detached, 21 crypto_aead_chacha20poly1305_ietf_decrypt_detached, */ 22 crypto_aead_chacha20poly1305_ietf_keygen, 23 crypto_aead_chacha20poly1305_KEYBYTES, 24 crypto_aead_chacha20poly1305_keybytes, 25 crypto_aead_chacha20poly1305_NSECBYTES, 26 crypto_aead_chacha20poly1305_nsecbytes, 27 crypto_aead_chacha20poly1305_NPUBBYTES, 28 crypto_aead_chacha20poly1305_npubbytes, 29 crypto_aead_chacha20poly1305_ABYTES, 30 crypto_aead_chacha20poly1305_abytes, 31 crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX, 32 crypto_aead_chacha20poly1305_messagebytes_max, 33 /* crypto_aead_chacha20poly1305_encrypt, 34 crypto_aead_chacha20poly1305_decrypt, 35 crypto_aead_chacha20poly1305_encrypt_detached, 36 crypto_aead_chacha20poly1305_decrypt_detached, */ 37 crypto_aead_chacha20poly1305_keygen; 38 39 40 import std.exception : assertThrown, assertNotThrown; 41 import nogc.exception: enforce; 42 43 // overloading some functions between module deimos.sodium.crypto_aead_chacha20poly1305 and this module 44 45 alias crypto_aead_chacha20poly1305_ietf_encrypt = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_ietf_encrypt; 46 47 /** 48 * The function crypto_aead_chacha20poly1305_ietf_encrypt() 49 * encrypts a message `m` using a secret key `k` (crypto_aead_chacha20poly1305_ietf_KEYBYTES bytes) 50 * and a public nonce `npub` (crypto_aead_chacha20poly1305_ietf_NPUBBYTES bytes). 51 * The encrypted message, as well as a tag authenticating both the confidential message m and ad.length bytes of non-confidential data `ad`, 52 * are put into `c`. 53 * ad can also be an empty array if no additional data are required. 54 * At most m.length + crypto_aead_chacha20poly1305_ietf_ABYTES bytes are put into `c`. 55 * The function always returns true. 56 * The public nonce npub should never ever be reused with the same key. The recommended way to generate it is to use 57 * randombytes_buf() for the first message, and then to increment it for each subsequent message using the same key. 58 */ 59 bool crypto_aead_chacha20poly1305_ietf_encrypt(scope ubyte[] c, 60 const scope ubyte[] m, 61 const scope ubyte[] ad, 62 const ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] npub, 63 const ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k) @nogc @trusted 64 { 65 // enforce(m.length, "Error invoking crypto_aead_chacha20poly1305_ietf_encrypt: m is null"); // TODO check if m.ptr==null would be okay 66 enforce(m.length <= ulong.max - crypto_aead_chacha20poly1305_ietf_ABYTES); 67 const c_expect_len = m.length + crypto_aead_chacha20poly1305_ietf_ABYTES; 68 // enforce(c.length == c_expect_len, "Expected c.length: ", c.length, " to be equal to m.length + crypto_aead_chacha20poly1305_ietf_ABYTES: ", c_expect_len); 69 enforce(c.length == c_expect_len, "Expected c.length is not equal to m.length + crypto_aead_chacha20poly1305_ietf_ABYTES"); 70 ulong clen_p; 71 bool result = crypto_aead_chacha20poly1305_ietf_encrypt(c.ptr, &clen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 72 if (result) 73 assert(clen_p == c_expect_len); // okay to be removed in release code 74 return result; 75 } 76 77 alias crypto_aead_chacha20poly1305_ietf_decrypt = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_ietf_decrypt; 78 79 /** 80 * The function crypto_aead_chacha20poly1305_ietf_decrypt() 81 verifies that the ciphertext `c` (as produced by crypto_aead_chacha20poly1305_ietf_encrypt()), 82 * includes a valid tag using a secret key `k`, a public nonce `npub`, and additional data `ad`. c.length is the ciphertext length 83 * in bytes with the authenticator, so it has to be at least crypto_aead_chacha20poly1305_ietf_ABYTES. 84 * 85 * ad can be an empty array if no additional data are required. 86 * The function returns false if the verification fails. 87 * If the verification succeeds, the function returns true, puts the decrypted message into `m` and stores its actual number of bytes into `mlen_p`. 88 * At most c.length - crypto_aead_chacha20poly1305_ietf_ABYTES bytes will be put into m. 89 */ 90 bool crypto_aead_chacha20poly1305_ietf_decrypt(scope ubyte[] m, 91 const scope ubyte[] c, 92 const scope ubyte[] ad, 93 const ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] npub, 94 const ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k) @nogc @trusted 95 { 96 // enforce(c.length >= crypto_aead_chacha20poly1305_ietf_ABYTES, "Expected c.length: ", c.length, " to be greater_equal to crypto_aead_chacha20poly1305_ietf_ABYTES: ", crypto_aead_chacha20poly1305_ietf_ABYTES); 97 enforce(c.length >= crypto_aead_chacha20poly1305_ietf_ABYTES, "Expected c.length is not greater_equal to crypto_aead_chacha20poly1305_ietf_ABYTES"); 98 const m_expect_len = c.length - crypto_aead_chacha20poly1305_ietf_ABYTES; 99 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to c.length - crypto_aead_chacha20poly1305_ietf_ABYTES: ", m_expect_len); 100 enforce(m.length == m_expect_len, "Expected m.length is not equal to c.length - crypto_aead_chacha20poly1305_ietf_ABYTES"); 101 ulong mlen_p; 102 bool result = crypto_aead_chacha20poly1305_ietf_decrypt(m.ptr, &mlen_p, null, c.ptr, c.length, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 103 if (result) 104 assert(mlen_p == m_expect_len); // okay to be removed in release code 105 return result; 106 } 107 108 alias crypto_aead_chacha20poly1305_ietf_encrypt_detached = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_ietf_encrypt_detached; 109 110 bool crypto_aead_chacha20poly1305_ietf_encrypt_detached(scope ubyte[] c, 111 out ubyte[crypto_aead_chacha20poly1305_ietf_ABYTES] mac, 112 const scope ubyte[] m, 113 const scope ubyte[] ad, 114 const ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] npub, 115 const ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k) @nogc @trusted 116 { 117 // enforce(m.length, "Error invoking crypto_aead_chacha20poly1305_ietf_encrypt_detached: m is null"); // TODO check if m.ptr==null would be okay 118 // enforce(c.length == m.length, "Expected c.length: ", c.length, " to be equal to m.length: ", m.length); 119 enforce(c.length == m.length, "Expected c.length is not equal to m.length"); 120 ulong maclen_p; 121 bool result = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c.ptr, mac.ptr, &maclen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 122 assert(maclen_p == crypto_aead_chacha20poly1305_ietf_ABYTES); // okay to be removed in release code 123 return result; 124 } 125 126 alias crypto_aead_chacha20poly1305_ietf_decrypt_detached = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_ietf_decrypt_detached; 127 128 bool crypto_aead_chacha20poly1305_ietf_decrypt_detached(scope ubyte[] m, 129 const scope ubyte[] c, 130 const ubyte[crypto_aead_chacha20poly1305_ietf_ABYTES] mac, 131 const scope ubyte[] ad, 132 const ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] npub, 133 const ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k) @nogc @trusted 134 { 135 // enforce(c.length, "Error invoking crypto_aead_chacha20poly1305_ietf_decrypt_detached: c is null"); // TODO check if c.ptr==null would be okay 136 // enforce(m.length == c.length, "Expected m.length: ", m.length, " to be equal to c.length: ", c.length); 137 enforce(m.length == c.length, "Expected m.length is not equal to c.length"); 138 return crypto_aead_chacha20poly1305_ietf_decrypt_detached(m.ptr, null, c.ptr, c.length, mac.ptr, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 139 } 140 141 /* -- Original ChaCha20-Poly1305 construction with a 64-bit nonce and a 64-bit internal counter -- */ 142 143 alias crypto_aead_chacha20poly1305_encrypt = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_encrypt; 144 145 bool crypto_aead_chacha20poly1305_encrypt(scope ubyte[] c, 146 const scope ubyte[] m, 147 const scope ubyte[] ad, 148 const ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] npub, 149 const ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k) @nogc @trusted 150 { 151 // enforce(m.length, "Error invoking crypto_aead_chacha20poly1305_encrypt: m is null"); // TODO check if m.ptr==null would be okay 152 const c_expect_len = m.length + crypto_aead_chacha20poly1305_ABYTES; 153 // enforce(c.length == c_expect_len, "Expected c.length: ", c.length, " to be equal to m.length + crypto_aead_chacha20poly1305_ABYTES: ", c_expect_len); 154 enforce(c.length == c_expect_len, "Expected c.length is not equal to m.length + crypto_aead_chacha20poly1305_ABYTES"); 155 ulong clen_p; 156 bool result = crypto_aead_chacha20poly1305_encrypt(c.ptr, &clen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 157 if (result) 158 assert(clen_p == c_expect_len); // okay to be removed in release code 159 return result; 160 } 161 162 alias crypto_aead_chacha20poly1305_decrypt = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_decrypt; 163 164 bool crypto_aead_chacha20poly1305_decrypt(scope ubyte[] m, 165 const scope ubyte[] c, 166 const scope ubyte[] ad, 167 const ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] npub, 168 const ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k) @nogc @trusted 169 { 170 // enforce(c.length >= crypto_aead_chacha20poly1305_ABYTES, "Expected c.length: ", c.length, " to be greater_equal to crypto_aead_chacha20poly1305_ABYTES: ", crypto_aead_chacha20poly1305_ABYTES); 171 enforce(c.length >= crypto_aead_chacha20poly1305_ABYTES, "Expected c.length is not greater_equal to crypto_aead_chacha20poly1305_ABYTES"); 172 const m_expect_len = c.length - crypto_aead_chacha20poly1305_ABYTES; 173 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to c.length - crypto_aead_chacha20poly1305_ABYTES: ", m_expect_len); 174 enforce(m.length == m_expect_len, "Expected m.length is not equal to c.length - crypto_aead_chacha20poly1305_ABYTES"); 175 ulong mlen_p; 176 bool result = crypto_aead_chacha20poly1305_decrypt(m.ptr, &mlen_p, null, c.ptr, c.length, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 177 if (result) 178 assert(mlen_p == m_expect_len); // okay to be removed in release code 179 return result; 180 } 181 182 alias crypto_aead_chacha20poly1305_encrypt_detached = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_encrypt_detached; 183 184 bool crypto_aead_chacha20poly1305_encrypt_detached(scope ubyte[] c, 185 out ubyte[crypto_aead_chacha20poly1305_ABYTES] mac, 186 const scope ubyte[] m, 187 const scope ubyte[] ad, 188 const ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] npub, 189 const ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k) @nogc @trusted 190 { 191 // enforce(m.length, "Error invoking crypto_aead_chacha20poly1305_encrypt_detached: m is null"); // TODO check if m.ptr==null would be okay 192 // enforce(c.length == m.length, "Expected c.length: ", c.length, " to be equal to m.length: ", m.length); 193 enforce(c.length == m.length, "Expected c.length is not equal to m.length"); 194 ulong maclen_p; 195 bool result = crypto_aead_chacha20poly1305_encrypt_detached(c.ptr, mac.ptr, &maclen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 196 assert(maclen_p == crypto_aead_chacha20poly1305_ABYTES); // okay to be removed in release code 197 return result; 198 } 199 200 alias crypto_aead_chacha20poly1305_decrypt_detached = deimos.sodium.crypto_aead_chacha20poly1305.crypto_aead_chacha20poly1305_decrypt_detached; 201 202 bool crypto_aead_chacha20poly1305_decrypt_detached(scope ubyte[] m, 203 const scope ubyte[] c, 204 const ubyte[crypto_aead_chacha20poly1305_ABYTES] mac, 205 const scope ubyte[] ad, 206 const ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] npub, 207 const ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k) @nogc @trusted 208 { 209 // enforce(c.length, "Error invoking crypto_aead_chacha20poly1305_decrypt_detached: c is null"); // TODO check if c.ptr==null would be okay 210 // enforce(m.length == c.length, "Expected m.length: ", m.length, " to be equal to c.length: ", c.length); 211 enforce(m.length == c.length, "Expected m.length is not equal to c.length"); 212 return crypto_aead_chacha20poly1305_decrypt_detached(m.ptr, null, c.ptr, c.length, mac.ptr, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 213 } 214 215 216 version(unittest) 217 { 218 import wrapper.sodium.randombytes : randombytes; 219 // share a key and nonce in the following unittests 220 ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] nonce = void; 221 ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] key = void; 222 223 ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] nonce2 = void; 224 ubyte[crypto_aead_chacha20poly1305_KEYBYTES] key2 = void; 225 226 static this() { 227 randombytes(nonce); 228 randombytes(key); 229 randombytes(nonce2); 230 randombytes(key2); 231 } 232 } 233 234 235 @system 236 unittest 237 { 238 import std..string : representation; 239 import std.stdio : writeln; 240 debug writeln("unittest block 1 from sodium.crypto_aead_chacha20poly1305.d"); 241 242 auto message = representation("test"); 243 enum message_len = 4; 244 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 245 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 246 ubyte[message_len + crypto_aead_chacha20poly1305_ietf_ABYTES] ciphertext; 247 ulong ciphertext_len; 248 249 crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.ptr, &ciphertext_len, message.ptr, message.length, 250 additional_data.ptr, additional_data.length, null, nonce.ptr, key.ptr); 251 252 ubyte[message_len] decrypted; 253 ulong decrypted_len; 254 assert(ciphertext_len==ciphertext.length); 255 assert(crypto_aead_chacha20poly1305_ietf_decrypt(decrypted.ptr, &decrypted_len, null, ciphertext.ptr, ciphertext_len, 256 additional_data.ptr, additional_data.length, nonce.ptr, key.ptr) == 0); 257 assert(decrypted == message); //writeln("Decrypted message (aead_chacha20poly1305): ", cast(string)decrypted); 258 assert(decrypted_len == decrypted.length); 259 260 // test null for &ciphertext_len / decrypted_len 261 crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.ptr, null, message.ptr, message.length, 262 additional_data.ptr, additional_data.length, null, nonce.ptr, key.ptr); 263 crypto_aead_chacha20poly1305_ietf_decrypt(decrypted.ptr, null, null, ciphertext.ptr, ciphertext_len, 264 additional_data.ptr, additional_data.length, nonce.ptr, key.ptr); 265 266 ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k; 267 crypto_aead_chacha20poly1305_ietf_keygen(k); 268 ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k2; 269 crypto_aead_chacha20poly1305_keygen(k2); 270 271 } 272 273 @safe 274 unittest 275 { 276 import std..string : representation; 277 import std.stdio : writeln, writefln; 278 import wrapper.sodium.utils : sodium_increment; 279 debug writeln("unittest block 2 from sodium.crypto_aead_chacha20poly1305.d"); 280 281 assert(crypto_aead_chacha20poly1305_ietf_keybytes() == crypto_aead_chacha20poly1305_ietf_KEYBYTES); 282 assert(crypto_aead_chacha20poly1305_ietf_nsecbytes() == crypto_aead_chacha20poly1305_ietf_NSECBYTES); 283 assert(crypto_aead_chacha20poly1305_ietf_npubbytes() == crypto_aead_chacha20poly1305_ietf_NPUBBYTES); 284 assert(crypto_aead_chacha20poly1305_ietf_abytes() == crypto_aead_chacha20poly1305_ietf_ABYTES); 285 assert(crypto_aead_chacha20poly1305_ietf_messagebytes_max() == crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX); // see travis Build #74 286 // debug writeln("crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX: ", crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX); 287 // debug writeln("crypto_aead_chacha20poly1305_ietf_messagebytes_max(): ", crypto_aead_chacha20poly1305_ietf_messagebytes_max()); 288 289 auto message = representation("test"); 290 enum message_len = 4; 291 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 292 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 293 ubyte[message_len + crypto_aead_chacha20poly1305_ietf_ABYTES] ciphertext1; 294 sodium_increment(nonce); 295 296 assertThrown (crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext1[0..$-1], message, additional_data, nonce, key)); 297 assertNotThrown(crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext1[0..$-message.length], null, additional_data, nonce, key)); 298 assertNotThrown(crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext1, message, null, nonce, key)); 299 300 assert(crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext1, message, additional_data, nonce, key)); 301 302 ubyte[message_len] decrypted; 303 assertThrown (crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, ciphertext1[0..crypto_aead_chacha20poly1305_ietf_ABYTES-1], additional_data, nonce, key)); 304 assertThrown (crypto_aead_chacha20poly1305_ietf_decrypt(decrypted[0..$-1], ciphertext1, additional_data, nonce, key)); 305 assertNotThrown(crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, ciphertext1, null, nonce, key)); 306 307 assert(crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, ciphertext1, additional_data, nonce, key)); 308 assert(decrypted == message); 309 // 310 ubyte[message_len] ciphertext2; 311 ubyte[crypto_aead_chacha20poly1305_ietf_ABYTES] mac; 312 sodium_increment(nonce); 313 314 assertThrown (crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext2[0..$-1], mac, message, additional_data, nonce, key)); 315 assertNotThrown(crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext2[0..$-message.length], mac, null, additional_data, nonce, key)); 316 assertNotThrown(crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext2, mac, message, null, nonce, key)); 317 318 assert(crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext2, mac, message, additional_data, nonce, key)); 319 320 assertThrown (crypto_aead_chacha20poly1305_ietf_decrypt_detached(decrypted[0..$-1], ciphertext2, mac, additional_data, nonce, key)); 321 assertNotThrown(crypto_aead_chacha20poly1305_ietf_decrypt_detached(decrypted[0..$-message.length], null, mac, additional_data, nonce, key)); 322 assertNotThrown(crypto_aead_chacha20poly1305_ietf_decrypt_detached(decrypted, ciphertext2, mac, null, nonce, key)); 323 324 assert(crypto_aead_chacha20poly1305_ietf_decrypt_detached(decrypted, ciphertext2, mac, additional_data, nonce, key)); 325 assert(decrypted == message); 326 327 } 328 329 @safe 330 unittest 331 { 332 import std..string : representation; 333 import std.stdio : writeln, writefln; 334 import wrapper.sodium.utils : sodium_increment; 335 debug writeln("unittest block 3 from sodium.crypto_aead_chacha20poly1305.d"); 336 337 assert(crypto_aead_chacha20poly1305_keybytes() == crypto_aead_chacha20poly1305_KEYBYTES); 338 assert(crypto_aead_chacha20poly1305_nsecbytes() == crypto_aead_chacha20poly1305_NSECBYTES); 339 assert(crypto_aead_chacha20poly1305_npubbytes() == crypto_aead_chacha20poly1305_NPUBBYTES); 340 assert(crypto_aead_chacha20poly1305_abytes() == crypto_aead_chacha20poly1305_ABYTES); 341 assert(crypto_aead_chacha20poly1305_messagebytes_max() == crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX); 342 343 auto message = representation("test"); 344 enum message_len = 4; 345 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 346 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 347 ubyte[message_len + crypto_aead_chacha20poly1305_ABYTES] ciphertext1; 348 sodium_increment(nonce2); 349 350 assertThrown (crypto_aead_chacha20poly1305_encrypt(ciphertext1[0..$-1], message, additional_data, nonce2, key2)); 351 assertNotThrown(crypto_aead_chacha20poly1305_encrypt(ciphertext1[0..$-message.length], null, additional_data, nonce2, key2)); 352 assertNotThrown(crypto_aead_chacha20poly1305_encrypt(ciphertext1, message, null, nonce2, key2)); 353 354 assert(crypto_aead_chacha20poly1305_encrypt(ciphertext1, message, additional_data, nonce2, key2)); 355 356 ubyte[message_len] decrypted; 357 assertThrown (crypto_aead_chacha20poly1305_decrypt(decrypted, ciphertext1[0..crypto_aead_chacha20poly1305_ABYTES-1], additional_data, nonce2, key2)); 358 assertThrown (crypto_aead_chacha20poly1305_decrypt(decrypted[0..$-1], ciphertext1, additional_data, nonce2, key2)); 359 assertNotThrown(crypto_aead_chacha20poly1305_decrypt(decrypted, ciphertext1, null, nonce2, key2)); 360 361 assert(crypto_aead_chacha20poly1305_decrypt(decrypted, ciphertext1, additional_data, nonce2, key2)); 362 assert(decrypted == message); 363 // 364 ubyte[message_len] ciphertext2; 365 ubyte[crypto_aead_chacha20poly1305_ABYTES] mac; 366 sodium_increment(nonce2); 367 368 assertThrown (crypto_aead_chacha20poly1305_encrypt_detached(ciphertext2[0..$-1], mac, message, additional_data, nonce2, key2)); 369 assertNotThrown(crypto_aead_chacha20poly1305_encrypt_detached(ciphertext2[0..$-message.length], mac, null, additional_data, nonce2, key2)); 370 assertNotThrown(crypto_aead_chacha20poly1305_encrypt_detached(ciphertext2, mac, message, null, nonce2, key2)); 371 372 assert(crypto_aead_chacha20poly1305_encrypt_detached(ciphertext2, mac, message, additional_data, nonce2, key2)); 373 374 assertThrown (crypto_aead_chacha20poly1305_decrypt_detached(decrypted[0..$-1], ciphertext2, mac, additional_data, nonce2, key2)); 375 assertNotThrown(crypto_aead_chacha20poly1305_decrypt_detached(decrypted[0..$-message.length], null, mac, additional_data, nonce2, key2)); 376 assertNotThrown(crypto_aead_chacha20poly1305_decrypt_detached(decrypted, ciphertext2, mac, null, nonce2, key2)); 377 378 assert(crypto_aead_chacha20poly1305_decrypt_detached(decrypted, ciphertext2, mac, additional_data, nonce2, key2)); 379 assert(decrypted == message); 380 } 381 382 383 384 @nogc @safe 385 unittest 386 { 387 // usage is not cryptographically safe here; it's purpose is to test @nogc @safe 388 import std..string : representation; 389 ubyte[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] n1 = nonce; 390 ubyte[crypto_aead_chacha20poly1305_ietf_KEYBYTES] k1; 391 crypto_aead_chacha20poly1305_ietf_keygen(k1); 392 ubyte[4] message = [116, 101, 115, 116]; //representation("test"); 393 ubyte[4] decrypted; 394 enum m_len = 4UL; 395 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 396 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 397 ubyte[m_len+crypto_aead_chacha20poly1305_ietf_ABYTES] ciphertext1; 398 ubyte[m_len] ciphertext2; 399 ubyte[ crypto_aead_chacha20poly1305_ietf_ABYTES] mac1; 400 401 assert(crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext1, message, additional_data, n1, k1)); 402 assert(crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, ciphertext1, additional_data, n1, k1)); 403 assert(decrypted == message); 404 decrypted = decrypted.init; 405 assert(crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext2, mac1, message, additional_data, n1, k1)); 406 assert(crypto_aead_chacha20poly1305_ietf_decrypt_detached(decrypted, ciphertext2, mac1, additional_data, n1, k1)); 407 assert(decrypted == message); 408 ubyte[crypto_aead_chacha20poly1305_NPUBBYTES] n2 = nonce[0..crypto_aead_chacha20poly1305_NPUBBYTES]; 409 ubyte[crypto_aead_chacha20poly1305_KEYBYTES] k2; 410 crypto_aead_chacha20poly1305_keygen(k2); 411 ubyte[m_len+crypto_aead_chacha20poly1305_ABYTES] ciphertext3; 412 ubyte[m_len] ciphertext4; 413 ubyte[ crypto_aead_chacha20poly1305_ABYTES] mac2; 414 decrypted = decrypted.init; 415 assert(crypto_aead_chacha20poly1305_encrypt(ciphertext3, message, additional_data, n2, k2)); 416 assert(crypto_aead_chacha20poly1305_decrypt(decrypted, ciphertext3, additional_data, n2, k2)); 417 assert(decrypted == message); 418 decrypted = decrypted.init; 419 assert(crypto_aead_chacha20poly1305_encrypt_detached(ciphertext4, mac2, message, additional_data, n2, k2)); 420 assert(crypto_aead_chacha20poly1305_decrypt_detached(decrypted, ciphertext4, mac2, additional_data, n2, k2)); 421 assert(decrypted == message); 422 }