1 // Written in the D programming language. 2 3 /* Authenticated Encryption with Additional Data : AES256-GCM */ 4 5 module wrapper.sodium.crypto_aead_aes256gcm; 6 7 import wrapper.sodium.core; // assure sodium got initialized 8 9 public 10 import deimos.sodium.crypto_aead_aes256gcm : crypto_aead_aes256gcm_is_available, 11 crypto_aead_aes256gcm_KEYBYTES, 12 crypto_aead_aes256gcm_keybytes, 13 crypto_aead_aes256gcm_NSECBYTES, 14 crypto_aead_aes256gcm_nsecbytes, 15 crypto_aead_aes256gcm_NPUBBYTES, 16 crypto_aead_aes256gcm_npubbytes, 17 crypto_aead_aes256gcm_ABYTES, 18 crypto_aead_aes256gcm_abytes, 19 crypto_aead_aes256gcm_MESSAGEBYTES_MAX, 20 crypto_aead_aes256gcm_messagebytes_max, 21 crypto_aead_aes256gcm_state, 22 crypto_aead_aes256gcm_statebytes, 23 /* crypto_aead_aes256gcm_encrypt, 24 crypto_aead_aes256gcm_decrypt, 25 crypto_aead_aes256gcm_encrypt_detached, 26 crypto_aead_aes256gcm_decrypt_detached, 27 crypto_aead_aes256gcm_beforenm, 28 crypto_aead_aes256gcm_encrypt_afternm, 29 crypto_aead_aes256gcm_decrypt_afternm, 30 crypto_aead_aes256gcm_encrypt_detached_afternm, 31 crypto_aead_aes256gcm_decrypt_detached_afternm; */ 32 crypto_aead_aes256gcm_keygen; 33 34 import std.exception : assertThrown, assertNotThrown; 35 import nogc.exception: enforce; 36 37 // overloading some functions between module deimos.sodium.crypto_aead_aes256gcm and this module 38 39 40 /* Wrapper(s)/substitute(s) for 'deimos' functions */ 41 42 43 44 alias crypto_aead_aes256gcm_encrypt = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_encrypt; 45 46 /** 47 * The function crypto_aead_aes256gcm_encrypt() encrypts a message `m` using a secret key `k` (crypto_aead_aes256gcm_KEYBYTES bytes) 48 * and a public nonce `npub` (crypto_aead_aes256gcm_NPUBBYTES bytes). 49 * The encrypted message, as well as a tag authenticating both the confidential message m and ad.length bytes of non-confidential data `ad`, 50 * are put into `c`. 51 * ad can also be an empty array if no additional data are required. 52 * At most m.length + crypto_aead_aes256gcm_ABYTES bytes are put into c, reflected by the length of `c`. 53 * The function always returns true. 54 * The public nonce npub should never ever be reused with the same key. The recommended way to generate it is to use 55 * randombytes_buf() for the first message, and then to increment it for each subsequent message using the same key. 56 * Params: 57 * Returns: 58 * Throws: 59 * See_Also: 60 */ 61 bool crypto_aead_aes256gcm_encrypt(scope ubyte[] c, 62 scope const ubyte[] m, 63 scope const ubyte[] ad, 64 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 65 const ubyte[crypto_aead_aes256gcm_KEYBYTES] k) @nogc @trusted 66 { 67 // enforce(m.length, "Error invoking crypto_aead_aes256gcm_encrypt: m is null"); // not required 68 enforce(m.length <= 16UL * ((1UL << 32) - 2)); 69 immutable c_expect_len = m.length + crypto_aead_aes256gcm_ABYTES; 70 // enforce(c.length == c_expect_len, "Expected c.length: ", c.length, " to be equal to m.length + crypto_aead_aes256gcm_ABYTES: ", c_expect_len); 71 enforce(c.length == c_expect_len, "Expected c.length is not equal to m.length + crypto_aead_aes256gcm_ABYTES"); 72 ulong clen_p; 73 bool result = crypto_aead_aes256gcm_encrypt(c.ptr, &clen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 74 assert(clen_p == c_expect_len); // okay to be removed in release code 75 return result; 76 } 77 78 alias crypto_aead_aes256gcm_decrypt = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_decrypt; 79 80 /** 81 * The function crypto_aead_aes256gcm_decrypt() verifies that the ciphertext `c` (as produced by crypto_aead_aes256gcm_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 aead_aes256gcm_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 * (and `c`'s .length might shrink to the length actually required). 89 * At most c.length - crypto_aead_aes256gcm_ABYTES bytes will be put into m. 90 */ 91 bool crypto_aead_aes256gcm_decrypt(scope ubyte[] m, 92 scope const ubyte[] c, 93 scope const ubyte[] ad, 94 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 95 const ubyte[crypto_aead_aes256gcm_KEYBYTES] k) @nogc @trusted 96 { 97 enforce(c.length <= 16UL * (1UL << 32)); 98 // enforce(c.length >= crypto_aead_aes256gcm_ABYTES, "Expected c.length: ", c.length, " to be greater_equal to crypto_aead_aes256gcm_ABYTES: ", crypto_aead_aes256gcm_ABYTES); 99 enforce(c.length >= crypto_aead_aes256gcm_ABYTES, "Expected c.length is not greater_equal to crypto_aead_aes256gcm_ABYTES"); 100 immutable m_expect_len = c.length - crypto_aead_aes256gcm_ABYTES; 101 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to c.length - crypto_aead_aes256gcm_ABYTES: ", m_expect_len); 102 enforce(m.length == m_expect_len, "Expected m.length is not equal to c.length - crypto_aead_aes256gcm_ABYTES"); 103 ulong mlen_p; 104 bool result = crypto_aead_aes256gcm_decrypt(m.ptr, &mlen_p, null, c.ptr, c.length, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 105 if (result) 106 assert(mlen_p == m_expect_len); // okay to be removed in release code 107 return result; 108 } 109 110 alias crypto_aead_aes256gcm_encrypt_detached = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_encrypt_detached; 111 112 bool crypto_aead_aes256gcm_encrypt_detached(scope ubyte[] c, 113 out ubyte[crypto_aead_aes256gcm_ABYTES] mac, 114 scope const ubyte[] m, 115 scope const ubyte[] ad, 116 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 117 const ubyte[crypto_aead_aes256gcm_KEYBYTES] k) @nogc @trusted 118 { 119 // enforce(m.length, "Error invoking crypto_aead_aes256gcm_encrypt_detached: m is null"); // not required 120 enforce(m.length <= 16UL * ((1UL << 32) - 2)); 121 // enforce(c.length == m.length, "Expected c.length: ", c.length, " to be equal to m.length: ", m.length); 122 enforce(c.length == m.length, "Expected c.length is not equal to m.length"); 123 ulong maclen_p; 124 bool result = crypto_aead_aes256gcm_encrypt_detached(c.ptr, mac.ptr, &maclen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, k.ptr) == 0; 125 assert(maclen_p == crypto_aead_aes256gcm_ABYTES); // okay to be removed in release code 126 return result; 127 } 128 129 alias crypto_aead_aes256gcm_decrypt_detached = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_decrypt_detached; 130 131 bool crypto_aead_aes256gcm_decrypt_detached(scope ubyte[] m, 132 scope const ubyte[] c, 133 const ubyte[crypto_aead_aes256gcm_ABYTES] mac, 134 scope const ubyte[] ad, 135 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 136 const ubyte[crypto_aead_aes256gcm_KEYBYTES] k) @nogc @trusted 137 { 138 // enforce(c.length, "Error invoking crypto_aead_aes256gcm_decrypt_detached: c is null"); // not required 139 enforce(c.length <= 16UL * (1UL << 32)); 140 // enforce(m.length == c.length, "Expected m.length: ", m.length, " to be equal to c.length: ", c.length); 141 enforce(m.length == c.length, "Expected m.lengthis not equal to c.length"); 142 return crypto_aead_aes256gcm_decrypt_detached(m.ptr, null, c.ptr, c.length, mac.ptr, ad.ptr, ad.length, npub.ptr, k.ptr) == 0; 143 } 144 145 /* -- Precomputation interface -- */ 146 147 alias crypto_aead_aes256gcm_beforenm = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_beforenm; 148 149 pragma(inline, true) 150 bool crypto_aead_aes256gcm_beforenm(ref crypto_aead_aes256gcm_state ctx, 151 const ubyte[crypto_aead_aes256gcm_KEYBYTES] k) @nogc pure @trusted 152 { 153 return crypto_aead_aes256gcm_beforenm(&ctx, k.ptr) == 0; 154 } 155 156 alias crypto_aead_aes256gcm_encrypt_afternm = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_encrypt_afternm; 157 158 bool crypto_aead_aes256gcm_encrypt_afternm(scope ubyte[] c, 159 scope const ubyte[] m, 160 scope const ubyte[] ad, 161 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 162 const ref crypto_aead_aes256gcm_state ctx) @nogc @trusted 163 { 164 // enforce(m.length, "Error invoking crypto_aead_aes256gcm_encrypt_afternm: m is null"); // not required 165 enforce(m.length <= 16UL * ((1UL << 32) - 2)); 166 immutable c_expect_len = m.length + crypto_aead_aes256gcm_ABYTES; 167 // enforce(c.length == c_expect_len, "Expected c.length: ", c.length, " to be equal to m.length + crypto_aead_aes256gcm_ABYTES: ", c_expect_len); 168 enforce(c.length == c_expect_len, "Expected c.length is not equal to m.length + crypto_aead_aes256gcm_ABYTES"); 169 ulong clen_p; 170 bool result = crypto_aead_aes256gcm_encrypt_afternm(c.ptr, &clen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, &ctx) == 0; 171 assert(clen_p == c_expect_len); // okay to be removed in release code 172 return result; 173 } 174 175 alias crypto_aead_aes256gcm_decrypt_afternm = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_decrypt_afternm; 176 177 bool crypto_aead_aes256gcm_decrypt_afternm(scope ubyte[] m, 178 scope const ubyte[] c, 179 scope const ubyte[] ad, 180 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 181 const ref crypto_aead_aes256gcm_state ctx) @nogc @trusted 182 { 183 enforce(c.length <= 16UL * (1UL << 32)); 184 // enforce(c.length >= crypto_aead_aes256gcm_ABYTES, "Expected c.length: ", c.length, " to be greater_equal to crypto_aead_aes256gcm_ABYTES: ", crypto_aead_aes256gcm_ABYTES); 185 enforce(c.length >= crypto_aead_aes256gcm_ABYTES, "Expected c.length is not greater_equal to crypto_aead_aes256gcm_ABYTES"); 186 immutable m_expect_len = c.length - crypto_aead_aes256gcm_ABYTES; 187 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to c.length - crypto_aead_aes256gcm_ABYTES: ", m_expect_len); 188 enforce(m.length == m_expect_len, "Expected m.length is not equal to c.length - crypto_aead_aes256gcm_ABYTES"); 189 ulong mlen_p; 190 bool result = crypto_aead_aes256gcm_decrypt_afternm(m.ptr, &mlen_p, null, c.ptr, c.length, ad.ptr, ad.length, npub.ptr, &ctx) == 0; 191 if (result) 192 assert(mlen_p == m_expect_len); // okay to be removed in release code 193 return result; 194 } 195 196 alias crypto_aead_aes256gcm_encrypt_detached_afternm = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_encrypt_detached_afternm; 197 198 bool crypto_aead_aes256gcm_encrypt_detached_afternm(scope ubyte[] c, 199 out ubyte[crypto_aead_aes256gcm_ABYTES] mac, 200 scope const ubyte[] m, 201 scope const ubyte[] ad, 202 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 203 const ref crypto_aead_aes256gcm_state ctx) @nogc @trusted 204 { 205 // enforce(m.length, "Error invoking crypto_aead_aes256gcm_encrypt_detached_afternm: m is null"); // not required 206 enforce(m.length <= 16UL * ((1UL << 32) - 2)); 207 // enforce(c.length == m.length, "Expected c.length: ", c.length, " to be equal to m.length: ", m.length); 208 enforce(c.length == m.length, "Expected c.length is not equal to m.length"); 209 ulong maclen_p; 210 bool result = crypto_aead_aes256gcm_encrypt_detached_afternm(c.ptr, mac.ptr, &maclen_p, m.ptr, m.length, ad.ptr, ad.length, null, npub.ptr, &ctx) == 0; 211 assert(maclen_p == crypto_aead_aes256gcm_ABYTES); // okay to be removed in release code 212 return result; 213 } 214 215 alias crypto_aead_aes256gcm_decrypt_detached_afternm = deimos.sodium.crypto_aead_aes256gcm.crypto_aead_aes256gcm_decrypt_detached_afternm; 216 217 bool crypto_aead_aes256gcm_decrypt_detached_afternm(scope ubyte[] m, 218 scope const ubyte[] c, 219 const ubyte[crypto_aead_aes256gcm_ABYTES] mac, 220 scope const ubyte[] ad, 221 const ubyte[crypto_aead_aes256gcm_NPUBBYTES] npub, 222 const ref crypto_aead_aes256gcm_state ctx) @nogc @trusted 223 { 224 // enforce(c.length, "Error invoking crypto_aead_aes256gcm_decrypt_detached_afternm: c is null"); // not required 225 enforce(c.length <= 16UL * (1UL << 32)); 226 // enforce(m.length == c.length, "Expected m.length: ", m.length, " to be equal to c.length: ", c.length); 227 enforce(m.length == c.length, "Expected m.length is not equal to c.length"); 228 return crypto_aead_aes256gcm_decrypt_detached_afternm(m.ptr, null, c.ptr, c.length, mac.ptr, ad.ptr, ad.length, npub.ptr, &ctx) == 0; 229 } 230 231 232 version(unittest) 233 { 234 import wrapper.sodium.randombytes : randombytes; 235 // share a key and nonce in the following unittests 236 ubyte[crypto_aead_aes256gcm_NPUBBYTES] nonce = void; 237 ubyte[crypto_aead_aes256gcm_KEYBYTES] key = void; 238 239 static this() { 240 randombytes(nonce); 241 randombytes(key); 242 } 243 } 244 245 246 @system 247 unittest 248 { 249 import std.string : representation; 250 import std.stdio : writeln; 251 debug writeln("unittest block 1 from sodium.crypto_aead_aes256gcm.d"); 252 253 if (crypto_aead_aes256gcm_is_available() == 1) { 254 auto message = representation("test"); 255 enum message_len = 4UL; 256 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 257 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 258 ubyte[message_len + crypto_aead_aes256gcm_ABYTES] ciphertext; 259 ulong ciphertext_len; 260 261 crypto_aead_aes256gcm_encrypt(ciphertext.ptr, &ciphertext_len, message.ptr, message.length, 262 additional_data.ptr, additional_data.length, null, nonce.ptr, key.ptr); 263 264 ubyte[message_len] decrypted; 265 ulong decrypted_len; 266 assert(ciphertext_len == ciphertext.length); 267 assert(crypto_aead_aes256gcm_decrypt(decrypted.ptr, &decrypted_len, null, ciphertext.ptr, ciphertext_len, 268 additional_data.ptr, additional_data.length, nonce.ptr, key.ptr) == 0); 269 assert(decrypted == message); //writeln("Decrypted message (aead_aes256gcm): ", cast(string)decrypted); 270 assert(decrypted_len == decrypted.length); 271 272 // test null for &ciphertext_len 273 crypto_aead_aes256gcm_encrypt(ciphertext.ptr, null, message.ptr, message.length, 274 additional_data.ptr, additional_data.length, null, nonce.ptr, key.ptr); 275 crypto_aead_aes256gcm_decrypt(decrypted.ptr, null, null, ciphertext.ptr, ciphertext_len, 276 additional_data.ptr, additional_data.length, nonce.ptr, key.ptr); 277 278 align(16) crypto_aead_aes256gcm_state ctx; 279 debug writeln("address of ctx: ", &ctx); 280 // debug writeln("(cast(size_t)&ctx & 0x0FUL): ", (cast(size_t)&ctx & 0x0FUL)); 281 assert((cast(size_t)&ctx & 0x0FUL) == 0); 282 crypto_aead_aes256gcm_beforenm(&ctx, key.ptr); 283 } 284 } 285 286 @safe 287 unittest 288 { 289 import std.string : representation; 290 import std.stdio : writeln, writefln; 291 import wrapper.sodium.utils : sodium_increment; 292 293 version(none/*viWindowsX86*/) { 294 writeln("early return for Windows X86: unittest block 2 from sodium.crypto_aead_aes256gcm.d"); 295 writeln("There is some not yet checked issue with 'Access Violation' running -m32_mscoff (alignment?), yet -m32 is okay"); 296 return; 297 } 298 else { 299 debug writeln("unittest block 2 from sodium.crypto_aead_aes256gcm.d"); 300 301 assert(crypto_aead_aes256gcm_keybytes() == crypto_aead_aes256gcm_KEYBYTES); 302 assert(crypto_aead_aes256gcm_nsecbytes() == crypto_aead_aes256gcm_NSECBYTES); 303 assert(crypto_aead_aes256gcm_npubbytes() == crypto_aead_aes256gcm_NPUBBYTES); 304 assert(crypto_aead_aes256gcm_abytes() == crypto_aead_aes256gcm_ABYTES); 305 assert(crypto_aead_aes256gcm_messagebytes_max() == crypto_aead_aes256gcm_MESSAGEBYTES_MAX); // see travis Build #74 306 // debug writeln("crypto_aead_aes256gcm_MESSAGEBYTES_MAX: ", crypto_aead_aes256gcm_MESSAGEBYTES_MAX); 307 // debug writeln("crypto_aead_aes256gcm_messagebytes_max(): ", crypto_aead_aes256gcm_messagebytes_max()); 308 assert(crypto_aead_aes256gcm_statebytes() == crypto_aead_aes256gcm_state.sizeof); 309 310 311 if (crypto_aead_aes256gcm_is_available() == 1) { 312 auto message = representation("test"); 313 enum message_len = 4UL; 314 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 315 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 316 ubyte[message_len + crypto_aead_aes256gcm_ABYTES] ciphertext1; 317 sodium_increment(nonce); 318 319 assertThrown (crypto_aead_aes256gcm_encrypt(ciphertext1[0..$-1], message, additional_data, nonce, key)); 320 assertNotThrown(crypto_aead_aes256gcm_encrypt(ciphertext1[0..$-message.length], null, additional_data, nonce, key)); 321 assertNotThrown(crypto_aead_aes256gcm_encrypt(ciphertext1, message, null, nonce, key)); 322 323 assert(crypto_aead_aes256gcm_encrypt(ciphertext1, message, additional_data, nonce, key)); 324 325 ubyte[message_len] decrypted; 326 assertThrown (crypto_aead_aes256gcm_decrypt(decrypted, ciphertext1[0..crypto_aead_aes256gcm_ABYTES-1], additional_data, nonce, key)); 327 assertThrown (crypto_aead_aes256gcm_decrypt(decrypted[0..$-1], ciphertext1, additional_data, nonce, key)); 328 assertNotThrown(crypto_aead_aes256gcm_decrypt(decrypted, ciphertext1, null, nonce, key)); 329 330 assert(crypto_aead_aes256gcm_decrypt(decrypted, ciphertext1, additional_data, nonce, key)); 331 assert(decrypted == message); 332 333 ubyte[message_len] ciphertext2; 334 ubyte[crypto_aead_aes256gcm_ABYTES] mac; 335 sodium_increment(nonce); 336 337 assertThrown (crypto_aead_aes256gcm_encrypt_detached(ciphertext2[0..$-1], mac, message, additional_data, nonce, key)); 338 assertNotThrown(crypto_aead_aes256gcm_encrypt_detached(ciphertext2[0..$-message.length], mac, null, additional_data, nonce, key)); 339 assertNotThrown(crypto_aead_aes256gcm_encrypt_detached(ciphertext2, mac, message, null, nonce, key)); 340 341 assert(crypto_aead_aes256gcm_encrypt_detached(ciphertext2, mac, message, additional_data, nonce, key)); 342 343 assertNotThrown(crypto_aead_aes256gcm_decrypt_detached(decrypted[0..$-message.length], null, mac, additional_data, nonce, key)); 344 assertThrown (crypto_aead_aes256gcm_decrypt_detached(decrypted[0..$-1], ciphertext2, mac, additional_data, nonce, key)); 345 assertNotThrown(crypto_aead_aes256gcm_decrypt_detached(decrypted, ciphertext2, mac, null, nonce, key)); 346 347 assert(crypto_aead_aes256gcm_decrypt_detached(decrypted, ciphertext2, mac, additional_data, nonce, key)); 348 assert(decrypted == message); 349 350 /* -- Precomputation interface -- */ 351 352 align(16) crypto_aead_aes256gcm_state ctx; 353 assert(crypto_aead_aes256gcm_beforenm(ctx, key)); 354 355 sodium_increment(nonce); 356 version(GNU) {} 357 else { 358 assertThrown (crypto_aead_aes256gcm_encrypt_afternm(ciphertext1[0..$-1], message, additional_data, nonce, ctx)); 359 assertNotThrown(crypto_aead_aes256gcm_encrypt_afternm(ciphertext1[0..$-message.length], null, additional_data, nonce, ctx)); 360 assertNotThrown(crypto_aead_aes256gcm_encrypt_afternm(ciphertext1, message, null, nonce, ctx)); 361 } 362 assert(crypto_aead_aes256gcm_encrypt_afternm(ciphertext1, message, additional_data, nonce, ctx)); 363 364 version(GNU) {} 365 else { 366 assertThrown (crypto_aead_aes256gcm_decrypt_afternm(decrypted, ciphertext1[0..crypto_aead_aes256gcm_ABYTES-1], additional_data, nonce, ctx)); 367 assertThrown (crypto_aead_aes256gcm_decrypt_afternm(decrypted[0..$-1], ciphertext1, additional_data, nonce, ctx)); 368 assertNotThrown(crypto_aead_aes256gcm_decrypt_afternm(decrypted, ciphertext1, null, nonce, ctx)); 369 } 370 assert(crypto_aead_aes256gcm_decrypt_afternm(decrypted, ciphertext1, additional_data, nonce, ctx)); 371 assert(decrypted == message); 372 373 sodium_increment(nonce); 374 375 version(GNU) {} 376 else { 377 assertThrown (crypto_aead_aes256gcm_encrypt_detached_afternm(ciphertext2[0..$-1], mac, message, additional_data, nonce, ctx)); 378 assertNotThrown(crypto_aead_aes256gcm_encrypt_detached_afternm(ciphertext2[0..$-message.length], mac, null, additional_data, nonce, ctx)); 379 assertNotThrown(crypto_aead_aes256gcm_encrypt_detached_afternm(ciphertext2, mac, message, null, nonce, ctx)); 380 } 381 assert(crypto_aead_aes256gcm_encrypt_detached_afternm(ciphertext2, mac, message, additional_data, nonce, ctx)); 382 383 version(GNU) {} 384 else { 385 assertThrown (crypto_aead_aes256gcm_decrypt_detached_afternm(decrypted[0..$-1], ciphertext2, mac, additional_data, nonce, ctx)); 386 assertNotThrown(crypto_aead_aes256gcm_decrypt_detached_afternm(decrypted[0..$-message.length], null, mac, additional_data, nonce, ctx)); 387 assertNotThrown(crypto_aead_aes256gcm_decrypt_detached_afternm(decrypted, ciphertext2, mac, null, nonce, ctx)); 388 } 389 assert(crypto_aead_aes256gcm_decrypt_detached_afternm(decrypted, ciphertext2, mac, additional_data, nonce, ctx)); 390 assert(decrypted == message); 391 392 ubyte[crypto_aead_aes256gcm_KEYBYTES] k; 393 crypto_aead_aes256gcm_keygen(k); 394 } // if (crypto_aead_aes256gcm_is_available() == 1) 395 } 396 } 397 398 @nogc @safe 399 unittest 400 { 401 if (crypto_aead_aes256gcm_is_available() == 1) { 402 // usage is not cryptographically safe here; it's purpose is to test @nogc @safe 403 import std.string : representation; 404 ubyte[crypto_aead_aes256gcm_NPUBBYTES] n = nonce; 405 ubyte[crypto_aead_aes256gcm_KEYBYTES] k; 406 crypto_aead_aes256gcm_keygen(k); 407 ubyte[4] message = [116, 101, 115, 116]; //representation("test"); 408 ubyte[4] decrypted; 409 enum m_len = 4UL; 410 auto additional_data = representation("A typical use case for additional data is to store protocol-specific metadata " ~ 411 "about the message, such as its length and encoding. (non-confidential, non-encrypted data"); 412 ubyte[m_len+crypto_aead_aes256gcm_ABYTES] ciphertext1; 413 ubyte[m_len] ciphertext2; 414 415 ubyte[ crypto_aead_aes256gcm_ABYTES] mac; 416 assert(crypto_aead_aes256gcm_encrypt(ciphertext1, message, additional_data, n, k)); 417 assert(crypto_aead_aes256gcm_decrypt(decrypted, ciphertext1, additional_data, n, k)); 418 assert(decrypted == message); 419 decrypted = decrypted.init; 420 assert(crypto_aead_aes256gcm_encrypt_detached(ciphertext2, mac, message, additional_data, n, k)); 421 assert(crypto_aead_aes256gcm_decrypt_detached(decrypted, ciphertext2, mac, additional_data, n, k)); 422 assert(decrypted == message); 423 version(Win32) {} 424 else { 425 align(16) crypto_aead_aes256gcm_state ctx; 426 decrypted = decrypted.init; 427 ciphertext1 = ciphertext1.init; 428 ciphertext2 = ciphertext2.init; 429 assert(crypto_aead_aes256gcm_beforenm(ctx, key)); 430 assert(crypto_aead_aes256gcm_encrypt_afternm(ciphertext1, message, additional_data, n, ctx)); 431 assert(crypto_aead_aes256gcm_decrypt_afternm(decrypted, ciphertext1, additional_data, n, ctx)); 432 assert(decrypted == message); 433 decrypted = decrypted.init; 434 assert(crypto_aead_aes256gcm_encrypt_detached_afternm(ciphertext2, mac, message, additional_data, n, ctx)); 435 assert(crypto_aead_aes256gcm_decrypt_detached_afternm(decrypted, ciphertext2, mac, additional_data, n, ctx)); 436 assert(decrypted == message); 437 } 438 } 439 }