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 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
]);
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
) {
1128 foreach (immutable j
; 0..17) {
1129 u
+= h
.ptr
[j
]+c
.ptr
[j
];
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);
1146 void sel25519 (long[] p
, long[] q
, int b
) {
1148 foreach (immutable i
; 0..16) {
1149 long t
= c
&(p
.ptr
[i
]^q
.ptr
[i
]);
1155 void pack25519 (ubyte[] o
, const(long)[] n
) {
1157 long[16] m
= void, t
= void;
1158 t
.ptr
[0..16] = n
.ptr
[0..16];
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;
1183 return crypto_verify_32(c
, d
);
1186 ubyte par25519 (const(long)[] a
) {
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];
1214 void S (long[] o
, const(long)[] a
) {
1218 void inv25519 (long[] o
, const(long)[] i
) {
1221 for (auto a
= 253; a
>= 0; --a
) {
1223 if (a
!= 2 && a
!= 4) M(c
, c
, i
);
1228 void pow2523 (long[] o
, const(long)[] i
) {
1231 for(auto a
= 250; a
>= 0; --a
) {
1233 if (a
!= 1) M(c
, c
, i
);
1238 // public for testing
1240 * This function multiplies a group element 'p' by an integer 'n'.
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
);
1257 long[16] a
= void, b
= void, c
= void, d
= void, e
= void, f
= void;
1259 z
.ptr
[31] = (n
.ptr
[31]&127)|
64;
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
);
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
1305 * This function computes the scalar product of a standard group element
1306 * and an integer 'n'.
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_
);
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;
1358 foreach (immutable i
; 0..8) z
.ptr
[i
] = a
.ptr
[i
] = dl64(x
[8*i
..$]);
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]);
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];
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
]; }
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.
1397 * output = resulting hash
1403 public void crypto_hash (ubyte[] output
, const(ubyte)[] msg
) {
1404 if (output
.length
< crypto_hash_BYTES
) assert(0, "output too small");
1407 auto n
= msg
.length
;
1413 crypto_hashblocks(h
, msg
, n
);
1418 x
.ptr
[0..n
] = msg
.ptr
[mpos
..mpos
+n
];
1421 n
= 256-128*(n
<112);
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]);
1435 A(b
, p
.ptr
[0], p
.ptr
[1]);
1436 A(t
, q
.ptr
[0], q
.ptr
[1]);
1438 M(c
, p
.ptr
[3], q
.ptr
[3]);
1440 M(d
, p
.ptr
[2], q
.ptr
[2]);
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
);
1464 r
.ptr
[31] ^
= par25519(tx
)<<7;
1467 void scalarmult (ref long[16][4] p
, ref long[16][4] q
, const(ubyte)[] s
) {
1472 for (int i
= 255; i
>= 0; --i
) {
1473 ubyte b
= (s
.ptr
[i
/8]>>(i
&7))&1;
1481 void scalarbase (ref long[16][4] p
, const(ubyte)[] s
) {
1482 long[16][4] q
= void;
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
) {
1496 for (auto i
= 63; i
>= 32; --i
) {
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;
1508 foreach (immutable j
; 0..32) {
1509 x
.ptr
[j
] += carry
-(x
.ptr
[31]>>4)*L
[j
];
1510 carry
= x
.ptr
[j
]>>8;
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
) {
1522 foreach (immutable i
; 0..64) x
.ptr
[i
] = cast(ulong)r
.ptr
[i
];
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;
1530 unpack25519(r
.ptr
[1], p
);
1533 Z(num
, num
, r
.ptr
[2]);
1534 A(den
, r
.ptr
[2], den
);
1538 M(den6
, den4
, den2
);
1546 M(r
.ptr
[0], t
, den
);
1550 if (!neq25519(chk
, num
)) M(r
.ptr
[0], r
.ptr
[0], I
);
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]);
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
1576 * sk = output buffer, should have room for at least 32 bytes
1577 * passphrase = passphrase, arbitrary length
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]);