some updates
[iv.d.git] / tweetNaCl.d
blobda6ee1d7b7366fde6ed455c915a76bbeac7a63ce
1 /*
2 * Contributors (alphabetical order)
3 * Daniel J. Bernstein, University of Illinois at Chicago and Technische Universiteit Eindhoven
4 * Wesley Janssen, Radboud Universiteit Nijmegen
5 * Tanja Lange, Technische Universiteit Eindhoven
6 * Peter Schwabe, Radboud Universiteit Nijmegen
8 * Ported by Ketmar // Invisible Vector ( ketmar@ketmar.no-ip.org )
9 */
10 //k8: yes, i know that this code sux. i know that i should rewrite it to be more 'D-ish'.
11 // i won't do that. thank you for your understanding. hehe.
12 module iv.tweetNaCl /*is aliced*/;
14 //import iv.alice;
15 public nothrow:
17 static if (!is(typeof(usize))) private alias usize = size_t;
18 static if (!is(typeof(sptrdiff))) private alias sptrdiff = ptrdiff_t;
19 static if (!is(typeof(ssizediff))) private alias ssizediff = ptrdiff_t;
21 static if (!is(typeof(ssize))) {
22 static if (usize.sizeof == 8) private alias ssize = long; //k8
23 else static if (usize.sizeof == 4) private alias ssize = int; //k8
24 else static assert(0, "invalid usize size"); //k8
28 // ////////////////////////////////////////////////////////////////////////// //
29 enum {
30 crypto_auth_BYTES = 32,
31 crypto_auth_KEYBYTES = 32,
33 crypto_box_PUBLICKEYBYTES = 32,
34 crypto_box_SECRETKEYBYTES = 32,
35 crypto_box_BEFORENMBYTES = 32,
36 crypto_box_NONCEBYTES = 24,
37 crypto_box_ZEROBYTES = 32,
38 crypto_box_BOXZEROBYTES = 16,
40 crypto_core_salsa20_OUTPUTBYTES = 64,
41 crypto_core_salsa20_INPUTBYTES = 16,
42 crypto_core_salsa20_KEYBYTES = 32,
43 crypto_core_salsa20_CONSTBYTES = 16,
45 crypto_core_hsalsa20_OUTPUTBYTES = 32,
46 crypto_core_hsalsa20_INPUTBYTES = 16,
47 crypto_core_hsalsa20_KEYBYTES = 32,
48 crypto_core_hsalsa20_CONSTBYTES = 16,
50 crypto_hash_BYTES = 64,
52 crypto_onetimeauth_BYTES = 16,
53 crypto_onetimeauth_KEYBYTES = 32,
55 crypto_scalarmult_BYTES = 32,
56 crypto_scalarmult_SCALARBYTES = 32,
58 crypto_secretbox_KEYBYTES = 32,
59 crypto_secretbox_NONCEBYTES = 24,
60 crypto_secretbox_ZEROBYTES = 32,
61 crypto_secretbox_BOXZEROBYTES = 16,
63 crypto_sign_BYTES = 64,
64 crypto_sign_PUBLICKEYBYTES = 32,
65 crypto_sign_SECRETKEYBYTES = 64,
67 crypto_stream_xsalsa20_KEYBYTES = 32,
68 crypto_stream_xsalsa20_NONCEBYTES = 24,
70 crypto_stream_salsa20_KEYBYTES = 32,
71 crypto_stream_salsa20_NONCEBYTES = 8,
73 crypto_stream_KEYBYTES = 32,
74 crypto_stream_NONCEBYTES = 24,
76 crypto_verify_16_BYTES = 16,
77 crypto_verify_32_BYTES = 32,
81 // ////////////////////////////////////////////////////////////////////////// //
82 /// set this callback to good (cryptograpic strong) random bytes generator
83 /// you can use /dev/urandom as prng
84 public void delegate (ubyte[] dest) nothrow randombytes = null;
87 // ////////////////////////////////////////////////////////////////////////// //
88 /**
89 * This function signs a message 'msg' using the sender's secret key 'sk'.
90 * The function returns the resulting signed message.
92 * WARNING! This function allocates!
94 * Params:
95 * msg == message
96 * sk == secret key, slice size must be at least crypto_sign_SECRETKEYBYTES, extra ignored
97 * dest == destination buffer; leave `null` to allocate, or pass array of at least `msg.length+crypto_sign_BYTES` bytes
99 * Returns:
100 * signed message
102 public ubyte[] crypto_sign (const(ubyte)[] msg, const(ubyte)[] sk, ubyte[] dest=null) {
103 if (sk.length < crypto_sign_SECRETKEYBYTES) assert(0, "sk too small");
104 ubyte[] sm;
105 if (dest.length >= msg.length+crypto_sign_BYTES) sm = dest[0..msg.length+64]; else sm.length = msg.length+crypto_sign_BYTES;
106 crypto_sign(sm, msg, sk);
107 return sm;
112 * This function verifies the signature in 'sm' using the receiver's public key 'pk'.
113 * The function returns the message.
115 * WARNING! This function allocates!
117 * Params:
118 * sm == signed message
119 * pk == public key, slice size must be at least crypto_sign_PUBLICKEYBYTES, extra ignored
120 * dest == destination buffer; leave `null` to allocate, or pass array of at least `sm.length` bytes
122 * Returns:
123 * decrypted message or null on error
125 public ubyte[] crypto_sign_open (const(ubyte)[] sm, const(ubyte)[] pk, ubyte[] dest=null) {
126 if (sm.length < crypto_sign_SECRETKEYBYTES) assert(0, "sm too small");
127 ubyte[] msg;
128 if (dest.length >= sm.length) msg = dest; else msg.length = sm.length;
129 scope(exit) if (msg.length >= crypto_sign_BYTES) msg[$-crypto_sign_BYTES..$] = 0; else if (msg.length) msg[] = 0;
130 if (!crypto_sign_open(msg, sm, pk)) return null;
131 return msg[0..sm.length-crypto_sign_BYTES]; // remove signature
135 // ////////////////////////////////////////////////////////////////////////// //
137 * This function checks that strings 'x' and 'y' has same content.
139 * Params:
140 * x = first string, slice length must be at least crypto_verify_16_BYTES, extra ignored
141 * y = second string, slice length must be at least crypto_verify_16_BYTES, extra ignored
143 * Returns:
144 * success flag
146 public bool crypto_verify_16 (const(ubyte)[] x, const(ubyte)[] y) @nogc {
147 pragma(inline, true);
148 if (x.length < crypto_verify_16_BYTES) assert(0, "x too small");
149 if (y.length < crypto_verify_16_BYTES) assert(0, "y too small");
150 return vn(x.ptr[0..crypto_verify_16_BYTES], y.ptr[0..crypto_verify_16_BYTES]);
154 * This function checks that strings 'x' and 'y' has same content.
156 * Params:
157 * x = first string, slice length must be at least crypto_verify_32_BYTES, extra ignored
158 * y = second string, slice length must be at least crypto_verify_32_BYTES, extra ignored
160 * Returns:
161 * success flag
163 public bool crypto_verify_32 (const(ubyte)[] x, const(ubyte)[] y) @nogc {
164 pragma(inline, true);
165 if (x.length < crypto_verify_32_BYTES) assert(0, "x too small");
166 if (y.length < crypto_verify_32_BYTES) assert(0, "y too small");
167 return vn(x.ptr[0..crypto_verify_32_BYTES], y.ptr[0..crypto_verify_32_BYTES]);
171 * This function encrypts a message 'msg' using a secret key 'key' and a nonce 'nonce'.
172 * The function returns the ciphertext 'output'.
174 * Params:
175 * output = resulting ciphertext
176 * msg = message
177 * nonce = nonce
178 * key = secret key
180 * Returns:
181 * ciphertext in 'output'
183 public void crypto_stream_salsa20_xor (ubyte[] output, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @trusted @nogc {
184 if (nonce.length < crypto_stream_salsa20_NONCEBYTES) assert(0, "invalid nonce size");
185 if (key.length < crypto_stream_salsa20_KEYBYTES) assert(0, "invalid key size");
186 if (msg.length > int.max/2) assert(0, "message too big");
187 //??? msg.length == 0 || output.length <= msg.length
188 ubyte[16] z = 0;
189 ubyte[64] x = void;
190 uint cpos = 0, mpos = 0;
191 auto b = output.length;
192 if (!b) return;
193 //if (b < (msg.length+63)/64*64) assert(0, "output buffer too small");
194 z.ptr[0..8] = nonce.ptr[0..8];
195 while (b >= 64) {
196 crypto_core_salsa20(x[], z[], key, sigma[]);
197 foreach (immutable v; x) output.ptr[cpos++] = (mpos < msg.length ? msg.ptr[mpos++] : 0)^v;
199 if (msg.length) {
200 foreach (immutable v; x) output[cpos++] = msg[mpos++]^v;
201 } else {
202 output[cpos..cpos+64] = x[];
203 cpos += 64;
206 uint u = 1;
207 foreach (immutable i; 8..16) {
208 u += cast(uint)z.ptr[i];
209 z.ptr[i] = u&0xff;
210 u >>= 8;
212 b -= 64;
214 if (b) {
215 crypto_core_salsa20(x[], z[], key, sigma[]);
217 if (msg.length) {
218 foreach (immutable i; 0..b) output[cpos++] = msg[mpos++]^x[i];
219 } else {
220 output[cpos..cpos+b] = x[0..b];
223 foreach (immutable i; 0..b) output.ptr[cpos++] = (mpos < msg.length ? msg.ptr[mpos++] : 0)^x.ptr[i];
228 * This function produces a stream 'c' as a function of a secret key 'key'
229 * and a nonce 'nonce'.
231 * Params:
232 * c = resulting stream
233 * nonce = nonce
234 * key = secret key
236 * Returns:
237 * ciphertext in 'c'
239 public void crypto_stream_salsa20 (ubyte[] c, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
240 if (nonce.length < crypto_stream_salsa20_NONCEBYTES) assert(0, "invalid nonce size");
241 if (key.length < crypto_stream_salsa20_KEYBYTES) assert(0, "invalid key size");
242 crypto_stream_salsa20_xor(c, null, nonce, key);
246 * This function produces a stream 'c' as a function of a secret key 'key'
247 * and a nonce 'nonce'.
249 * Params:
250 * c = output slice
251 * nonce = nonce
252 * key = secret key
254 * Returns:
255 * stream in 'c'
257 public void crypto_stream (ubyte[] c, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
258 if (c.length == 0) assert(0, "invalid c");
259 if (nonce.length < crypto_stream_NONCEBYTES) assert(0, "invalid nonce size");
260 if (key.length < crypto_stream_KEYBYTES) assert(0, "invalid key size");
261 ubyte[32] s = void;
262 crypto_core_hsalsa20(s[], nonce, key, sigma[]);
263 crypto_stream_salsa20(c, nonce[16..$], s[]);
267 * This function encrypts a message 'msg' using a secret key 'key' and a nonce 'nonce'.
268 * The function returns the ciphertext 'c'.
270 * Params:
271 * c = output slice
272 * msg = message
273 * nonce = nonce
274 * key = secret key
276 * Returns:
277 * ciphertext in 'c'
279 public void crypto_stream_xor (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
280 if (msg.length < c.length) assert(0, "invalid msg size");
281 if (nonce.length < crypto_stream_NONCEBYTES) assert(0, "invalid nonce size");
282 if (key.length < crypto_stream_KEYBYTES) assert(0, "invalid key size");
283 ubyte[32] s = void;
284 crypto_core_hsalsa20(s[], nonce, key, sigma[]);
285 crypto_stream_salsa20_xor(c, msg, nonce[16..$], s);
289 * This function authenticates a message 'msg' using a secret key 'key'.
290 * The function returns an authenticator 'output'.
292 * Params:
293 * output = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
294 * msg == message
295 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
297 * Returns:
298 * authenticator in 'output'
300 public void crypto_onetimeauth (ubyte[] output, const(ubyte)[] msg, const(ubyte)[] key) @nogc {
301 if (key.length < crypto_onetimeauth_KEYBYTES) assert(0, "invalid key size");
302 if (output.length < crypto_onetimeauth_BYTES) assert(0, "invalid output size");
303 if (msg.length > int.max/2) assert(0, "invalid message size");
305 uint s, u;
306 uint[17] x = void, r = void, h/*autoclear*/, c = void, g = void;
307 uint mpos = 0;
308 auto n = msg.length;
310 foreach (immutable i; 0..16) r.ptr[i] = key.ptr[i];
311 r.ptr[16..17] = 0;
313 r.ptr[3] &= 15;
314 r.ptr[4] &= 252;
315 r.ptr[7] &= 15;
316 r.ptr[8] &= 252;
317 r.ptr[11] &= 15;
318 r.ptr[12] &= 252;
319 r.ptr[15] &= 15;
321 while (n > 0) {
322 c.ptr[0..17] = 0;
324 usize jj;
325 for (jj = 0; jj < 16 && jj < n; ++jj) c.ptr[jj] = (mpos+jj < msg.length ? msg.ptr[mpos+jj] : 0);
326 c.ptr[jj] = 1;
327 mpos += jj;
328 n -= jj;
330 add1305(h, c);
331 foreach (immutable i; 0..17) {
332 x.ptr[i] = 0;
333 foreach (immutable j; 0..17) x.ptr[i] += h.ptr[j]*(j <= i ? r.ptr[i-j] : 320*r.ptr[i+17-j]);
335 h[] = x[];
336 u = 0;
337 foreach (immutable j; 0..16) {
338 u += h.ptr[j];
339 h.ptr[j] = u&255;
340 u >>= 8;
342 u += h.ptr[16];
343 h.ptr[16] = u&3;
344 u = 5*(u>>2);
345 foreach (immutable j; 0..16) {
346 u += h.ptr[j];
347 h.ptr[j] = u&255;
348 u >>= 8;
350 u += h.ptr[16];
351 h.ptr[16] = u;
354 g[] = h[];
355 add1305(h, minusp);
356 s = -(h.ptr[16]>>7);
357 foreach (immutable j; 0..17) h.ptr[j] ^= s&(g.ptr[j]^h.ptr[j]);
359 foreach (immutable j; 0..16) c.ptr[j] = key.ptr[j+16];
360 c.ptr[16] = 0;
361 add1305(h, c);
362 foreach (immutable j; 0..16) output.ptr[j] = cast(ubyte)(h.ptr[j]&0xff);
366 * This function checks that 'h' is a correct authenticator of a message 'msg'
367 * under the secret key 'key'.
369 * Params:
370 * h = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
371 * msg == message
372 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
374 * Returns:
375 * success flag
377 public bool crypto_onetimeauth_verify (const(ubyte)[] h, const(ubyte)[] msg, const(ubyte)[] key) @nogc {
378 if (h.length < crypto_onetimeauth_BYTES) assert(0, "invalid h size");
379 if (key.length < crypto_onetimeauth_KEYBYTES) assert(0, "invalid key size");
380 ubyte[16] x = void;
381 crypto_onetimeauth(x[], msg, key);
382 return crypto_verify_16(h, x[]);
386 * This function encrypts and authenticates a message 'msg' using a secret
387 * key 'key' and a nonce 'nonce'.
388 * The function returns the resulting ciphertext 'c'.
389 * Note that first 'crypto_secretbox_ZEROBYTES' in source buffer SHOULD always contains zeroes.
390 * Note that first 'crypto_secretbox_BOXZEROBYTES' in destination buffer will always contains zeroes.
392 * Params:
393 * c = resulting cyphertext ('c' size should be at least msg.length)
394 * msg = message
395 * key = secret key
396 * nonce = nonce
398 * Returns:
399 * success flag and cyphertext in 'c' (on success)
401 public bool crypto_secretbox (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
402 if (nonce.length < crypto_secretbox_NONCEBYTES) assert(0, "invalid nonce size");
403 if (key.length < crypto_secretbox_KEYBYTES) assert(0, "invalid key size");
404 if (msg.length > int.max/2) assert(0, "msg too big");
405 if (msg.length <= crypto_secretbox_BOXZEROBYTES) assert(0, "msg too small");
406 if (c.length < msg.length) return false;
407 ubyte b = 0;
408 foreach (immutable ubyte mb; msg.ptr[0..crypto_secretbox_ZEROBYTES]) b |= mb;
409 if (b != 0) return false;
410 crypto_stream_xor(c.ptr[0..msg.length], msg, nonce, key);
411 crypto_onetimeauth(c[16..$], c[32..$], c);
412 c.ptr[0..crypto_secretbox_BOXZEROBYTES] = 0;
413 return true;
417 * This function verifies and decrypts a ciphertext 'c' using a secret
418 * key 'key' and a nonce 'nonce'.
419 * The function returns the resulting plaintext 'output'.
420 * Note that first 'crypto_secretbox_BOXZEROBYTES' in source buffer SHOULD always contains zeroes.
421 * Note that first 'crypto_secretbox_ZEROBYTES' in destination buffer will always contains zeroes.
423 * Params:
424 * output = resulting message ('output' size should be at least msg.length)
425 * c = cyphertext
426 * key = secret key
427 * nonce = nonce
429 * Returns:
430 * success flag and message in 'output' (on success)
432 public bool crypto_secretbox_open (ubyte[] output, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
433 if (nonce.length < crypto_secretbox_NONCEBYTES) assert(0, "invalid nonce size");
434 if (key.length < crypto_secretbox_KEYBYTES) assert(0, "invalid key size");
435 if (c.length > int.max/2) assert(0, "message too big");
436 if (c.length < crypto_secretbox_ZEROBYTES) return false;
437 if (output.length < c.length) return false;
438 ubyte b = 0;
439 foreach (immutable ubyte mb; c.ptr[0..crypto_secretbox_BOXZEROBYTES]) b |= mb;
440 if (b != 0) return false;
441 ubyte[32] x = void;
442 crypto_stream(x[], nonce, key);
443 if (!crypto_onetimeauth_verify(c[16..$], c[32../*$*/32+(output.length-32)], x)) return false;
444 crypto_stream_xor(output.ptr[0..c.length], c, nonce, key);
445 output.ptr[0..crypto_secretbox_ZEROBYTES] = 0;
446 return true;
450 * This function randomly generates a secret key and a corresponding public key.
452 * Params:
453 * pk = slice to put generated public key into
454 * sk = slice to put generated secret key into
456 * Returns:
457 * pair of new keys
459 public void crypto_box_keypair (ubyte[] pk, ubyte[] sk) {
460 if (pk.length < crypto_box_PUBLICKEYBYTES) assert(0, "invalid pk size");
461 if (sk.length < crypto_box_SECRETKEYBYTES) assert(0, "invalid sk size");
462 randombytes(sk.ptr[0..32]);
463 crypto_scalarmult_base(pk, sk);
467 * This function generates a public key from a given secret key.
469 * Params:
470 * pk = slice to put generated public key into
471 * sk = slice with secret key
473 * Returns:
474 * pair of new keys
476 public void crypto_box_pk_from_sk (ubyte[] pk, const(ubyte)[] sk) {
477 if (pk.length < crypto_box_PUBLICKEYBYTES) assert(0, "invalid pk size");
478 if (sk.length < crypto_box_SECRETKEYBYTES) assert(0, "invalid sk size");
479 crypto_scalarmult_base(pk, sk);
483 * This function computes a shared secret 's' from public key 'pk' and secret key 'sk'.
485 * Params:
486 * skey = slice to put secret into (crypto_box_BEFORENMBYTES)
487 * pk = public
488 * sk = secret
490 * Returns:
491 * generated secret
493 public void crypto_box_beforenm (ubyte[] skey, const(ubyte)[] pk, const(ubyte)[] sk) @nogc {
494 if (skey.length < crypto_box_BEFORENMBYTES) assert(0, "invalid skey size");
495 if (pk.length < crypto_box_PUBLICKEYBYTES) assert(0, "invalid pk size");
496 if (sk.length < crypto_box_SECRETKEYBYTES) assert(0, "invalid sk size");
497 ubyte[32] s = void;
498 crypto_scalarmult(s[], sk, pk);
499 crypto_core_hsalsa20(skey, zero_[], s[], sigma[]);
503 * This function encrypts and authenticates a message 'msg' using a secret
504 * key 'key' and a nonce 'nonce'.
505 * The function returns the resulting ciphertext 'c'.
506 * Note that first 'crypto_box_ZEROBYTES' in source buffer SHOULD always contains zeroes.
507 * Note that first 'crypto_box_BOXZEROBYTES' in destination buffer will always contains zeroes.
509 * Params:
510 * c = resulting cyphertext ('c' size should be at least msg.length)
511 * msg = message
512 * nonce = nonce
513 * key = secret
515 * Returns:
516 * success flag and cyphertext in 'c' (on success)
518 public bool crypto_box_afternm (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
519 pragma(inline, true);
520 if (nonce.length < crypto_box_NONCEBYTES) assert(0, "invalid nonce size");
521 if (key.length < crypto_box_BEFORENMBYTES) assert(0, "invalid key size");
522 return crypto_secretbox(c, msg, nonce, key);
526 * This function verifies and decrypts a ciphertext 'c' using a secret
527 * key 'key' and a nonce 'nonce'.
528 * The function returns the resulting message 'msg'.
529 * Note that first 'crypto_box_ZEROBYTES' in destination buffer will always contains zeroes.
531 * Params:
532 * msg = resulting message ('msg' size should be at least msg.length+crypto_box_ZEROBYTES)
533 * c = cyphertext
534 * nonce = nonce
535 * key = secret
537 * Returns:
538 * success flag and resulting message in 'msg'
540 public bool crypto_box_open_afternm (ubyte[] msg, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] key) @nogc {
541 pragma(inline, true);
542 if (nonce.length < crypto_box_NONCEBYTES) assert(0, "invalid nonce size");
543 if (key.length < crypto_box_BEFORENMBYTES) assert(0, "invalid key size");
544 return crypto_secretbox_open(msg, c, nonce, key);
548 * This function encrypts and authenticates a message 'msg' using the sender's secret
549 * key 'sk', the receiver's public key 'pk', and a nonce 'nonce'.
550 * The function returns the resulting ciphertext 'c'.
551 * Note that first 'crypto_box_ZEROBYTES' in source buffer SHOULD always contains zeroes.
552 * Note that first 'crypto_box_BOXZEROBYTES' in destination buffer will always contains zeroes.
554 * usage: fill first `crypto_box_ZEROBYTES` of `msg` with zeroes, and other bytes with
555 * actual unencrypted message data.
556 * make `c` of exactly `msg` size.
557 * call `crypto_box()`.
558 * `c[crypto_box_BOXZEROBYTES..$]` will be your encrypted message, ready to send.
560 * Params:
561 * c = resulting cyphertext ('c' size should be at least msg.length)
562 * msg = message
563 * nonce = nonce
564 * pk = receiver's public key
565 * sk = sender's secret key
567 * Returns:
568 * success flag and cyphertext in 'c'
570 public bool crypto_box(bool doSanityChecks=true) (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk) @nogc {
571 if (nonce.length < crypto_box_NONCEBYTES) assert(0, "invalid nonce size");
572 if (pk.length < crypto_box_PUBLICKEYBYTES) assert(0, "invalid pk size");
573 if (sk.length < crypto_box_SECRETKEYBYTES) assert(0, "invalid sk size");
574 if (msg.length < crypto_box_ZEROBYTES) assert(0, "invalid msg size");
575 if (c.length < msg.length) assert(0, "invalid c size");
576 static if (crypto_box_BOXZEROBYTES > crypto_box_ZEROBYTES) {
577 if (c.length < crypto_box_BOXZEROBYTES) assert(0, "invalid c size");
579 static if (doSanityChecks) {
580 ubyte b = 0;
581 foreach (immutable ubyte bv; msg[0..crypto_box_ZEROBYTES]) b |= bv;
582 if (b != 0) assert(0, "invalid msg padding");
584 ubyte[32] k = void;
585 crypto_box_beforenm(k[], pk, sk);
586 c.ptr[0..crypto_box_BOXZEROBYTES] = 0; // why not?
587 return crypto_box_afternm(c[0..msg.length], msg, nonce, k[]);
591 * This function verifies and decrypts a ciphertext 'c' using the receiver's secret
592 * key 'sk', the sender's public key 'pk', and a nonce 'nonce'.
593 * The function returns the resulting message 'msg'.
594 * Note that first 'crypto_box_BOXZEROBYTES' in source buffer SHOULD always contains zeroes.
595 * Note that first 'crypto_box_ZEROBYTES' in destination buffer will always contains zeroes.
597 * usage: fill first `crypto_box_BOXZEROBYTES` of `c` with zeroes, and other bytes with
598 * actual encrypted message data.
599 * make `msg` of exactly `c` size.
600 * call `crypto_box_open()`.
601 * `msg[crypto_box_ZEROBYTES..$]` will be your decrypted message, ready to read.
603 * Params:
604 * msg = resulting message ('msg' size should be at least msg.length)
605 * c = cyphertext
606 * nonce = nonce
607 * pk = receiver's public key
608 * sk = sender's secret key
610 * Returns:
611 * success flag and message in 'msg'
613 public bool crypto_box_open(bool doSanityChecks=true) (ubyte[] msg, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk) @nogc {
614 if (nonce.length < crypto_box_NONCEBYTES) assert(0, "invalid nonce size");
615 if (pk.length < crypto_box_PUBLICKEYBYTES) assert(0, "invalid pk size");
616 if (sk.length < crypto_box_SECRETKEYBYTES) assert(0, "invalid sk size");
617 if (c.length < crypto_box_BOXZEROBYTES) assert(0, "invalid c size");
618 if (msg.length < c.length) assert(0, "invalid msg size");
619 static if (crypto_box_ZEROBYTES > crypto_box_BOXZEROBYTES) {
620 if (msg.length < crypto_box_ZEROBYTES) assert(0, "invalid msg size");
622 static if (doSanityChecks) {
623 ubyte b = 0;
624 foreach (immutable ubyte bv; c[0..crypto_box_BOXZEROBYTES]) b |= bv;
625 if (b != 0) assert(0, "invalid c padding");
627 ubyte[32] k = void;
628 crypto_box_beforenm(k[], pk, sk);
629 msg.ptr[0..crypto_box_ZEROBYTES] = 0; // why not?
630 return crypto_box_open_afternm(msg[0..c.length], c, nonce, k[]);
634 // ////////////////////////////////////////////////////////////////////////// //
635 // Ketmar's utility functions
638 * Calculate buffer size to hold encrypted message; it is bigger than `msg` size.
640 * WARNING! doesn't do overflow checking!
642 * Params:
643 * msglength = input message length
645 * Returns:
646 * buffer size to hold encrypted message
648 public usize crypto_boxes_encsize(string boxmode) (usize msglength) pure nothrow @safe @nogc
649 if (boxmode == "box" || boxmode == "secretbox")
651 pragma(inline, true);
652 return msglength+mixin("crypto_"~boxmode~"_ZEROBYTES")-mixin("crypto_"~boxmode~"_BOXZEROBYTES");
655 alias crypto_box_encsize = crypto_boxes_encsize!"box"; /// ditto
656 alias crypto_secretbox_encsize = crypto_boxes_encsize!"secretbox"; /// ditto
659 * Calculate buffer size to hold decrypted message; it is smaller than `msg` size.
661 * WARNING! doesn't do overflow checking!
663 * Params:
664 * msglength = input message length
666 * Returns:
667 * buffer size to hold encrypted message
669 public usize crypto_boxes_decsize(string boxmode) (usize msglength) pure nothrow @safe @nogc
670 if (boxmode == "box" || boxmode == "secretbox")
672 pragma(inline, true);
673 return
674 (msglength > mixin("crypto_"~boxmode~"_ZEROBYTES")-mixin("crypto_"~boxmode~"_BOXZEROBYTES") ?
675 msglength-(mixin("crypto_"~boxmode~"_ZEROBYTES")-mixin("crypto_"~boxmode~"_BOXZEROBYTES")) : 0);
678 alias crypto_box_decsize = crypto_boxes_decsize!"box"; /// ditto
679 alias crypto_secretbox_decsize = crypto_boxes_decsize!"secretbox"; /// ditto
682 * Check if `msg` can contain encrypted and authenticated message (i.e. it has enough data for that).
684 * Params:
685 * msg = input message
687 * Returns:
688 * `true` if `msg` size is valid.
690 public bool crypto_boxes_valid_encsize(string boxmode) (const(ubyte)[] msg) pure nothrow @safe @nogc
691 if (boxmode == "box" || boxmode == "secretbox")
693 pragma(inline, true);
694 return (msg.length >= mixin("crypto_"~boxmode~"_ZEROBYTES")-mixin("crypto_"~boxmode~"_BOXZEROBYTES"));
697 alias crypto_box_valid_encsize = crypto_boxes_valid_encsize!"box"; /// ditto
698 alias crypto_secretbox_valid_encsize = crypto_boxes_valid_encsize!"secretbox"; /// ditto
702 * This function encrypts and authenticates a message 'msg' using the sender's secret
703 * key 'sk', the receiver's public key 'pk', and a nonce 'nonce'.
704 * The function returns the resulting ciphertext 'c'.
705 * Note that `c` must be of at least `crypto_box_encsize(msg)` bytes in size.
707 * WARNING! this function is using `malloc()` internally, but not GC.
709 * Params:
710 * c = resulting cyphertext
711 * msg = message
712 * nonce = nonce
713 * pk = receiver's public key for "box" mode, or the only key for "secretbox" mode
714 * sk = sender's secret key for "box" mode, unused (and can be `null`) for "secretbox" mode
716 * Returns:
717 * success flag and cyphertext in 'c'
719 public bool crypto_boxes_enc(string boxmode) (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk=null) @trusted @nogc
720 if (boxmode == "box" || boxmode == "secretbox")
722 enum ZeroBytes = mixin("crypto_"~boxmode~"_ZEROBYTES");
723 enum BoxZeroBytes = mixin("crypto_"~boxmode~"_BOXZEROBYTES");
725 if (c.length < crypto_boxes_encsize!boxmode(msg.length)) return false;
726 if (nonce.length < mixin("crypto_"~boxmode~"_NONCEBYTES")) return false;
727 static if (boxmode == "box") {
728 if (pk.length < crypto_box_PUBLICKEYBYTES) return false;
729 if (sk.length < crypto_box_SECRETKEYBYTES) return false;
730 } else {
731 if (pk.length < crypto_secretbox_KEYBYTES) return false;
734 // use stack buffer for small messages; assume that we can alloca at least 4kb+ZeroBytes*2
735 import core.stdc.stdlib : alloca, malloc, free;
736 import core.stdc.string : memset, memcpy;
737 ubyte* smem = null, dmem = null;
738 bool doFree = false;
739 scope(exit) if (doFree) { if (smem !is null) free(smem); if (dmem !is null) free(dmem); }
740 immutable memsz = msg.length+ZeroBytes;
741 if (msg.length <= 2048) {
742 smem = cast(ubyte*)alloca(memsz);
743 dmem = cast(ubyte*)alloca(memsz);
744 } else {
745 smem = cast(ubyte*)malloc(memsz);
746 dmem = cast(ubyte*)malloc(memsz);
747 doFree = true;
749 if (smem is null || dmem is null) return false;
750 memset(smem, 0, memsz);
751 memset(dmem, 0, memsz);
752 // copy `msg` to `smem`
753 if (msg.length) memcpy(smem+ZeroBytes, msg.ptr, msg.length);
754 // process
755 static if (boxmode == "box") {
756 auto res = crypto_box(dmem[0..memsz], smem[0..memsz], nonce, pk, sk);
757 } else static if (boxmode == "secretbox") {
758 auto res = crypto_secretbox(dmem[0..memsz], smem[0..memsz], nonce, pk);
759 } else {
760 static assert(0, "wtf?!");
762 ubyte b = 0;
763 foreach (immutable ubyte bv; dmem[0..BoxZeroBytes]) b |= bv;
764 // copy result to destination buffer
765 memcpy(c.ptr, dmem+BoxZeroBytes, crypto_boxes_encsize!boxmode(msg.length));
766 return (res && b == 0);
769 alias crypto_box_enc = crypto_boxes_enc!"box"; /// ditto
770 alias crypto_secretbox_enc = crypto_boxes_enc!"secretbox"; /// ditto
773 * This function verifies and decrypts a ciphertext 'c' using the receiver's secret
774 * key 'sk', the sender's public key 'pk', and a nonce 'nonce'.
775 * Note that `msg` must be of at least `crypto_box_decsize(msg)` bytes in size.
776 * Also note that key order for "box" mode is reverse of `crypto_box_XXX()` functions.
778 * WARNING! this function is using `malloc()` internally, but not GC.
780 * Params:
781 * msg = resulting message
782 * c = cyphertext
783 * nonce = nonce
784 * pk = receiver's public key for "box" mode, or the only key for "secretbox" mode
785 * sk = sender's secret key for "box" mode, unused (and can be `null`) for "secretbox" mode
787 * Returns:
788 * success flag and message in 'msg'
790 public bool crypto_boxes_dec(string boxmode) (ubyte[] msg, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk=null) @trusted @nogc
791 if (boxmode == "box" || boxmode == "secretbox")
793 enum ZeroBytes = mixin("crypto_"~boxmode~"_ZEROBYTES");
794 enum BoxZeroBytes = mixin("crypto_"~boxmode~"_BOXZEROBYTES");
796 if (c.length < crypto_boxes_valid_encsize!boxmode(c)) return false;
797 if (msg.length < crypto_boxes_decsize!boxmode(c.length)) return false;
798 if (nonce.length < mixin("crypto_"~boxmode~"_NONCEBYTES")) return false;
799 static if (boxmode == "box") {
800 if (pk.length < crypto_box_PUBLICKEYBYTES) return false;
801 if (sk.length < crypto_box_SECRETKEYBYTES) return false;
802 } else {
803 if (pk.length < crypto_secretbox_KEYBYTES) return false;
806 // use stack buffer for small messages; assume that we can alloca at least 4kb+crypto_box_ZEROBYTES*2
807 import core.stdc.stdlib : alloca, malloc, free;
808 import core.stdc.string : memset, memcpy;
809 ubyte* smem = null, dmem = null;
810 bool doFree = false;
811 scope(exit) if (doFree) { if (smem !is null) free(smem); if (dmem !is null) free(dmem); }
812 immutable memsz = c.length+(ZeroBytes-BoxZeroBytes);
813 if (c.length <= 2048) {
814 smem = cast(ubyte*)alloca(memsz);
815 dmem = cast(ubyte*)alloca(memsz);
816 } else {
817 smem = cast(ubyte*)malloc(memsz);
818 dmem = cast(ubyte*)malloc(memsz);
819 doFree = true;
821 if (smem is null || dmem is null) return false;
822 memset(smem, 0, memsz);
823 memset(dmem, 0, memsz);
824 // copy `c` to `smem`
825 memcpy(smem+BoxZeroBytes, c.ptr, c.length);
826 // process
827 static if (boxmode == "box") {
828 auto res = crypto_box_open(dmem[0..memsz], smem[0..memsz], nonce, pk, sk);
829 } else {
830 auto res = crypto_secretbox_open(dmem[0..memsz], smem[0..memsz], nonce, pk);
832 ubyte b = 0;
833 foreach (immutable ubyte bv; dmem[0..ZeroBytes]) b |= bv;
834 // copy result to destination buffer
835 memcpy(msg.ptr, dmem+ZeroBytes, crypto_boxes_decsize!boxmode(c.length));
836 return (res && b == 0);
839 alias crypto_box_dec = crypto_boxes_dec!"box"; /// ditto
840 alias crypto_secretbox_dec = crypto_boxes_dec!"secretbox"; /// ditto
843 // ////////////////////////////////////////////////////////////////////////// //
845 * This function signs a message 'msg' using the sender's secret key 'sk'.
846 * The function returns the resulting signed message.
848 * Params:
849 * sm = buffer to receive signed message, must be of size at least msg.length+crypto_sign_BYTES
850 * msg = message
851 * sk = secret key, slice size must be at least crypto_sign_SECRETKEYBYTES, extra ignored
853 * Returns:
854 * signed message
856 public void crypto_sign (ubyte[] sm, const(ubyte)[] msg, const(ubyte)[] sk) @nogc {
857 if (sk.length < crypto_sign_SECRETKEYBYTES) assert(0, "invalid sk size");
858 if (sm.length < msg.length+64) assert(0, "invalid sm size");
860 ubyte[64] d = void, h = void, r = void;
861 ulong[64] x = 0;
862 long[16][4] p = void;
863 auto n = msg.length;
864 auto smlen = n+64;
866 crypto_hash(d, sk.ptr[0..32]);
867 d.ptr[0] &= 248;
868 d.ptr[31] &= 127;
869 d.ptr[31] |= 64;
871 sm.ptr[64..64+n] = msg[];
872 sm.ptr[32..64] = d.ptr[32..64];
874 crypto_hash(r, sm.ptr[32..32+n+32]);
875 reduce(r);
876 scalarbase(p, r);
877 pack(sm, p);
879 sm.ptr[32..64] = sk.ptr[32..64];
880 crypto_hash(h, sm.ptr[0..n+64]);
881 reduce(h);
883 foreach (immutable i; 0..32) x.ptr[i] = cast(ulong)r.ptr[i];
884 foreach (immutable i; 0..32) foreach (immutable j; 0..32) x.ptr[i+j] += h.ptr[i]*cast(ulong)d.ptr[j];
885 modL(sm[32..$], cast(long[])x);
889 * This function verifies the signature in 'sm' using the receiver's public key 'pk'.
891 * Params:
892 * msg = decrypted message, last crypto_sign_BYTES bytes are useless zeroes, must be of size at least sm.length-crypto_sign_BYTES
893 * sm = signed message
894 * pk = public key, slice size must be at least crypto_sign_PUBLICKEYBYTES, extra ignored
896 * Returns:
897 * success flag
899 public bool crypto_sign_open (ubyte[] msg, const(ubyte)[] sm, const(ubyte)[] pk) @nogc {
900 if (pk.length < crypto_sign_PUBLICKEYBYTES) assert(0, "invalid pk size");
901 if (msg.length < sm.length) assert(0, "invalid sm size");
902 if (sm.length < 64) assert(0, "invalid sm size");
904 ubyte[32] t = void;
905 ubyte[64] h = void;
906 long[16][4] p = void, q = void;
907 auto n = sm.length;
909 if (n < 64) return false;
911 if (!unpackneg(q, pk)) return false;
912 msg.ptr[0..n] = sm[];
913 msg.ptr[32..64] = pk.ptr[0..32];
914 crypto_hash(h, msg);
915 reduce(h);
916 scalarmult(p, q, h);
918 scalarbase(q, sm[32..$]);
919 add(p, q);
920 pack(t, p);
922 n -= 64;
923 if (!crypto_verify_32(sm, t)) {
924 msg[0..$/*n*/] = 0;
925 return false;
928 msg.ptr[0..n] = sm.ptr[64..64+n];
929 if (msg.length > n) msg[n..$] = 0;
931 return true;
935 * This function randomly generates a secret key and a corresponding public key.
937 * Params:
938 * pk = slice to put generated public key into (at least crypto_sign_PUBLICKEYBYTES)
939 * sk = slice to put generated secret key into (at least crypto_sign_SECRETKEYBYTES)
941 * Returns:
942 * pair of new keys (in pk and sk)
944 public void crypto_sign_keypair (ubyte[] pk, ubyte[] sk) {
945 if (pk.length < crypto_sign_PUBLICKEYBYTES) assert(0, "invalid pk size");
946 if (sk.length < crypto_sign_SECRETKEYBYTES) assert(0, "invalid sk size");
948 ubyte[64] d = void;
949 long[16][4] p = void;
951 randombytes(sk.ptr[0..32]);
952 crypto_hash(d, sk.ptr[0..32]);
953 d.ptr[0] &= 248;
954 d.ptr[31] &= 127;
955 d.ptr[31] |= 64;
957 scalarbase(p, d);
958 pack(pk, p);
960 sk.ptr[32..64] = pk.ptr[0..32];
964 * This function generates a public key from the given secret key.
966 * Params:
967 * pk = slice to put generated public key into (at least crypto_sign_PUBLICKEYBYTES)
968 * sk = slice to get secret key from (at least crypto_sign_SECRETKEYBYTES,
969 * crypto_sign_PUBLICKEYBYTES is secret key, won't be modified)
971 * Returns:
972 * pair of new keys (in pk and sk)
974 public void crypto_sign_pk_from_sk (ubyte[] pk, ubyte[] sk) {
975 if (pk.length < crypto_sign_PUBLICKEYBYTES) assert(0, "invalid pk size");
976 if (sk.length < crypto_sign_SECRETKEYBYTES) assert(0, "invalid sk size");
978 ubyte[64] d = void;
979 long[16][4] p = void;
981 //randombytes(sk.ptr[0..32]);
982 crypto_hash(d, sk.ptr[0..32]);
983 d.ptr[0] &= 248;
984 d.ptr[31] &= 127;
985 d.ptr[31] |= 64;
987 scalarbase(p, d);
988 pack(pk, p);
990 sk.ptr[32..64] = pk.ptr[0..32];
994 // ////////////////////////////////////////////////////////////////////////// //
995 private @trusted @nogc:
997 static immutable ubyte[16] zero_ = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
998 static immutable ubyte[32] nine_ = [9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
1000 static immutable long[16]
1001 gf0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
1002 gf1 = [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
1003 xx121665 = [0xDB41,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
1004 D = [0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203],
1005 D2 =[0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406],
1006 X = [0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169],
1007 Y = [0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666],
1008 I = [0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83];
1010 uint ld32 (const(ubyte)[] x) {
1011 pragma(inline, true);
1012 assert(x.length >= 4);
1013 uint u = x.ptr[3];
1014 u = (u<<8)|x.ptr[2];
1015 u = (u<<8)|x.ptr[1];
1016 return (u<<8)|x.ptr[0];
1019 ulong dl64 (const(ubyte)[] x) {
1020 pragma(inline, true);
1021 assert(x.length >= 8);
1022 ulong u = x.ptr[0];
1023 u = (u<<8)|x.ptr[1];
1024 u = (u<<8)|x.ptr[2];
1025 u = (u<<8)|x.ptr[3];
1026 u = (u<<8)|x.ptr[4];
1027 u = (u<<8)|x.ptr[5];
1028 u = (u<<8)|x.ptr[6];
1029 return (u<<8)|x.ptr[7];
1032 void st32 (ubyte[] x, uint u) {
1033 pragma(inline, true);
1034 assert(x.length >= 4);
1035 x.ptr[0] = u&0xff;
1036 x.ptr[1] = (u>>8)&0xff;
1037 x.ptr[2] = (u>>16)&0xff;
1038 x.ptr[3] = (u>>24)&0xff;
1041 void ts64 (ubyte[] x, ulong u) {
1042 pragma(inline, true);
1043 assert(x.length >= 8);
1044 x.ptr[0] = (u>>56)&0xff;
1045 x.ptr[1] = (u>>48)&0xff;
1046 x.ptr[2] = (u>>40)&0xff;
1047 x.ptr[3] = (u>>32)&0xff;
1048 x.ptr[4] = (u>>24)&0xff;
1049 x.ptr[5] = (u>>16)&0xff;
1050 x.ptr[6] = (u>>8)&0xff;
1051 x.ptr[7] = u&0xff;
1054 bool vn (const(ubyte)[] x, const(ubyte)[] y) {
1055 assert(x.length >= y.length);
1056 uint d = 0;
1057 foreach (immutable i, immutable v; cast(const(ubyte)[])x) d |= v^y.ptr[i];
1058 return (1&((d-1)>>8)) != 0;
1061 private void salsa_core(string type) (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant)
1062 if (type == "salsa" || type == "hsalsa") // constraint
1064 static uint ROTL32 (uint x, int c) pure nothrow @safe @nogc { pragma(inline, true); return (x<<c)|((x&0xffffffff)>>(32-c)); }
1066 // magic!
1067 assert(mixin(`output.length >= crypto_core_`~type~`20_OUTPUTBYTES`));
1068 assert(mixin(`input.length >= crypto_core_`~type~`20_INPUTBYTES`));
1069 assert(mixin(`key.length >= crypto_core_`~type~`20_KEYBYTES`));
1070 assert(mixin(`constant.length >= crypto_core_`~type~`20_CONSTBYTES`));
1072 uint[16] w = void, x = void, y = void;
1073 uint[4] t = void;
1075 foreach (immutable i; 0..4) {
1076 x.ptr[5*i] = ld32(constant[4*i..$]);
1077 x.ptr[1+i] = ld32(key[4*i..$]);
1078 x.ptr[6+i] = ld32(input[4*i..$]);
1079 x.ptr[11+i] = ld32(key[16+4*i..$]);
1082 y[] = x[];
1084 foreach (immutable i; 0..20) {
1085 foreach (immutable j; 0..4) {
1086 foreach (immutable m; 0..4) t.ptr[m] = x.ptr[(5*j+4*m)%16];
1087 t.ptr[1] ^= ROTL32(t.ptr[0]+t.ptr[3], 7);
1088 t.ptr[2] ^= ROTL32(t.ptr[1]+t.ptr[0], 9);
1089 t.ptr[3] ^= ROTL32(t.ptr[2]+t.ptr[1], 13);
1090 t.ptr[0] ^= ROTL32(t.ptr[3]+t.ptr[2], 18);
1091 foreach (immutable m; 0..4) w.ptr[4*j+(j+m)%4] = t.ptr[m];
1093 foreach (immutable m; 0..16) x.ptr[m] = w.ptr[m];
1096 foreach (immutable i; 0..16) x.ptr[i] += y.ptr[i];
1098 static if (type == "hsalsa") {
1099 foreach (immutable i; 0..4) {
1100 x.ptr[5*i] -= ld32(constant[4*i..$]);
1101 x.ptr[6+i] -= ld32(input[4*i..$]);
1103 foreach (immutable i; 0..4) {
1104 st32(output[4*i..$], x.ptr[5*i]);
1105 st32(output[16+4*i..$], x.ptr[6+i]);
1107 } else {
1108 foreach (immutable i; 0..16) st32(output[4*i..$], x.ptr[i]);
1112 // public for testing
1113 public void crypto_core_salsa20 (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant) {
1114 pragma(inline, true);
1115 salsa_core!"salsa"(output, input, key, constant);
1118 // public for testing
1119 public void crypto_core_hsalsa20 (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant) {
1120 pragma(inline, true);
1121 salsa_core!"hsalsa"(output, input, key, constant);
1124 private immutable ubyte[] sigma = cast(immutable ubyte[])"expand 32-byte k";
1126 private void add1305 (uint[] h, const(uint)[] c) {
1127 uint u = 0;
1128 foreach (immutable j; 0..17) {
1129 u += h.ptr[j]+c.ptr[j];
1130 h.ptr[j] = u&255;
1131 u >>= 8;
1135 private immutable uint[17] minusp = [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252];
1137 void car25519 (long[] o) {
1138 foreach (immutable i; 0..16) {
1139 o.ptr[i] += (1<<16);
1140 long c = o.ptr[i]>>16;
1141 o.ptr[(i+1)*(i<15)] += c-1+37*(c-1)*(i==15);
1142 o.ptr[i] -= c<<16;
1146 void sel25519 (long[] p, long[] q, int b) {
1147 long c = ~(b-1);
1148 foreach (immutable i; 0..16) {
1149 long t = c&(p.ptr[i]^q.ptr[i]);
1150 p.ptr[i] ^= t;
1151 q.ptr[i] ^= t;
1155 void pack25519 (ubyte[] o, const(long)[] n) {
1156 int b;
1157 long[16] m = void, t = void;
1158 t.ptr[0..16] = n.ptr[0..16];
1159 car25519(t);
1160 car25519(t);
1161 car25519(t);
1162 foreach (immutable j; 0..2) {
1163 m.ptr[0] = t.ptr[0]-0xffed;
1164 foreach (immutable i; 1..15) {
1165 m.ptr[i] = t.ptr[i]-0xffff-((m.ptr[i-1]>>16)&1);
1166 m.ptr[i-1] &= 0xffff;
1168 m.ptr[15] = t.ptr[15]-0x7fff-((m.ptr[14]>>16)&1);
1169 b = (m.ptr[15]>>16)&1;
1170 m.ptr[14] &= 0xffff;
1171 sel25519(t, m, 1-b);
1173 foreach (immutable i; 0..16) {
1174 o.ptr[2*i] = t.ptr[i]&0xff;
1175 o.ptr[2*i+1] = (t.ptr[i]>>8)&0xff;
1179 bool neq25519 (const(long)[] a, const(long)[] b) {
1180 ubyte[32] c = void, d = void;
1181 pack25519(c, a);
1182 pack25519(d, b);
1183 return crypto_verify_32(c, d);
1186 ubyte par25519 (const(long)[] a) {
1187 ubyte[32] d = void;
1188 pack25519(d, a);
1189 return d.ptr[0]&1;
1192 void unpack25519 (long[] o, const(ubyte)[] n) {
1193 foreach (immutable i; 0..16) o.ptr[i] = n.ptr[2*i]+(cast(long)n.ptr[2*i+1]<<8);
1194 o.ptr[15] &= 0x7fff;
1197 void A (long[] o, const(long)[] a, const(long)[] b) {
1198 foreach (immutable i; 0..16) o.ptr[i] = a.ptr[i]+b.ptr[i];
1201 void Z (long[] o, const(long)[] a, const(long)[] b) {
1202 foreach (immutable i; 0..16) o.ptr[i] = a.ptr[i]-b.ptr[i];
1205 void M (long[] o, const(long)[] a, const(long)[] b) {
1206 long[31] t; // automatically becomes 0
1207 foreach (immutable i; 0..16) foreach (immutable j; 0..16) t.ptr[i+j] += a.ptr[i]*b.ptr[j];
1208 foreach (immutable i; 0..15) t.ptr[i] += 38*t.ptr[i+16];
1209 o.ptr[0..16] = t.ptr[0..16];
1210 car25519(o);
1211 car25519(o);
1214 void S (long[] o, const(long)[] a) {
1215 M(o, a, a);
1218 void inv25519 (long[] o, const(long)[] i) {
1219 long[16] c = void;
1220 c[] = i.ptr[0..16];
1221 for (auto a = 253; a >= 0; --a) {
1222 S(c, c);
1223 if (a != 2 && a != 4) M(c, c, i);
1225 o.ptr[0..16] = c[];
1228 void pow2523 (long[] o, const(long)[] i) {
1229 long[16] c = void;
1230 c[] = i.ptr[0..16];
1231 for(auto a = 250; a >= 0; --a) {
1232 S(c, c);
1233 if (a != 1) M(c, c, i);
1235 o.ptr[0..16] = c[];
1238 // public for testing
1239 /* FIXME!
1240 * This function multiplies a group element 'p' by an integer 'n'.
1242 * Params:
1243 * p = group element
1244 * n = number
1246 * Returns:
1247 * resulting group element 'q' of length crypto_scalarmult_BYTES.
1249 public void crypto_scalarmult (ubyte[] q, const(ubyte)[] n, const(ubyte)[] p) {
1250 assert(q.length == crypto_scalarmult_BYTES);
1251 assert(n.length == crypto_scalarmult_BYTES);
1252 assert(p.length == crypto_scalarmult_BYTES);
1254 ubyte[32] z = void;
1255 long[80] x = void;
1256 long r;
1257 long[16] a = void, b = void, c = void, d = void, e = void, f = void;
1258 z[] = n.ptr[0..32];
1259 z.ptr[31] = (n.ptr[31]&127)|64;
1260 z.ptr[0] &= 248;
1261 unpack25519(x, p);
1262 foreach (immutable i; 0..16) {
1263 b.ptr[i] = x.ptr[i];
1264 d.ptr[i] = a.ptr[i] = c.ptr[i] = 0;
1266 a.ptr[0] = d.ptr[0] = 1;
1267 for (int i = 254; i >= 0; --i) {
1268 r = (z.ptr[i>>3]>>(i&7))&1;
1269 sel25519(a, b, cast(int)r);
1270 sel25519(c, d, cast(int)r);
1271 A(e, a, c);
1272 Z(a, a, c);
1273 A(c, b, d);
1274 Z(b, b, d);
1275 S(d, e);
1276 S(f, a);
1277 M(a, c, a);
1278 M(c, b, e);
1279 A(e, a, c);
1280 Z(a, a, c);
1281 S(b, a);
1282 Z(c, d, f);
1283 M(a, c, xx121665);
1284 A(a, a, d);
1285 M(c, c, a);
1286 M(a, d, f);
1287 M(d, b, x);
1288 S(b, e);
1289 sel25519(a, b, cast(int)r);
1290 sel25519(c, d, cast(int)r);
1292 foreach (immutable i; 0..16) {
1293 x.ptr[i+16] = a.ptr[i];
1294 x.ptr[i+32] = c.ptr[i];
1295 x.ptr[i+48] = b.ptr[i];
1296 x.ptr[i+64] = d.ptr[i];
1298 inv25519(x[32..$], x[32..$]);
1299 M(x[16..$], x[16..$], x[32..$]);
1300 pack25519(q, x[16..$]);
1303 // public for testing
1304 /* FIXME!
1305 * This function computes the scalar product of a standard group element
1306 * and an integer 'n'.
1308 * Params:
1309 * n = number
1311 * Returns:
1312 * resulting group element 'q' of length crypto_scalarmult_BYTES.
1314 public void crypto_scalarmult_base (ubyte[] q, const(ubyte)[] n) {
1315 pragma(inline, true);
1316 assert(q.length == crypto_scalarmult_BYTES);
1317 assert(n.length == crypto_scalarmult_SCALARBYTES);
1318 crypto_scalarmult(q, n, nine_);
1321 private:
1322 ulong R (ulong x, int c) pure { pragma(inline, true); return (x>>c)|(x<<(64-c)); }
1323 ulong Ch (ulong x, ulong y, ulong z) pure { pragma(inline, true); return (x&y)^(~x&z); }
1324 ulong Maj (ulong x, ulong y, ulong z) pure { pragma(inline, true); return (x&y)^(x&z)^(y&z); }
1325 ulong Sigma0 (ulong x) pure { pragma(inline, true); return R(x, 28)^R(x, 34)^R(x, 39); }
1326 ulong Sigma1 (ulong x) pure { pragma(inline, true); return R(x, 14)^R(x, 18)^R(x, 41); }
1327 ulong sigma0 (ulong x) pure { pragma(inline, true); return R(x, 1)^R(x, 8)^(x>>7); }
1328 ulong sigma1 (ulong x) pure { pragma(inline, true); return R(x, 19)^R(x, 61)^(x>>6); }
1330 immutable ulong[80] K = [
1331 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
1332 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
1333 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
1334 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
1335 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
1336 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
1337 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
1338 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
1339 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL,
1340 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, 0x92722c851482353bUL,
1341 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL,
1342 0xd192e819d6ef5218UL, 0xd69906245565a910UL, 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL,
1343 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL,
1344 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL,
1345 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL,
1346 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL,
1347 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL,
1348 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
1349 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
1350 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL
1353 void crypto_hashblocks (ubyte[] x, const(ubyte)[] m, ulong n) {
1354 ulong[8] z = void, b = void, a = void;
1355 ulong[16] w = void;
1356 ulong t;
1357 uint mpos = 0;
1358 foreach (immutable i; 0..8) z.ptr[i] = a.ptr[i] = dl64(x[8*i..$]);
1359 while (n >= 128) {
1360 foreach (immutable i; 0..16) w.ptr[i] = dl64(m[mpos+8*i..$]);
1361 foreach (immutable i; 0..80) {
1362 b.ptr[0..8] = a.ptr[0..8];
1363 t = a.ptr[7]+Sigma1(a.ptr[4])+Ch(a.ptr[4], a.ptr[5], a.ptr[6])+K[i]+w.ptr[i%16];
1364 b.ptr[7] = t+Sigma0(a.ptr[0])+Maj(a.ptr[0], a.ptr[1], a.ptr[2]);
1365 b.ptr[3] += t;
1366 //foreach (immutable j; 0..8) a.ptr[(j+1)%8] = b.ptr[j];
1367 a.ptr[1..8] = b.ptr[0..7];
1368 a.ptr[0] = b.ptr[7];
1369 if (i%16 == 15) {
1370 foreach (immutable j; 0..16) w.ptr[j] += w.ptr[(j+9)%16]+sigma0(w.ptr[(j+1)%16])+sigma1(w.ptr[(j+14)%16]);
1373 foreach (immutable i; 0..8) { a.ptr[i] += z.ptr[i]; z.ptr[i] = a.ptr[i]; }
1374 mpos += 128;
1375 n -= 128;
1377 foreach (immutable i; 0..8) ts64(x[8*i..$], z.ptr[i]);
1380 immutable ubyte[64] ivc = [
1381 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08,
1382 0xbb, 0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b,
1383 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, 0xf8, 0x2b,
1384 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1,
1385 0x51, 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1,
1386 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
1387 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b,
1388 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79
1392 * This function hashes a message 'msg'.
1393 * It returns a hash 'output'. The output length of 'output'
1394 * should be at least crypto_hash_BYTES.
1396 * Params:
1397 * output = resulting hash
1398 * msg = message
1400 * Returns:
1401 * sha512 hash
1403 public void crypto_hash (ubyte[] output, const(ubyte)[] msg) {
1404 if (output.length < crypto_hash_BYTES) assert(0, "output too small");
1405 ubyte[64] h = void;
1406 ubyte[256] x = 0;
1407 auto n = msg.length;
1408 ulong b = n;
1409 uint mpos = 0;
1411 h[] = ivc[];
1413 crypto_hashblocks(h, msg, n);
1414 mpos += n;
1415 n &= 127;
1416 mpos -= n;
1418 x.ptr[0..n] = msg.ptr[mpos..mpos+n];
1419 x.ptr[n] = 128;
1421 n = 256-128*(n<112);
1422 x.ptr[n-9] = b>>61;
1423 ts64(x[n-8..$], b<<3);
1424 crypto_hashblocks(h, x, n);
1426 output.ptr[0..64] = h;
1429 private void add (ref long[16][4] p, ref long[16][4] q) {
1430 long[16] a = void, b = void, c = void, d = void, t = void, e = void, f = void, g = void, h = void;
1432 Z(a, p.ptr[1], p.ptr[0]);
1433 Z(t, q.ptr[1], q.ptr[0]);
1434 M(a, a, t);
1435 A(b, p.ptr[0], p.ptr[1]);
1436 A(t, q.ptr[0], q.ptr[1]);
1437 M(b, b, t);
1438 M(c, p.ptr[3], q.ptr[3]);
1439 M(c, c, D2);
1440 M(d, p.ptr[2], q.ptr[2]);
1441 A(d, d, d);
1442 Z(e, b, a);
1443 Z(f, d, c);
1444 A(g, d, c);
1445 A(h, b, a);
1447 M(p.ptr[0], e, f);
1448 M(p.ptr[1], h, g);
1449 M(p.ptr[2], g, f);
1450 M(p.ptr[3], e, h);
1453 void cswap (ref long[16][4] p, ref long[16][4] q, ubyte b) {
1454 pragma(inline, true);
1455 foreach (immutable i; 0..4) sel25519(p.ptr[i], q.ptr[i], b);
1458 void pack (ubyte[] r, ref long[16][4] p) {
1459 long[16] tx = void, ty = void, zi = void;
1460 inv25519(zi, p.ptr[2]);
1461 M(tx, p.ptr[0], zi);
1462 M(ty, p.ptr[1], zi);
1463 pack25519(r, ty);
1464 r.ptr[31] ^= par25519(tx)<<7;
1467 void scalarmult (ref long[16][4] p, ref long[16][4] q, const(ubyte)[] s) {
1468 p.ptr[0][] = gf0[];
1469 p.ptr[1][] = gf1[];
1470 p.ptr[2][] = gf1[];
1471 p.ptr[3][] = gf0[];
1472 for (int i = 255; i >= 0; --i) {
1473 ubyte b = (s.ptr[i/8]>>(i&7))&1;
1474 cswap(p, q, b);
1475 add(q, p);
1476 add(p, p);
1477 cswap(p, q, b);
1481 void scalarbase (ref long[16][4] p, const(ubyte)[] s) {
1482 long[16][4] q = void;
1483 q.ptr[0][] = X[];
1484 q.ptr[1][] = Y[];
1485 q.ptr[2][] = gf1[];
1486 M(q.ptr[3], X, Y);
1487 scalarmult(p, q, s);
1490 immutable ulong[32] L = [
1491 0xed,0xd3,0xf5,0x5c,0x1a,0x63,0x12,0x58,0xd6,0x9c,0xf7,0xa2,0xde,0xf9,0xde,0x14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10
1494 void modL (ubyte[] r, long[] x) {
1495 long carry;
1496 for (auto i = 63; i >= 32; --i) {
1497 int j;
1498 carry = 0;
1499 for (j = i-32; j < i-12; ++j) {
1500 x.ptr[j] += carry-16*x.ptr[i]*L[j-(i-32)];
1501 carry = (x.ptr[j]+128)>>8;
1502 x.ptr[j] -= carry<<8;
1504 x.ptr[j] += carry;
1505 x.ptr[i] = 0;
1507 carry = 0;
1508 foreach (immutable j; 0..32) {
1509 x.ptr[j] += carry-(x.ptr[31]>>4)*L[j];
1510 carry = x.ptr[j]>>8;
1511 x.ptr[j] &= 255;
1513 foreach (immutable j; 0..32) x.ptr[j] -= carry*L[j];
1514 foreach (immutable i; 0..32) {
1515 x.ptr[i+1] += x.ptr[i]>>8;
1516 r.ptr[i] = x.ptr[i]&255;
1520 void reduce (ubyte[] r) {
1521 long[64] x = void;
1522 foreach (immutable i; 0..64) x.ptr[i] = cast(ulong)r.ptr[i];
1523 r.ptr[0..64] = 0;
1524 modL(r, x);
1527 private bool unpackneg (ref long[16][4] r, const(ubyte)[] p) {
1528 long[16] t = void, chk = void, num = void, den = void, den2 = void, den4 = void, den6 = void;
1529 r.ptr[2][] = gf1[];
1530 unpack25519(r.ptr[1], p);
1531 S(num, r.ptr[1]);
1532 M(den, num, D);
1533 Z(num, num, r.ptr[2]);
1534 A(den, r.ptr[2], den);
1536 S(den2, den);
1537 S(den4, den2);
1538 M(den6, den4, den2);
1539 M(t, den6, num);
1540 M(t, t, den);
1542 pow2523(t, t);
1543 M(t, t, num);
1544 M(t, t, den);
1545 M(t, t, den);
1546 M(r.ptr[0], t, den);
1548 S(chk, r.ptr[0]);
1549 M(chk, chk, den);
1550 if (!neq25519(chk, num)) M(r.ptr[0], r.ptr[0], I);
1552 S(chk, r.ptr[0]);
1553 M(chk, chk, den);
1554 if (!neq25519(chk, num)) return false;
1556 if (par25519(r.ptr[0]) == (p.ptr[31]>>7)) Z(r.ptr[0], gf0, r.ptr[0]);
1558 M(r.ptr[3], r.ptr[0], r.ptr[1]);
1559 return true;
1563 // ////////////////////////////////////////////////////////////////////////// //
1564 // Ketmar's additions
1566 /** Generate 32-byte secret key from the given passphase and salt.
1568 * This is very simple (and cryptographically weak) function to
1569 * generate crypto key from the given passphrase and salt.
1571 * WARNING! This function sux, and it is absolutely cryptographically weak
1572 * (hence the name). Only use it if you don't care about any
1573 * attacks. Heh.
1575 * Params:
1576 * sk = output buffer, should have room for at least 32 bytes
1577 * passphrase = passphrase, arbitrary length
1578 * salt = salt
1580 * Returns:
1581 * Generated key in first 32 bytes of sk.
1583 public void weak_crypto_key_from_passphrase (ubyte[] sk, const(void)[] passphrase, ulong salt) @trusted @nogc {
1584 if (sk.length < 32) assert(0, "invalid sk size");
1585 static assert(crypto_hash_BYTES == 64);
1586 ubyte[crypto_hash_BYTES+24/*nonce*/] hash = void;
1587 crypto_hash(hash[], cast(const(ubyte)[])passphrase[]);
1588 hash[crypto_hash_BYTES..$] = 0;
1589 hash.ptr[crypto_hash_BYTES+0] = cast(ubyte)(salt&0xff);
1590 hash.ptr[crypto_hash_BYTES+1] = cast(ubyte)((salt>>8)&0xff);
1591 hash.ptr[crypto_hash_BYTES+2] = cast(ubyte)((salt>>16)&0xff);
1592 hash.ptr[crypto_hash_BYTES+3] = cast(ubyte)((salt>>24)&0xff);
1593 hash.ptr[crypto_hash_BYTES+4] = cast(ubyte)((salt>>32)&0xff);
1594 hash.ptr[crypto_hash_BYTES+5] = cast(ubyte)((salt>>40)&0xff);
1595 hash.ptr[crypto_hash_BYTES+6] = cast(ubyte)((salt>>48)&0xff);
1596 hash.ptr[crypto_hash_BYTES+7] = cast(ubyte)((salt>>56)&0xff);
1597 crypto_stream_xor(sk[0..32], hash[0..32], hash[64..64+24], hash[32..64]);