egra: added some useful primitives to agg drawer
[iv.d.git] / stc / rabbit.d
blob64e1d6e258cd8abd05335ad27aace2689a24ff10
1 /*
2 * Rabbit engine by Cryptico A/S.
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 /****************************************************************************************************/
17 /* Developed by Cryptico A/S. */
18 /* */
19 /* "Rabbit has been released into the public domain and may be used freely for any purpose." */
20 /* http://web.archive.org/web/20121114021058/http://www.ecrypt.eu.org/stream/phorum/read.php?1,1244 */
21 /* */
22 /* Rabbit claims 128-bit security against attackers whose target is one specific key. If, however, */
23 /* the attacker targets a large number of keys at once and does not really care which one he breaks,*/
24 /* then the small IV size results in a reduced security level of 96 bit. This is due to generic TMD */
25 /* trade-off attacks. */
26 /****************************************************************************************************/
27 module iv.stc.rabbit /*is aliced*/;
29 import std.range;
30 import iv.alice;
31 import iv.stc.core;
34 public struct Rabbit {
35 // base stream cipher interface
36 mixin StreamCipherCore;
38 public:
39 // cipher parameters
40 enum BlockSize = 16;
41 enum IVSize = 8; // in bytes
42 enum KeySize = 16; // in bytes
43 enum SupportIV = true;
45 private:
46 void resetState(KR, IR) (KR key, IR iv) @trusted {
47 static if (hasLength!KR) assert(key.length == 16); else assert(!key.empty);
48 static if (hasLength!IR) assert(iv.length == 0 || iv.length == 8);
49 ubyte[KeySize] kb = void;
51 usize len = 0;
52 while (!key.empty && len < kb.length) {
53 kb.ptr[len++] = cast(ubyte)key.front;
54 key.popFront;
56 if (len != KeySize) key.popFront; // this should throw exception
58 ubyte[] keybuf = kb[0..KeySize];
59 ubyte[IVSize] ib = void;
60 ubyte[] ivbuf;
62 usize len = 0;
63 while (!iv.empty && len < ib.length) {
64 ib.ptr[len++] = cast(ubyte)iv.front;
65 iv.popFront;
67 if (len && len != IVSize) iv.popFront; // this should throw exception
68 ivbuf = ib[0..IVSize];
70 uint k0, k1, k2, k3;
71 // generate four subkeys
72 k0 = cast(ubyte)keybuf.ptr[3];
73 k0 = (k0<<8)|cast(ubyte)keybuf.ptr[2];
74 k0 = (k0<<8)|cast(ubyte)keybuf.ptr[1];
75 k0 = (k0<<8)|cast(ubyte)keybuf.ptr[0];
76 // second
77 k1 = cast(ubyte)keybuf.ptr[7];
78 k1 = (k1<<8)|cast(ubyte)keybuf.ptr[6];
79 k1 = (k1<<8)|cast(ubyte)keybuf.ptr[5];
80 k1 = (k1<<8)|cast(ubyte)keybuf.ptr[4];
81 // third
82 k2 = cast(ubyte)keybuf.ptr[11];
83 k2 = (k2<<8)|cast(ubyte)keybuf.ptr[10];
84 k2 = (k2<<8)|cast(ubyte)keybuf.ptr[9];
85 k2 = (k2<<8)|cast(ubyte)keybuf.ptr[8];
86 // fourth
87 k3 = cast(ubyte)keybuf.ptr[15];
88 k3 = (k3<<8)|cast(ubyte)keybuf.ptr[14];
89 k3 = (k3<<8)|cast(ubyte)keybuf.ptr[13];
90 k3 = (k3<<8)|cast(ubyte)keybuf.ptr[12];
91 // generate initial state variables
92 statex.ptr[0] = k0;
93 statex.ptr[2] = k1;
94 statex.ptr[4] = k2;
95 statex.ptr[6] = k3;
96 statex.ptr[1] = (k3<<16)|(k2>>16);
97 statex.ptr[3] = (k0<<16)|(k3>>16);
98 statex.ptr[5] = (k1<<16)|(k0>>16);
99 statex.ptr[7] = (k2<<16)|(k1>>16);
100 // generate initial counter values
101 statec.ptr[0] = bitRotLeft(k2, 16);
102 statec.ptr[2] = bitRotLeft(k3, 16);
103 statec.ptr[4] = bitRotLeft(k0, 16);
104 statec.ptr[6] = bitRotLeft(k1, 16);
105 statec.ptr[1] = (k0&0xFFFF0000U)|(k1&0xFFFF);
106 statec.ptr[3] = (k1&0xFFFF0000U)|(k2&0xFFFF);
107 statec.ptr[5] = (k2&0xFFFF0000U)|(k3&0xFFFF);
108 statec.ptr[7] = (k3&0xFFFF0000U)|(k0&0xFFFF);
109 // clear carry bit
110 statecarry = 0;
111 // iterate the system four times
112 foreach (immutable i; 0..4) nextState();
113 // modify the counters
114 foreach (immutable i; 0..8) statec.ptr[i] ^= statex.ptr[(i+4)&0x7];
115 if (ivbuf.length) {
116 uint i0, i1, i2, i3;
117 // generate four subvectors
118 i0 = cast(ubyte)ivbuf.ptr[3];
119 i0 = (i0<<8)|cast(ubyte)ivbuf.ptr[2];
120 i0 = (i0<<8)|cast(ubyte)ivbuf.ptr[1];
121 i0 = (i0<<8)|cast(ubyte)ivbuf.ptr[0];
122 // third
123 i2 = cast(ubyte)ivbuf.ptr[7];
124 i2 = (i2<<8)|cast(ubyte)ivbuf.ptr[6];
125 i2 = (i2<<8)|cast(ubyte)ivbuf.ptr[5];
126 i2 = (i2<<8)|cast(ubyte)ivbuf.ptr[4];
127 // second
128 i1 = (i0>>16)|(i2&0xFFFF0000U);
129 // fourth
130 i3 = (i2<<16)|(i0&0x0000FFFFU);
131 // modify counter values
132 statec.ptr[0] ^= i0;
133 statec.ptr[1] ^= i1;
134 statec.ptr[2] ^= i2;
135 statec.ptr[3] ^= i3;
136 statec.ptr[4] ^= i0;
137 statec.ptr[5] ^= i1;
138 statec.ptr[6] ^= i2;
139 statec.ptr[7] ^= i3;
140 // iterate the system four times
141 foreach (immutable i; 0..4) nextState();
145 void clearState () nothrow @trusted @nogc {
146 statex[] = 0;
147 statec[] = 0;
148 statecarry = 0;
151 /* Square a 32-bit unsigned integer to obtain the 64-bit result and return */
152 /* the upper 32 bits XOR the lower 32 bits */
153 static uint gfunc (uint x) nothrow @trusted @nogc {
154 pragma(inline, true);
155 uint a, b, h, l;
156 // construct high and low argument for squaring
157 a = x&0xFFFF;
158 b = x>>16;
159 // calculate high and low result of squaring
160 h = ((((a*a)>>17)+(a*b))>>15)+b*b;
161 l = x*x;
162 // return high XOR low
163 return h^l;
166 /* Calculate the next internal state */
167 void nextState () nothrow @trusted @nogc {
168 uint[8] g = void, c_old = void;
169 // save old counter values
170 c_old[0..8] = statec.ptr[0..8];
171 // calculate new counter values
172 statec.ptr[0] = statec.ptr[0]+0x4D34D34DU+statecarry;
173 statec.ptr[1] = statec.ptr[1]+0xD34D34D3U+(statec.ptr[0]<c_old[0]);
174 statec.ptr[2] = statec.ptr[2]+0x34D34D34U+(statec.ptr[1]<c_old[1]);
175 statec.ptr[3] = statec.ptr[3]+0x4D34D34DU+(statec.ptr[2]<c_old[2]);
176 statec.ptr[4] = statec.ptr[4]+0xD34D34D3U+(statec.ptr[3]<c_old[3]);
177 statec.ptr[5] = statec.ptr[5]+0x34D34D34U+(statec.ptr[4]<c_old[4]);
178 statec.ptr[6] = statec.ptr[6]+0x4D34D34DU+(statec.ptr[5]<c_old[5]);
179 statec.ptr[7] = statec.ptr[7]+0xD34D34D3U+(statec.ptr[6]<c_old[6]);
180 statecarry = (statec.ptr[7] < c_old[7]);
181 // calculate the g-values
182 foreach (immutable i, ref n; g) n = gfunc(statex.ptr[i]+statec.ptr[i]);
183 // calculate new state values
184 statex.ptr[0] = g.ptr[0]+bitRotLeft(g.ptr[7],16)+bitRotLeft(g.ptr[6], 16);
185 statex.ptr[1] = g.ptr[1]+bitRotLeft(g.ptr[0], 8)+g.ptr[7];
186 statex.ptr[2] = g.ptr[2]+bitRotLeft(g.ptr[1],16)+bitRotLeft(g.ptr[0], 16);
187 statex.ptr[3] = g.ptr[3]+bitRotLeft(g.ptr[2], 8)+g.ptr[1];
188 statex.ptr[4] = g.ptr[4]+bitRotLeft(g.ptr[3],16)+bitRotLeft(g.ptr[2], 16);
189 statex.ptr[5] = g.ptr[5]+bitRotLeft(g.ptr[4], 8)+g.ptr[3];
190 statex.ptr[6] = g.ptr[6]+bitRotLeft(g.ptr[5],16)+bitRotLeft(g.ptr[4], 16);
191 statex.ptr[7] = g.ptr[7]+bitRotLeft(g.ptr[6], 8)+g.ptr[5];
194 /* Generate buffer to xor later */
195 void getBuf () nothrow @trusted @nogc {
196 void putToBuf (usize pos, uint n) nothrow @trusted @nogc {
197 buf.ptr[pos+0] = n&0xff;
198 buf.ptr[pos+1] = (n>>8)&0xff;
199 buf.ptr[pos+2] = (n>>16)&0xff;
200 buf.ptr[pos+3] = (n>>24)&0xff;
202 // iterate the system
203 nextState();
204 // generate 16 bytes of pseudo-random data
205 putToBuf( 0, statex.ptr[0]^(statex.ptr[5]>>16)^(statex.ptr[3]<<16));
206 putToBuf( 4, statex.ptr[2]^(statex.ptr[7]>>16)^(statex.ptr[5]<<16));
207 putToBuf( 8, statex.ptr[4]^(statex.ptr[1]>>16)^(statex.ptr[7]<<16));
208 putToBuf(12, statex.ptr[6]^(statex.ptr[3]>>16)^(statex.ptr[1]<<16));
211 private:
212 uint[8] statex;
213 uint[8] statec;
214 uint statecarry;
218 unittest {
219 import std.stdio;
220 auto rb0 = Rabbit("thisiscipherkey!");
221 auto rb1 = Rabbit("thisiscipherkey!");
222 string s0 = "test";
223 string s1 = "text";
224 ubyte[] o0, o1;
225 o0.length = 8;
226 o1.length = 8;
227 rb0.process(o0[0..4], s0);
228 rb0.process(o0[4..8], s1);
229 rb1.process(o1, s0~s1);
230 assert(o0 == o1);
234 unittest {
235 import std.stdio;
236 import iv.stc.testing;
237 writeln("testing Rabbit...");
238 processTVFile!Rabbit(import("rabbit-verified.test-vectors"));
239 writeln(count, " tests passed.");