1 /**
2 * Noekeon
3 * 
4 * Copyright:
5 * (C) 1999-2008 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.noekeon;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_NOEKEON):
15 
16 import botan.block.block_cipher;
17 import botan.utils.loadstor;
18 import botan.utils.rotate;
19 import botan.utils.mem_ops;
20 
21 /**
22 * Noekeon
23 */
24 class Noekeon : BlockCipherFixedParams!(16, 16), BlockCipher, SymmetricAlgorithm
25 {
26 public:
27     /*
28     * Noekeon Encryption
29     */
30     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
31     {
32         foreach (size_t i; 0 .. blocks)
33         {
34             uint A0 = loadBigEndian!uint(input, 0);
35             uint A1 = loadBigEndian!uint(input, 1);
36             uint A2 = loadBigEndian!uint(input, 2);
37             uint A3 = loadBigEndian!uint(input, 3);
38             
39             foreach (size_t j; 0 .. 16)
40             {
41                 A0 ^= m_RC[j];
42                 theta(A0, A1, A2, A3, m_EK.ptr[0 .. 4]);
43                 
44                 A1 = rotateLeft(A1, 1);
45                 A2 = rotateLeft(A2, 5);
46                 A3 = rotateLeft(A3, 2);
47                 
48                 gamma(A0, A1, A2, A3);
49                 
50                 A1 = rotateRight(A1, 1);
51                 A2 = rotateRight(A2, 5);
52                 A3 = rotateRight(A3, 2);
53             }
54             
55             A0 ^= m_RC[16];
56             theta(A0, A1, A2, A3, m_EK.ptr[0 .. 4]);
57             
58             storeBigEndian(output, A0, A1, A2, A3);
59             
60             input += BLOCK_SIZE;
61             output += BLOCK_SIZE;
62         }
63     }
64 
65     /*
66     * Noekeon Encryption
67     */
68     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
69     {
70         foreach (size_t i; 0 .. blocks)
71         {
72             uint A0 = loadBigEndian!uint(input, 0);
73             uint A1 = loadBigEndian!uint(input, 1);
74             uint A2 = loadBigEndian!uint(input, 2);
75             uint A3 = loadBigEndian!uint(input, 3);
76             
77             for (size_t j = 16; j != 0; --j)
78             {
79                 theta(A0, A1, A2, A3, m_DK.ptr[0 .. 4]);
80                 A0 ^= m_RC[j];
81                 
82                 A1 = rotateLeft(A1, 1);
83                 A2 = rotateLeft(A2, 5);
84                 A3 = rotateLeft(A3, 2);
85                 
86                 gamma(A0, A1, A2, A3);
87                 
88                 A1 = rotateRight(A1, 1);
89                 A2 = rotateRight(A2, 5);
90                 A3 = rotateRight(A3, 2);
91             }
92             
93             theta(A0, A1, A2, A3, m_DK.ptr[0 .. 4]);
94             A0 ^= m_RC[0];
95             
96             storeBigEndian(output, A0, A1, A2, A3);
97             
98             input += BLOCK_SIZE;
99             output += BLOCK_SIZE;
100         }
101     }
102     
103 
104     /*
105     * Clear memory of sensitive data
106     */
107     override void clear()
108     {
109         zap(m_EK);
110         zap(m_DK);
111     }
112     
113 
114     @property string name() const { return "Noekeon"; }
115     override @property size_t parallelism() const { return 1; }
116     override BlockCipher clone() const { return new Noekeon; }
117     override size_t blockSize() const { return super.blockSize(); }
118     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
119 
120 protected:
121     /**
122     * The Noekeon round constants
123     */
124     __gshared immutable ubyte[17] m_RC = [
125         0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
126         0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
127         0xD4 ];
128 
129     /**
130     * Returns: const reference to encryption subkeys
131     */
132     ref const(SecureVector!uint) getEK() const { return m_EK; }
133 
134     /**
135     * Returns: const reference to decryption subkeys
136     */
137     ref const(SecureVector!uint) getDK() const { return m_DK; }
138 
139 protected:
140     /*
141     * Noekeon Key Schedule
142     */
143     override void keySchedule(const(ubyte)* key, size_t)
144     {
145         uint A0 = loadBigEndian!uint(key, 0);
146         uint A1 = loadBigEndian!uint(key, 1);
147         uint A2 = loadBigEndian!uint(key, 2);
148         uint A3 = loadBigEndian!uint(key, 3);
149         
150         foreach (size_t i; 0 .. 16)
151         {
152             A0 ^= m_RC[i];
153             theta(A0, A1, A2, A3);
154             
155             A1 = rotateLeft(A1, 1);
156             A2 = rotateLeft(A2, 5);
157             A3 = rotateLeft(A3, 2);
158             
159             gamma(A0, A1, A2, A3);
160             
161             A1 = rotateRight(A1, 1);
162             A2 = rotateRight(A2, 5);
163             A3 = rotateRight(A3, 2);
164         }
165         
166         A0 ^= m_RC[16];
167         
168         m_DK.resize(4);
169         m_DK[0] = A0;
170         m_DK[1] = A1;
171         m_DK[2] = A2;
172         m_DK[3] = A3;
173         
174         theta(A0, A1, A2, A3);
175         
176         m_EK.resize(4);
177         m_EK[0] = A0;
178         m_EK[1] = A1;
179         m_EK[2] = A2;
180         m_EK[3] = A3;
181     }
182 
183     SecureVector!uint m_EK, m_DK;
184 }
185 
186 package:
187     
188 /*
189 * Noekeon's Theta Operation
190 */
191 void theta(ref uint A0, ref uint A1,
192            ref uint A2, ref uint A3,
193            in uint[] EK) pure
194 {
195     uint T = A0 ^ A2;
196     T ^= rotateLeft(T, 8) ^ rotateRight(T, 8);
197     A1 ^= T;
198     A3 ^= T;
199     
200     A0 ^= EK[0];
201     A1 ^= EK[1];
202     A2 ^= EK[2];
203     A3 ^= EK[3];
204     
205     T = A1 ^ A3;
206     T ^= rotateLeft(T, 8) ^ rotateRight(T, 8);
207     A0 ^= T;
208     A2 ^= T;
209 }
210 
211 /*
212 * Theta With Null Key
213 */
214 void theta(ref uint A0, ref uint A1,
215            ref uint A2, ref uint A3) pure
216 {
217     uint T = A0 ^ A2;
218     T ^= rotateLeft(T, 8) ^ rotateRight(T, 8);
219     A1 ^= T;
220     A3 ^= T;
221     
222     T = A1 ^ A3;
223     T ^= rotateLeft(T, 8) ^ rotateRight(T, 8);
224     A0 ^= T;
225     A2 ^= T;
226 }
227 
228 /*
229 * Noekeon's Gamma S-Box Layer
230 */
231 void gamma(ref uint A0, ref uint A1, ref uint A2, ref uint A3) pure
232 {
233     A1 ^= ~A3 & ~A2;
234     A0 ^= A2 & A1;
235     
236     uint T = A3;
237     A3 = A0;
238     A0 = T;
239     
240     A2 ^= A0 ^ A1 ^ A3;
241     
242     A1 ^= ~A3 & ~A2;
243     A0 ^= A2 & A1;
244 }