1 /**
2 * Threefish
3 * 
4 * Copyright:
5 * (C) 2013,2014 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.block.threefish;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_THREEFISH_512):
15 
16 import botan.utils.rotate;
17 import botan.utils.loadstor;
18 import botan.block.block_cipher;
19 import botan.utils.types;
20 import botan.utils.mem_ops;
21 import std.format : format;
22 
23 /**
24 * Threefish-512
25 */
26 class Threefish512 : BlockCipherFixedParams!(64, 64), BlockCipher, SymmetricAlgorithm
27 {
28 public:
29     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
30     {
31         assert(m_K.length == 9, "Key was set");
32         assert(m_T.length == 3, "Tweak was set");
33         
34         foreach (size_t i; 0 .. blocks)
35         {
36             ulong X0 = loadLittleEndian!ulong(input, 0);
37             ulong X1 = loadLittleEndian!ulong(input, 1);
38             ulong X2 = loadLittleEndian!ulong(input, 2);
39             ulong X3 = loadLittleEndian!ulong(input, 3);
40             ulong X4 = loadLittleEndian!ulong(input, 4);
41             ulong X5 = loadLittleEndian!ulong(input, 5);
42             ulong X6 = loadLittleEndian!ulong(input, 6);
43             ulong X7 = loadLittleEndian!ulong(input, 7);
44             
45             mixin(THREEFISH_ENC_INJECT_KEY!(0));
46 
47             mixin(THREEFISH_ENC_8_ROUNDS!(1,2));
48             mixin(THREEFISH_ENC_8_ROUNDS!(3,4));
49             mixin(THREEFISH_ENC_8_ROUNDS!(5,6));
50             mixin(THREEFISH_ENC_8_ROUNDS!(7,8));
51             mixin(THREEFISH_ENC_8_ROUNDS!(9,10));
52             mixin(THREEFISH_ENC_8_ROUNDS!(11,12));
53             mixin(THREEFISH_ENC_8_ROUNDS!(13,14));
54             mixin(THREEFISH_ENC_8_ROUNDS!(15,16));
55             mixin(THREEFISH_ENC_8_ROUNDS!(17,18));
56             
57             storeLittleEndian(output, X0, X1, X2, X3, X4, X5, X6, X7);
58             
59             input += 64;
60             output += 64;
61         }
62     }
63 
64     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
65     {
66         assert(m_K.length == 9, "Key was set");
67         assert(m_T.length == 3, "Tweak was set");
68         
69         foreach (size_t i; 0 .. blocks)
70         {
71             ulong X0 = loadLittleEndian!ulong(input, 0);
72             ulong X1 = loadLittleEndian!ulong(input, 1);
73             ulong X2 = loadLittleEndian!ulong(input, 2);
74             ulong X3 = loadLittleEndian!ulong(input, 3);
75             ulong X4 = loadLittleEndian!ulong(input, 4);
76             ulong X5 = loadLittleEndian!ulong(input, 5);
77             ulong X6 = loadLittleEndian!ulong(input, 6);
78             ulong X7 = loadLittleEndian!ulong(input, 7);
79             
80             mixin(THREEFISH_DEC_INJECT_KEY!(18));
81 
82             mixin(THREEFISH_DEC_8_ROUNDS!(17,16));
83             mixin(THREEFISH_DEC_8_ROUNDS!(15,14));
84             mixin(THREEFISH_DEC_8_ROUNDS!(13,12));
85             mixin(THREEFISH_DEC_8_ROUNDS!(11,10));
86             mixin(THREEFISH_DEC_8_ROUNDS!(9,8));
87             mixin(THREEFISH_DEC_8_ROUNDS!(7,6));
88             mixin(THREEFISH_DEC_8_ROUNDS!(5,4));
89             mixin(THREEFISH_DEC_8_ROUNDS!(3,2));
90             mixin(THREEFISH_DEC_8_ROUNDS!(1,0));
91             
92             storeLittleEndian(output, X0, X1, X2, X3, X4, X5, X6, X7);
93             
94             input += 64;
95             output += 64;
96         }
97     }
98 
99     final void setTweak(const(ubyte)* tweak, size_t len)
100     {
101         if (len != 16)
102             throw new Exception("Unsupported twofish tweak length");
103         m_T[0] = loadLittleEndian!ulong(tweak, 0);
104         m_T[1] = loadLittleEndian!ulong(tweak, 1);
105         m_T[2] = m_T[0] ^ m_T[1];
106     }
107 
108     override void clear()
109     {
110         if (m_T.length == 0) m_T = SecureVector!ulong(3);
111         else zeroise(m_T);
112         if (m_K.length == 0) m_K = SecureVector!ulong(9);
113         else zeroise(m_K);
114     }
115 
116     final override @property string name() const { return "Threefish-512"; }
117     override @property size_t parallelism() const { return 1; }
118     override BlockCipher clone() const { return new Threefish512; }
119     override size_t blockSize() const { return super.blockSize(); }
120     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
121 
122     this() {
123         m_T = SecureVector!ulong(3);
124     }
125 
126 protected:
127     final ref const(SecureVector!ulong) getT() const { return m_T; }
128     final ref const(SecureVector!ulong) getK() const { return m_K; }
129     override void keySchedule(const(ubyte)* key, size_t)
130     {
131         // todo: define key schedule for smaller keys
132         m_K.resize(9);
133         
134         foreach (size_t i; 0 .. 8)
135             m_K[i] = loadLittleEndian!ulong(key, i);
136         
137         m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^
138                  m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22;
139     }
140 public:
141     final void skeinFeedfwd(const ref SecureVector!ulong M, const ref SecureVector!ulong T)
142     {
143         assert(m_K.length == 9, "Key was set");
144         assert(M.length == 8, "Single block");
145         
146         m_T[0] = T[0];
147         m_T[1] = T[1];
148         m_T[2] = T[0] ^ T[1];
149         
150         ulong X0 = M[0];
151         ulong X1 = M[1];
152         ulong X2 = M[2];
153         ulong X3 = M[3];
154         ulong X4 = M[4];
155         ulong X5 = M[5];
156         ulong X6 = M[6];
157         ulong X7 = M[7];
158         
159         mixin(THREEFISH_ENC_INJECT_KEY!(0));
160 
161         mixin(THREEFISH_ENC_8_ROUNDS!(1,2));
162         mixin(THREEFISH_ENC_8_ROUNDS!(3,4));
163         mixin(THREEFISH_ENC_8_ROUNDS!(5,6));
164         mixin(THREEFISH_ENC_8_ROUNDS!(7,8));
165         mixin(THREEFISH_ENC_8_ROUNDS!(9,10));
166         mixin(THREEFISH_ENC_8_ROUNDS!(11,12));
167         mixin(THREEFISH_ENC_8_ROUNDS!(13,14));
168         mixin(THREEFISH_ENC_8_ROUNDS!(15,16));
169         mixin(THREEFISH_ENC_8_ROUNDS!(17,18));
170         
171         m_K[0] = M[0] ^ X0;
172         m_K[1] = M[1] ^ X1;
173         m_K[2] = M[2] ^ X2;
174         m_K[3] = M[3] ^ X3;
175         m_K[4] = M[4] ^ X4;
176         m_K[5] = M[5] ^ X5;
177         m_K[6] = M[6] ^ X6;
178         m_K[7] = M[7] ^ X7;
179         
180         m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^
181                  m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22;
182     }
183 
184     // Private data
185     SecureVector!ulong m_T;
186     SecureVector!ulong m_K;
187 }
188 
189 package:
190 
191 
192 enum string THREEFISH_ENC_ROUND(alias _X0, alias _X1, alias _X2, alias _X3, 
193                            alias _X4, alias _X5, alias _X6, alias _X7, 
194                            ubyte _ROT1, ubyte _ROT2, ubyte _ROT3, ubyte _ROT4) = q{
195     %1$s += %5$s;
196     %2$s += %6$s;
197     %3$s += %7$s;
198     %4$s += %8$s;
199     %5$s = rotateLeft(%5$s, %9$s);
200     %6$s = rotateLeft(%6$s, %10$s);
201     %7$s = rotateLeft(%7$s, %11$s);
202     %8$s = rotateLeft(%8$s, %12$s);
203     %5$s ^= %1$s;
204     %6$s ^= %2$s;
205     %7$s ^= %3$s;
206     %8$s ^= %4$s;
207 }.format(
208     __traits(identifier, _X0), __traits(identifier, _X1), __traits(identifier, _X2), __traits(identifier, _X3),
209     __traits(identifier, _X4), __traits(identifier, _X5), __traits(identifier, _X6), __traits(identifier, _X7),
210     _ROT1.stringof, _ROT2.stringof, _ROT3.stringof, _ROT4.stringof);
211 
212 enum string THREEFISH_ENC_INJECT_KEY(ushort r) = 
213     `X0 += m_K[(` ~ r.stringof ~ `  ) % 9];
214     X1 += m_K[(` ~ (r + 1).stringof ~ `) % 9];
215     X2 += m_K[(` ~ (r + 2).stringof ~ `) % 9];
216     X3 += m_K[(` ~ (r + 3).stringof ~ `) % 9];
217     X4 += m_K[(` ~ (r + 4).stringof ~ `) % 9];
218     X5 += m_K[(` ~ (r + 5).stringof ~ `) % 9] + m_T[(` ~ r.stringof ~ `  ) % 3];
219     X6 += m_K[(` ~ (r + 6).stringof ~ `) % 9] + m_T[(` ~ (r + 1).stringof ~ `) % 3];
220     X7 += m_K[(` ~ (r + 7).stringof ~ `) % 9] + (` ~ r.stringof ~ `);`;
221 
222 enum string THREEFISH_ENC_8_ROUNDS(ushort R1, ushort R2) =
223     `mixin(THREEFISH_ENC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37));
224     mixin(THREEFISH_ENC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42));
225     mixin(THREEFISH_ENC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39));
226     mixin(THREEFISH_ENC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56));
227     mixin(THREEFISH_ENC_INJECT_KEY!(` ~ R1.stringof ~ `));
228     mixin(THREEFISH_ENC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24));
229     mixin(THREEFISH_ENC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17));
230     mixin(THREEFISH_ENC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43));
231     mixin(THREEFISH_ENC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3,  8,35,56,22));
232     mixin(THREEFISH_ENC_INJECT_KEY!(` ~ R2.stringof ~ `));`;
233 
234 enum string THREEFISH_DEC_ROUND(alias _X0, alias _X1, alias _X2, alias _X3, 
235                            alias _X4, alias _X5, alias _X6, alias _X7, 
236                            ubyte _ROT1, ubyte _ROT2, ubyte _ROT3, ubyte _ROT4) = q{
237     %5$s ^= %1$s;
238     %6$s ^= %2$s;
239     %7$s ^= %3$s;
240     %8$s ^= %4$s;
241     %5$s = rotateRight(%5$s, %9$s);
242     %6$s = rotateRight(%6$s, %10$s);
243     %7$s = rotateRight(%7$s, %11$s);
244     %8$s = rotateRight(%8$s, %12$s);
245     %1$s -= %5$s;
246     %2$s -= %6$s;
247     %3$s -= %7$s;
248     %4$s -= %8$s;
249 }.format(
250     __traits(identifier, _X0), __traits(identifier, _X1), __traits(identifier, _X2), __traits(identifier, _X3),
251     __traits(identifier, _X4), __traits(identifier, _X5), __traits(identifier, _X6), __traits(identifier, _X7),
252     _ROT1.stringof, _ROT2.stringof, _ROT3.stringof, _ROT4.stringof);
253     
254 enum string THREEFISH_DEC_INJECT_KEY(ushort r) =
255     `X0 -= m_K[(` ~ r.stringof ~ `  ) % 9];
256     X1 -= m_K[(` ~ (r+1).stringof ~ `) % 9];
257     X2 -= m_K[(` ~ (r+2).stringof ~ `) % 9];
258     X3 -= m_K[(` ~ (r+3).stringof ~ `) % 9];
259     X4 -= m_K[(` ~ (r+4).stringof ~ `) % 9];
260     X5 -= m_K[(` ~ (r+5).stringof ~ `) % 9] + m_T[(` ~ r.stringof ~ `  ) % 3];
261     X6 -= m_K[(` ~ (r+6).stringof ~ `) % 9] + m_T[(` ~ (r+1).stringof ~ `) % 3];
262     X7 -= m_K[(` ~ (r+7).stringof ~ `) % 9] + (` ~ r.stringof ~ `);`;
263 
264 enum string THREEFISH_DEC_8_ROUNDS(ushort R1, ushort R2) =
265     `mixin(THREEFISH_DEC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3,  8,35,56,22));
266     mixin(THREEFISH_DEC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43));
267     mixin(THREEFISH_DEC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17));
268     mixin(THREEFISH_DEC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24));
269     mixin(THREEFISH_DEC_INJECT_KEY!(` ~ R1.stringof ~ `));
270     mixin(THREEFISH_DEC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56));
271     mixin(THREEFISH_DEC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39));
272     mixin(THREEFISH_DEC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42));
273     mixin(THREEFISH_DEC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37));
274     mixin(THREEFISH_DEC_INJECT_KEY!(` ~ R2.stringof ~ `));`;
275