flexlay2: respect maximum box size
[iv.d.git] / stc / chacha.d
blobc7c7590eb3e1ce17a19b8ba912a99dcdac56a7e4
1 /*
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*/;
18 import std.range;
19 import iv.alice;
20 import iv.stc.core;
23 public struct ChaCha20 {
24 // base stream cipher interface
25 mixin StreamCipherCore;
27 public:
28 // cipher parameters
29 enum BlockSize = 64;
30 enum IVSize = 8; // in bytes
31 enum KeySize = 32; // in bytes
32 enum SupportIV = true;
34 private:
35 enum sigma = "expand 32-byte k";
36 enum tau = "expand 16-byte k";
38 private:
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;
44 ubyte[] keybuf;
46 usize len = 0;
47 while (!key.empty && len < kb.length) {
48 kb.ptr[len++] = cast(ubyte)key.front;
49 key.popFront;
51 if (len != 16 && len != 32) key.popFront; // this should throw exception
52 keybuf = kb[0..len];
54 ubyte[12] ib = 0;
55 ubyte[] ivbuf;
57 usize len = 0;
58 while (!iv.empty && len < ib.length) {
59 ib.ptr[len++] = cast(ubyte)iv.front;
60 iv.popFront;
62 if (len && len != IVSize) iv.popFront; // this should throw exception
63 ivbuf = ib[0..len];
66 static uint U8TO32_LITTLE (const(ubyte)* n) nothrow @trusted @nogc {
67 uint res = 0;
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;
72 return res;
75 // setup key
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);
80 uint ofs = 0;
81 string constants;
82 if (keybuf.length == 32) {
83 /* recommended */
84 ofs = 16;
85 constants = sigma;
86 } else {
87 /* kbits == 128 */
88 constants = tau;
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);
99 // setup iv
100 state.ptr[12] = 0;
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);
105 } else {
106 state.ptr[13] = 0;
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 {
113 state[] = 0;
116 // output: 64 bytes
117 // input: 16 uints
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[]; }
157 private:
158 uint[16] state;