2 * Salsa20 engine by D. J. Bernstein.
3 * Copyright (C) 2014 Ketmar Dark // Invisible Vector (ketmar@ketmar.no-ip.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * Get a copy of the GNU GPL from <http://www.gnu.org/licenses/>.
16 module iv
.stc.chacha
/*is aliced*/;
23 public struct ChaCha20
{
24 // base stream cipher interface
25 mixin StreamCipherCore
;
30 enum IVSize
= 8; // in bytes
31 enum KeySize
= 32; // in bytes
32 enum SupportIV
= true;
35 enum sigma
= "expand 32-byte k";
36 enum tau
= "expand 16-byte k";
39 void resetState(KR
, IR
) (KR key
, IR iv
) @trusted {
40 static assert(IVSize
== 8);
41 static if (hasLength
!KR
) assert(key
.length
== 16 || key
.length
== 32); else assert(!key
.empty
);
42 static if (hasLength
!IR
) assert(iv
.length
== 0 || iv
.length
== 8 || iv
.length
== 12);
43 ubyte[KeySize
] kb
= 0;
47 while (!key
.empty
&& len
< kb
.length
) {
48 kb
.ptr
[len
++] = cast(ubyte)key
.front
;
51 if (len
!= 16 && len
!= 32) key
.popFront
; // this should throw exception
58 while (!iv
.empty
&& len
< ib
.length
) {
59 ib
.ptr
[len
++] = cast(ubyte)iv
.front
;
62 if (len
&& len
!= IVSize
) iv
.popFront
; // this should throw exception
66 static uint U8TO32_LITTLE (const(ubyte)* n
) nothrow @trusted @nogc {
68 res |
= cast(uint)n
[0];
69 res |
= cast(uint)n
[1]<<8;
70 res |
= cast(uint)n
[2]<<16;
71 res |
= cast(uint)n
[3]<<24;
76 state
.ptr
[4] = U8TO32_LITTLE(kb
.ptr
+0);
77 state
.ptr
[5] = U8TO32_LITTLE(kb
.ptr
+4);
78 state
.ptr
[6] = U8TO32_LITTLE(kb
.ptr
+8);
79 state
.ptr
[7] = U8TO32_LITTLE(kb
.ptr
+12);
82 if (keybuf
.length
== 32) {
90 state
.ptr
[8] = U8TO32_LITTLE(kb
.ptr
+ofs
+0);
91 state
.ptr
[9] = U8TO32_LITTLE(kb
.ptr
+ofs
+4);
92 state
.ptr
[10] = U8TO32_LITTLE(kb
.ptr
+ofs
+8);
93 state
.ptr
[11] = U8TO32_LITTLE(kb
.ptr
+ofs
+12);
94 state
.ptr
[0] = U8TO32_LITTLE(cast(immutable(ubyte*))constants
.ptr
+0);
95 state
.ptr
[1] = U8TO32_LITTLE(cast(immutable(ubyte*))constants
.ptr
+4);
96 state
.ptr
[2] = U8TO32_LITTLE(cast(immutable(ubyte*))constants
.ptr
+8);
97 state
.ptr
[3] = U8TO32_LITTLE(cast(immutable(ubyte*))constants
.ptr
+12);
101 if (ivbuf
.length
== 12) {
102 state
.ptr
[13] = U8TO32_LITTLE(ivbuf
.ptr
+0);
103 state
.ptr
[14] = U8TO32_LITTLE(ivbuf
.ptr
+4);
104 state
.ptr
[15] = U8TO32_LITTLE(ivbuf
.ptr
+8);
107 if (ivbuf
.length
>= 4) state
.ptr
[14] = U8TO32_LITTLE(ivbuf
.ptr
+0);
108 if (ivbuf
.length
>= 8) state
.ptr
[15] = U8TO32_LITTLE(ivbuf
.ptr
+4);
112 void clearState () nothrow @trusted @nogc {
118 static void nextState (ubyte[] output
, const(uint)[] input
) nothrow @trusted @nogc {
119 assert(output
.length
== 64);
120 assert(input
.length
== 16);
122 enum QUARTERROUND(int a
, int b
, int c
, int d
) =
123 "x.ptr["~a
.stringof
~"] = cast(uint)x.ptr["~a
.stringof
~"]+x.ptr["~b
.stringof
~"]; x.ptr["~d
.stringof
~"] = bitRotLeft(x.ptr["~d
.stringof
~"]^x.ptr["~a
.stringof
~"],16);\n"~
124 "x.ptr["~c
.stringof
~"] = cast(uint)x.ptr["~c
.stringof
~"]+x.ptr["~d
.stringof
~"]; x.ptr["~b
.stringof
~"] = bitRotLeft(x.ptr["~b
.stringof
~"]^x.ptr["~c
.stringof
~"],12);\n"~
125 "x.ptr["~a
.stringof
~"] = cast(uint)x.ptr["~a
.stringof
~"]+x.ptr["~b
.stringof
~"]; x.ptr["~d
.stringof
~"] = bitRotLeft(x.ptr["~d
.stringof
~"]^x.ptr["~a
.stringof
~"], 8);\n"~
126 "x.ptr["~c
.stringof
~"] = cast(uint)x.ptr["~c
.stringof
~"]+x.ptr["~d
.stringof
~"]; x.ptr["~b
.stringof
~"] = bitRotLeft(x.ptr["~b
.stringof
~"]^x.ptr["~c
.stringof
~"], 7);\n";
128 uint[16] x
= input
[0..16];
130 foreach (immutable _
; 0..10) {
131 mixin(QUARTERROUND
!( 0, 4, 8,12));
132 mixin(QUARTERROUND
!( 1, 5, 9,13));
133 mixin(QUARTERROUND
!( 2, 6,10,14));
134 mixin(QUARTERROUND
!( 3, 7,11,15));
135 mixin(QUARTERROUND
!( 0, 5,10,15));
136 mixin(QUARTERROUND
!( 1, 6,11,12));
137 mixin(QUARTERROUND
!( 2, 7, 8,13));
138 mixin(QUARTERROUND
!( 3, 4, 9,14));
141 foreach (immutable i
, ref n
; x
) n
+= input
.ptr
[i
];
142 foreach (immutable i
, uint n
; x
) {
143 output
.ptr
[i
*4] = n
&0xff;
144 output
.ptr
[i
*4+1] = (n
>>8)&0xff;
145 output
.ptr
[i
*4+2] = (n
>>16)&0xff;
146 output
.ptr
[i
*4+3] = (n
>>24)&0xff;
150 void getBuf () nothrow @trusted @nogc {
151 nextState(buf
, state
);
152 if (++state
.ptr
[12] == 0) ++state
.ptr
[13]; // stopping at 2^70 bytes per nonce is user's responsibility
155 public @property uint[16] getState () nothrow @trusted @nogc { return state
[]; }