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. */
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 */
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*/;
34 public struct Rabbit
{
35 // base stream cipher interface
36 mixin StreamCipherCore
;
41 enum IVSize
= 8; // in bytes
42 enum KeySize
= 16; // in bytes
43 enum SupportIV
= true;
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;
52 while (!key
.empty
&& len
< kb
.length
) {
53 kb
.ptr
[len
++] = cast(ubyte)key
.front
;
56 if (len
!= KeySize
) key
.popFront
; // this should throw exception
58 ubyte[] keybuf
= kb
[0..KeySize
];
59 ubyte[IVSize
] ib
= void;
63 while (!iv
.empty
&& len
< ib
.length
) {
64 ib
.ptr
[len
++] = cast(ubyte)iv
.front
;
67 if (len
&& len
!= IVSize
) iv
.popFront
; // this should throw exception
68 ivbuf
= ib
[0..IVSize
];
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];
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];
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];
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
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);
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];
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];
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];
128 i1
= (i0
>>16)|
(i2
&0xFFFF0000U
);
130 i3
= (i2
<<16)|
(i0
&0x0000FFFFU
);
131 // modify counter values
140 // iterate the system four times
141 foreach (immutable i
; 0..4) nextState();
145 void clearState () nothrow @trusted @nogc {
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);
156 // construct high and low argument for squaring
159 // calculate high and low result of squaring
160 h
= ((((a
*a
)>>17)+(a
*b
))>>15)+b
*b
;
162 // return high XOR low
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
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));
220 auto rb0
= Rabbit("thisiscipherkey!");
221 auto rb1
= Rabbit("thisiscipherkey!");
227 rb0
.process(o0
[0..4], s0
);
228 rb0
.process(o0
[4..8], s1
);
229 rb1
.process(o1
, s0
~s1
);
236 import iv
.stc.testing
;
237 writeln("testing Rabbit...");
238 processTVFile
!Rabbit(import("rabbit-verified.test-vectors"));
239 writeln(count
, " tests passed.");