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.chacha8
/*is aliced*/;
23 public struct ChaCha8
{
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);
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);
102 if (ivbuf
.length
>= 4) state
.ptr
[14] = U8TO32_LITTLE(ivbuf
.ptr
+0);
103 if (ivbuf
.length
>= 8) state
.ptr
[15] = U8TO32_LITTLE(ivbuf
.ptr
+4);
106 void clearState () nothrow @trusted @nogc {
112 static void nextState (ubyte[] output
, const(uint)[] input
) nothrow @trusted @nogc {
113 assert(output
.length
== 64);
114 assert(input
.length
== 16);
116 enum QUARTERROUND(int a
, int b
, int c
, int d
) =
117 "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"~
118 "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"~
119 "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"~
120 "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";
122 uint[16] x
= input
[0..16];
124 for (int i
= 8; i
> 0; i
-= 2) {
125 mixin(QUARTERROUND
!( 0, 4, 8,12));
126 mixin(QUARTERROUND
!( 1, 5, 9,13));
127 mixin(QUARTERROUND
!( 2, 6,10,14));
128 mixin(QUARTERROUND
!( 3, 7,11,15));
129 mixin(QUARTERROUND
!( 0, 5,10,15));
130 mixin(QUARTERROUND
!( 1, 6,11,12));
131 mixin(QUARTERROUND
!( 2, 7, 8,13));
132 mixin(QUARTERROUND
!( 3, 4, 9,14));
135 foreach (immutable i
, ref n
; x
) n
+= input
.ptr
[i
];
136 foreach (immutable i
, uint n
; x
) {
137 output
.ptr
[i
*4] = n
&0xff;
138 output
.ptr
[i
*4+1] = (n
>>8)&0xff;
139 output
.ptr
[i
*4+2] = (n
>>16)&0xff;
140 output
.ptr
[i
*4+3] = (n
>>24)&0xff;
144 void getBuf () nothrow @trusted @nogc {
145 nextState(buf
, state
);
146 if (++state
.ptr
[12] == 0) ++state
.ptr
[13]; // stopping at 2^70 bytes per nonce is user's responsibility
149 public @property uint[16] getState () nothrow @trusted @nogc { return state
[]; }