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 )
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*/;
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 // ////////////////////////////////////////////////////////////////////////// //
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 // ////////////////////////////////////////////////////////////////////////// //
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!
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
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");
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
);
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!
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
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");
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.
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
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.
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
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'.
175 * output = resulting ciphertext
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
190 uint cpos
= 0, mpos
= 0;
191 auto b
= output
.length
;
193 //if (b < (msg.length+63)/64*64) assert(0, "output buffer too small");
194 z
.ptr
[0..8] = nonce
.ptr
[0..8];
196 crypto_core_salsa20(x
[], z
[], key
, sigma
[]);
197 foreach (immutable v
; x
) output
.ptr
[cpos
++] = (mpos
< msg
.length ? msg
.ptr
[mpos
++] : 0)^v
;
200 foreach (immutable v; x) output[cpos++] = msg[mpos++]^v;
202 output[cpos..cpos+64] = x[];
207 foreach (immutable i
; 8..16) {
208 u
+= cast(uint)z
.ptr
[i
];
215 crypto_core_salsa20(x
[], z
[], key
, sigma
[]);
218 foreach (immutable i; 0..b) output[cpos++] = msg[mpos++]^x[i];
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'.
232 * c = resulting stream
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'.
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");
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'.
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");
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'.
293 * output = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
295 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
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");
306 uint[17] x
= void, r
= void, h
/*autoclear*/, c
= void, g
= void;
310 foreach (immutable i
; 0..16) r
.ptr
[i
] = key
.ptr
[i
];
325 for (jj
= 0; jj
< 16 && jj
< n
; ++jj
) c
.ptr
[jj
] = (mpos
+jj
< msg
.length ? msg
.ptr
[mpos
+jj
] : 0);
331 foreach (immutable i
; 0..17) {
333 foreach (immutable j
; 0..17) x
.ptr
[i
] += h
.ptr
[j
]*(j
<= i ? r
.ptr
[i
-j
] : 320*r
.ptr
[i
+17-j
]);
337 foreach (immutable j
; 0..16) {
345 foreach (immutable j
; 0..16) {
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];
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'.
370 * h = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
372 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
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");
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.
393 * c = resulting cyphertext ('c' size should be at least msg.length)
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;
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;
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.
424 * output = resulting message ('output' size should be at least msg.length)
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;
439 foreach (immutable ubyte mb
; c
.ptr
[0..crypto_secretbox_BOXZEROBYTES
]) b |
= mb
;
440 if (b
!= 0) return false;
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;
450 * This function randomly generates a secret key and a corresponding public key.
453 * pk = slice to put generated public key into
454 * sk = slice to put generated secret key into
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.
470 * pk = slice to put generated public key into
471 * sk = slice with secret key
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'.
486 * skey = slice to put secret into (crypto_box_BEFORENMBYTES)
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");
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.
510 * c = resulting cyphertext ('c' size should be at least msg.length)
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.
532 * msg = resulting message ('msg' size should be at least msg.length+crypto_box_ZEROBYTES)
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.
561 * c = resulting cyphertext ('c' size should be at least msg.length)
564 * pk = receiver's public key
565 * sk = sender's secret key
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
) {
581 foreach (immutable ubyte bv
; msg
[0..crypto_box_ZEROBYTES
]) b |
= bv
;
582 if (b
!= 0) assert(0, "invalid msg padding");
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.
604 * msg = resulting message ('msg' size should be at least msg.length)
607 * pk = receiver's public key
608 * sk = sender's secret key
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
) {
624 foreach (immutable ubyte bv
; c
[0..crypto_box_BOXZEROBYTES
]) b |
= bv
;
625 if (b
!= 0) assert(0, "invalid c padding");
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!
643 * msglength = input message length
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!
664 * msglength = input message length
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);
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).
685 * msg = input message
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.
710 * c = resulting cyphertext
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
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;
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;
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
);
745 smem
= cast(ubyte*)malloc(memsz
);
746 dmem
= cast(ubyte*)malloc(memsz
);
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
);
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
);
760 static assert(0, "wtf?!");
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.
781 * msg = resulting message
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
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;
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;
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
);
817 smem
= cast(ubyte*)malloc(memsz
);
818 dmem
= cast(ubyte*)malloc(memsz
);
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
);
827 static if (boxmode
== "box") {
828 auto res
= crypto_box_open(dmem
[0..memsz
], smem
[0..memsz
], nonce
, pk
, sk
);
830 auto res
= crypto_secretbox_open(dmem
[0..memsz
], smem
[0..memsz
], nonce
, pk
);
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.
849 * sm = buffer to receive signed message, must be of size at least msg.length+crypto_sign_BYTES
851 * sk = secret key, slice size must be at least crypto_sign_SECRETKEYBYTES, extra ignored
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;
862 long[16][4] p
= void;
866 crypto_hash(d
, sk
.ptr
[0..32]);
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]);
879 sm
.ptr
[32..64] = sk
.ptr
[32..64];
880 crypto_hash(h
, sm
.ptr
[0..n
+64]);
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'.
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
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");
906 long[16][4] p
= void, q
= void;
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];
918 scalarbase(q
, sm
[32..$]);
923 if (!crypto_verify_32(sm
, t
)) {
928 msg
.ptr
[0..n
] = sm
.ptr
[64..64+n
];
929 if (msg
.length
> n
) msg
[n
..$] = 0;
935 * This function randomly generates a secret key and a corresponding public key.
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)
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");
949 long[16][4] p
= void;
951 randombytes(sk
.ptr
[0..32]);
952 crypto_hash(d
, sk
.ptr
[0..32]);
960 sk
.ptr
[32..64] = pk
.ptr
[0..32];
964 * This function generates a public key from the given secret key.
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)
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");
979 long[16][4] p
= void;
981 //randombytes(sk.ptr[0..32]);
982 crypto_hash(d
, sk
.ptr
[0..32]);
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);
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);
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);
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;
1054 bool vn (const(ubyte)[] x
, const(ubyte)[] y
) {
1055 assert(x
.length
>= y
.length
);
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
)); }
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;
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
..$]);
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 for (auto m
= 0; m
< 4; ++m
) w
.ptr
[4*j
+(j
+m
)%4] = t
.ptr
[m
];
1093 for (auto m
= 0; m
< 16; ++m
) x
.ptr
[m
] = w
.ptr
[m
];
1096 static if (type
== "hsalsa") {
1097 for (auto i
= 0; i
< 16; ++i
) x
.ptr
[i
] += y
.ptr
[i
];
1098 for (auto i
= 0; i
< 4; ++i
) {
1099 x
.ptr
[5*i
] -= ld32(constant
[4*i
..$]);
1100 x
.ptr
[6+i
] -= ld32(input
[4*i
..$]);
1102 for (auto i
= 0; i
< 4; ++i
) {
1103 st32(output
[4*i
..$], x
.ptr
[5*i
]);
1104 st32(output
[16+4*i
..$], x
.ptr
[6+i
]);
1107 for (auto i
= 0; i
< 16; ++i
) st32(output
[4*i
..$], x
.ptr
[i
]+y
.ptr
[i
]);
1111 // public for testing
1112 public void crypto_core_salsa20 (ubyte[] output
, const(ubyte)[] input
, const(ubyte)[] key
, const(ubyte)[] constant
) {
1113 pragma(inline
, true);
1114 salsa_core
!"salsa"(output
, input
, key
, constant
);
1117 // public for testing
1118 public void crypto_core_hsalsa20 (ubyte[] output
, const(ubyte)[] input
, const(ubyte)[] key
, const(ubyte)[] constant
) {
1119 pragma(inline
, true);
1120 salsa_core
!"hsalsa"(output
, input
, key
, constant
);
1123 private immutable ubyte[] sigma
= cast(immutable ubyte[])"expand 32-byte k";
1125 private void add1305 (uint[] h
, const(uint)[] c
) {
1127 foreach (immutable j
; 0..17) {
1128 u
+= h
.ptr
[j
]+c
.ptr
[j
];
1134 private immutable uint[17] minusp
= [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252];
1136 void car25519 (long[] o
) {
1137 foreach (immutable i
; 0..16) {
1138 o
.ptr
[i
] += (1<<16);
1139 long c
= o
.ptr
[i
]>>16;
1140 o
.ptr
[(i
+1)*(i
<15)] += c
-1+37*(c
-1)*(i
==15);
1145 void sel25519 (long[] p
,long[] q
, int b
) {
1147 foreach (immutable i
; 0..16) {
1148 long t
= c
&(p
.ptr
[i
]^q
.ptr
[i
]);
1154 void pack25519 (ubyte[] o
, const(long)[] n
) {
1156 long[16] m
= void, t
= void;
1157 t
.ptr
[0..16] = n
.ptr
[0..16];
1161 foreach (immutable j
; 0..2) {
1162 m
.ptr
[0] = t
.ptr
[0]-0xffed;
1163 foreach (immutable i
; 1..15) {
1164 m
.ptr
[i
] = t
.ptr
[i
]-0xffff-((m
.ptr
[i
-1]>>16)&1);
1165 m
.ptr
[i
-1] &= 0xffff;
1167 m
.ptr
[15] = t
.ptr
[15]-0x7fff-((m
.ptr
[14]>>16)&1);
1168 b
= (m
.ptr
[15]>>16)&1;
1169 m
.ptr
[14] &= 0xffff;
1170 sel25519(t
, m
, 1-b
);
1172 foreach (immutable i
; 0..16) {
1173 o
.ptr
[2*i
] = t
.ptr
[i
]&0xff;
1174 o
.ptr
[2*i
+1] = (t
.ptr
[i
]>>8)&0xff;
1178 bool neq25519 (const(long)[] a
, const(long)[] b
) {
1179 ubyte[32] c
= void, d
= void;
1182 return crypto_verify_32(c
, d
);
1185 ubyte par25519 (const(long)[] a
) {
1191 void unpack25519 (long[] o
, const(ubyte)[] n
) {
1192 foreach (immutable i
; 0..16) o
.ptr
[i
] = n
.ptr
[2*i
]+(cast(long)n
.ptr
[2*i
+1]<<8);
1193 o
.ptr
[15] &= 0x7fff;
1196 void A (long[] o
, const(long)[] a
, const(long)[] b
) {
1197 foreach (immutable i
; 0..16) o
.ptr
[i
] = a
.ptr
[i
]+b
.ptr
[i
];
1200 void Z (long[] o
, const(long)[] a
, const(long)[] b
) {
1201 foreach (immutable i
; 0..16) o
.ptr
[i
] = a
.ptr
[i
]-b
.ptr
[i
];
1204 void M (long[] o
, const(long)[] a
, const(long)[] b
) {
1205 long[31] t
; // automatically becomes 0
1206 foreach (immutable i
; 0..16) foreach (immutable j
; 0..16) t
.ptr
[i
+j
] += a
.ptr
[i
]*b
.ptr
[j
];
1207 foreach (immutable i
; 0..15) t
.ptr
[i
] += 38*t
.ptr
[i
+16];
1208 o
.ptr
[0..16] = t
.ptr
[0..16];
1213 void S (long[] o
, const(long)[] a
) {
1217 void inv25519 (long[] o
, const(long)[] i
) {
1220 for (auto a
= 253; a
>= 0; --a
) {
1222 if (a
!= 2 && a
!= 4) M(c
, c
, i
);
1227 void pow2523 (long[] o
, const(long)[] i
) {
1230 for(auto a
= 250; a
>= 0; --a
) {
1232 if (a
!= 1) M(c
, c
, i
);
1237 // public for testing
1239 * This function multiplies a group element 'p' by an integer 'n'.
1246 * resulting group element 'q' of length crypto_scalarmult_BYTES.
1248 public void crypto_scalarmult (ubyte[] q
, const(ubyte)[] n
, const(ubyte)[] p
) {
1249 assert(q
.length
== crypto_scalarmult_BYTES
);
1250 assert(n
.length
== crypto_scalarmult_BYTES
);
1251 assert(p
.length
== crypto_scalarmult_BYTES
);
1256 long[16] a
= void, b
= void, c
= void, d
= void, e
= void, f
= void;
1258 z
.ptr
[31] = (n
.ptr
[31]&127)|
64;
1261 foreach (immutable i
; 0..16) {
1262 b
.ptr
[i
] = x
.ptr
[i
];
1263 d
.ptr
[i
] = a
.ptr
[i
] = c
.ptr
[i
] = 0;
1265 a
.ptr
[0] = d
.ptr
[0] = 1;
1266 for (int i
= 254; i
>= 0; --i
) {
1267 r
= (z
.ptr
[i
>>3]>>(i
&7))&1;
1268 sel25519(a
, b
, cast(int)r
);
1269 sel25519(c
, d
, cast(int)r
);
1288 sel25519(a
, b
, cast(int)r
);
1289 sel25519(c
, d
, cast(int)r
);
1291 foreach (immutable i
; 0..16) {
1292 x
.ptr
[i
+16] = a
.ptr
[i
];
1293 x
.ptr
[i
+32] = c
.ptr
[i
];
1294 x
.ptr
[i
+48] = b
.ptr
[i
];
1295 x
.ptr
[i
+64] = d
.ptr
[i
];
1297 inv25519(x
[32..$], x
[32..$]);
1298 M(x
[16..$], x
[16..$], x
[32..$]);
1299 pack25519(q
, x
[16..$]);
1302 // public for testing
1304 * This function computes the scalar product of a standard group element
1305 * and an integer 'n'.
1311 * resulting group element 'q' of length crypto_scalarmult_BYTES.
1313 public void crypto_scalarmult_base (ubyte[] q
, const(ubyte)[] n
) {
1314 pragma(inline
, true);
1315 assert(q
.length
== crypto_scalarmult_BYTES
);
1316 assert(n
.length
== crypto_scalarmult_SCALARBYTES
);
1317 crypto_scalarmult(q
, n
, nine_
);
1321 ulong R (ulong x
, int c
) pure { pragma(inline
, true); return (x
>>c
)|
(x
<<(64-c
)); }
1322 ulong Ch (ulong x
, ulong y
, ulong z
) pure { pragma(inline
, true); return (x
&y
)^
(~x
&z
); }
1323 ulong Maj (ulong x
, ulong y
, ulong z
) pure { pragma(inline
, true); return (x
&y
)^
(x
&z
)^
(y
&z
); }
1324 ulong Sigma0 (ulong x
) pure { pragma(inline
, true); return R(x
, 28)^
R(x
, 34)^
R(x
, 39); }
1325 ulong Sigma1 (ulong x
) pure { pragma(inline
, true); return R(x
, 14)^
R(x
, 18)^
R(x
, 41); }
1326 ulong sigma0 (ulong x
) pure { pragma(inline
, true); return R(x
, 1)^
R(x
, 8)^
(x
>>7); }
1327 ulong sigma1 (ulong x
) pure { pragma(inline
, true); return R(x
, 19)^
R(x
, 61)^
(x
>>6); }
1329 immutable ulong[80] K
= [
1330 0x428a2f98d728ae22UL
, 0x7137449123ef65cdUL
, 0xb5c0fbcfec4d3b2fUL
, 0xe9b5dba58189dbbcUL
,
1331 0x3956c25bf348b538UL
, 0x59f111f1b605d019UL
, 0x923f82a4af194f9bUL
, 0xab1c5ed5da6d8118UL
,
1332 0xd807aa98a3030242UL
, 0x12835b0145706fbeUL
, 0x243185be4ee4b28cUL
, 0x550c7dc3d5ffb4e2UL
,
1333 0x72be5d74f27b896fUL
, 0x80deb1fe3b1696b1UL
, 0x9bdc06a725c71235UL
, 0xc19bf174cf692694UL
,
1334 0xe49b69c19ef14ad2UL
, 0xefbe4786384f25e3UL
, 0x0fc19dc68b8cd5b5UL
, 0x240ca1cc77ac9c65UL
,
1335 0x2de92c6f592b0275UL
, 0x4a7484aa6ea6e483UL
, 0x5cb0a9dcbd41fbd4UL
, 0x76f988da831153b5UL
,
1336 0x983e5152ee66dfabUL
, 0xa831c66d2db43210UL
, 0xb00327c898fb213fUL
, 0xbf597fc7beef0ee4UL
,
1337 0xc6e00bf33da88fc2UL
, 0xd5a79147930aa725UL
, 0x06ca6351e003826fUL
, 0x142929670a0e6e70UL
,
1338 0x27b70a8546d22ffcUL
, 0x2e1b21385c26c926UL
, 0x4d2c6dfc5ac42aedUL
, 0x53380d139d95b3dfUL
,
1339 0x650a73548baf63deUL
, 0x766a0abb3c77b2a8UL
, 0x81c2c92e47edaee6UL
, 0x92722c851482353bUL
,
1340 0xa2bfe8a14cf10364UL
, 0xa81a664bbc423001UL
, 0xc24b8b70d0f89791UL
, 0xc76c51a30654be30UL
,
1341 0xd192e819d6ef5218UL
, 0xd69906245565a910UL
, 0xf40e35855771202aUL
, 0x106aa07032bbd1b8UL
,
1342 0x19a4c116b8d2d0c8UL
, 0x1e376c085141ab53UL
, 0x2748774cdf8eeb99UL
, 0x34b0bcb5e19b48a8UL
,
1343 0x391c0cb3c5c95a63UL
, 0x4ed8aa4ae3418acbUL
, 0x5b9cca4f7763e373UL
, 0x682e6ff3d6b2b8a3UL
,
1344 0x748f82ee5defb2fcUL
, 0x78a5636f43172f60UL
, 0x84c87814a1f0ab72UL
, 0x8cc702081a6439ecUL
,
1345 0x90befffa23631e28UL
, 0xa4506cebde82bde9UL
, 0xbef9a3f7b2c67915UL
, 0xc67178f2e372532bUL
,
1346 0xca273eceea26619cUL
, 0xd186b8c721c0c207UL
, 0xeada7dd6cde0eb1eUL
, 0xf57d4f7fee6ed178UL
,
1347 0x06f067aa72176fbaUL
, 0x0a637dc5a2c898a6UL
, 0x113f9804bef90daeUL
, 0x1b710b35131c471bUL
,
1348 0x28db77f523047d84UL
, 0x32caab7b40c72493UL
, 0x3c9ebe0a15c9bebcUL
, 0x431d67c49c100d4cUL
,
1349 0x4cc5d4becb3e42b6UL
, 0x597f299cfc657e2aUL
, 0x5fcb6fab3ad6faecUL
, 0x6c44198c4a475817UL
1352 void crypto_hashblocks (ubyte[] x
, const(ubyte)[] m
, ulong n
) {
1353 ulong[8] z
= void, b
= void, a
= void;
1357 foreach (immutable i
; 0..8) z
.ptr
[i
] = a
.ptr
[i
] = dl64(x
[8*i
..$]);
1359 foreach (immutable i
; 0..16) w
.ptr
[i
] = dl64(m
[mpos
+8*i
..$]);
1360 foreach (immutable i
; 0..80) {
1361 b
.ptr
[0..8] = a
.ptr
[0..8];
1362 t
= a
.ptr
[7]+Sigma1(a
.ptr
[4])+Ch(a
.ptr
[4], a
.ptr
[5], a
.ptr
[6])+K
[i
]+w
.ptr
[i
%16];
1363 b
.ptr
[7] = t
+Sigma0(a
.ptr
[0])+Maj(a
.ptr
[0], a
.ptr
[1], a
.ptr
[2]);
1365 //foreach (immutable j; 0..8) a.ptr[(j+1)%8] = b.ptr[j];
1366 a
.ptr
[1..8] = b
.ptr
[0..7];
1367 a
.ptr
[0] = b
.ptr
[7];
1369 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]);
1372 foreach (immutable i
; 0..8) { a
.ptr
[i
] += z
.ptr
[i
]; z
.ptr
[i
] = a
.ptr
[i
]; }
1376 foreach (immutable i
; 0..8) ts64(x
[8*i
..$], z
.ptr
[i
]);
1379 immutable ubyte[64] ivc
= [
1380 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08,
1381 0xbb, 0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b,
1382 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, 0xf8, 0x2b,
1383 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1,
1384 0x51, 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1,
1385 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
1386 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b,
1387 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79
1391 * This function hashes a message 'msg'.
1392 * It returns a hash 'output'. The output length of 'output'
1393 * should be at least crypto_hash_BYTES.
1396 * output = resulting hash
1402 public void crypto_hash (ubyte[] output
, const(ubyte)[] msg
) {
1403 if (output
.length
< crypto_hash_BYTES
) assert(0, "output too small");
1406 auto n
= msg
.length
;
1412 crypto_hashblocks(h
, msg
, n
);
1417 x
.ptr
[0..n
] = msg
.ptr
[mpos
..mpos
+n
];
1420 n
= 256-128*(n
<112);
1422 ts64(x
[n
-8..$], b
<<3);
1423 crypto_hashblocks(h
, x
, n
);
1425 output
.ptr
[0..64] = h
;
1428 private void add (ref long[16][4] p
, ref long[16][4] q
) {
1429 long[16] a
= void, b
= void, c
= void, d
= void, t
= void, e
= void, f
= void, g
= void, h
= void;
1431 Z(a
, p
.ptr
[1], p
.ptr
[0]);
1432 Z(t
, q
.ptr
[1], q
.ptr
[0]);
1434 A(b
, p
.ptr
[0], p
.ptr
[1]);
1435 A(t
, q
.ptr
[0], q
.ptr
[1]);
1437 M(c
, p
.ptr
[3], q
.ptr
[3]);
1439 M(d
, p
.ptr
[2], q
.ptr
[2]);
1452 void cswap (ref long[16][4] p
, ref long[16][4] q
, ubyte b
) {
1453 pragma(inline
, true);
1454 foreach (immutable i
; 0..4) sel25519(p
.ptr
[i
], q
.ptr
[i
], b
);
1457 void pack (ubyte[] r
, ref long[16][4] p
) {
1458 long[16] tx
= void, ty
= void, zi
= void;
1459 inv25519(zi
, p
.ptr
[2]);
1460 M(tx
, p
.ptr
[0], zi
);
1461 M(ty
, p
.ptr
[1], zi
);
1463 r
.ptr
[31] ^
= par25519(tx
)<<7;
1466 void scalarmult (ref long[16][4] p
, ref long[16][4] q
, const(ubyte)[] s
) {
1471 for (int i
= 255; i
>= 0; --i
) {
1472 ubyte b
= (s
.ptr
[i
/8]>>(i
&7))&1;
1480 void scalarbase (ref long[16][4] p
, const(ubyte)[] s
) {
1481 long[16][4] q
= void;
1486 scalarmult(p
, q
, s
);
1489 immutable ulong[32] L
= [
1490 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
1493 void modL (ubyte[] r
, long[] x
) {
1495 for (auto i
= 63; i
>= 32; --i
) {
1498 for (j
= i
-32; j
< i
-12; ++j
) {
1499 x
.ptr
[j
] += carry
-16*x
.ptr
[i
]*L
[j
-(i
-32)];
1500 carry
= (x
.ptr
[j
]+128)>>8;
1501 x
.ptr
[j
] -= carry
<<8;
1507 foreach (immutable j
; 0..32) {
1508 x
.ptr
[j
] += carry
-(x
.ptr
[31]>>4)*L
[j
];
1509 carry
= x
.ptr
[j
]>>8;
1512 foreach (immutable j
; 0..32) x
.ptr
[j
] -= carry
*L
[j
];
1513 foreach (immutable i
; 0..32) {
1514 x
.ptr
[i
+1] += x
.ptr
[i
]>>8;
1515 r
.ptr
[i
] = x
.ptr
[i
]&255;
1519 void reduce (ubyte[] r
) {
1521 foreach (immutable i
; 0..64) x
.ptr
[i
] = cast(ulong)r
.ptr
[i
];
1526 private bool unpackneg (ref long[16][4] r
, const(ubyte)[] p
) {
1527 long[16] t
= void, chk
= void, num
= void, den
= void, den2
= void, den4
= void, den6
= void;
1529 unpack25519(r
.ptr
[1], p
);
1532 Z(num
, num
, r
.ptr
[2]);
1533 A(den
, r
.ptr
[2], den
);
1537 M(den6
, den4
, den2
);
1545 M(r
.ptr
[0], t
, den
);
1549 if (!neq25519(chk
, num
)) M(r
.ptr
[0], r
.ptr
[0], I
);
1553 if (!neq25519(chk
, num
)) return false;
1555 if (par25519(r
.ptr
[0]) == (p
.ptr
[31]>>7)) Z(r
.ptr
[0], gf0
, r
.ptr
[0]);
1557 M(r
.ptr
[3], r
.ptr
[0], r
.ptr
[1]);
1562 // ////////////////////////////////////////////////////////////////////////// //
1563 // Ketmar's additions
1565 /** Generate 32-byte secret key from the given passphase and salt.
1567 * This is very simple (and cryptographically weak) function to
1568 * generate crypto key from the given passphrase and salt.
1570 * WARNING! This function sux, and it is absolutely cryptographically weak
1571 * (hence the name). Only use it if you don't care about any
1575 * sk = output buffer, should have room for at least 32 bytes
1576 * passphrase = passphrase, arbitrary length
1580 * Generated key in first 32 bytes of sk.
1582 public void weak_crypto_key_from_passphrase (ubyte[] sk
, const(void)[] passphrase
, ulong salt
) @trusted @nogc {
1583 if (sk
.length
< 32) assert(0, "invalid sk size");
1584 static assert(crypto_hash_BYTES
== 64);
1585 ubyte[crypto_hash_BYTES
+24/*nonce*/] hash
= void;
1586 crypto_hash(hash
[], cast(const(ubyte)[])passphrase
[]);
1587 hash
[crypto_hash_BYTES
..$] = 0;
1588 hash
.ptr
[crypto_hash_BYTES
+0] = cast(ubyte)(salt
&0xff);
1589 hash
.ptr
[crypto_hash_BYTES
+1] = cast(ubyte)((salt
>>8)&0xff);
1590 hash
.ptr
[crypto_hash_BYTES
+2] = cast(ubyte)((salt
>>16)&0xff);
1591 hash
.ptr
[crypto_hash_BYTES
+3] = cast(ubyte)((salt
>>24)&0xff);
1592 hash
.ptr
[crypto_hash_BYTES
+4] = cast(ubyte)((salt
>>32)&0xff);
1593 hash
.ptr
[crypto_hash_BYTES
+5] = cast(ubyte)((salt
>>40)&0xff);
1594 hash
.ptr
[crypto_hash_BYTES
+6] = cast(ubyte)((salt
>>48)&0xff);
1595 hash
.ptr
[crypto_hash_BYTES
+7] = cast(ubyte)((salt
>>56)&0xff);
1596 crypto_stream_xor(sk
[0..32], hash
[0..32], hash
[64..64+24], hash
[32..64]);