]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sshaes.c
Preliminary support for RSA user authentication in SSH2! Most of the
[PuTTY.git] / sshaes.c
1 /*
2  * aes.c - implementation of AES / Rijndael
3  * 
4  * AES is a flexible algorithm as regards endianness: it has no
5  * inherent preference as to which way round you should form words
6  * from the input byte stream. It talks endlessly of four-byte
7  * _vectors_, but never of 32-bit _words_ - there's no 32-bit
8  * addition at all, which would force an endianness by means of
9  * which way the carries went. So it would be possible to write a
10  * working AES that read words big-endian, and another working one
11  * that read them little-endian, just by computing a different set
12  * of tables - with no speed drop.
13  * 
14  * It's therefore tempting to do just that, and remove the overhead
15  * of GET_32BIT_MSB_FIRST() et al, allowing every system to use its
16  * own endianness-native code; but I decided not to, partly for
17  * ease of testing, and mostly because I like the flexibility that
18  * allows you to encrypt a non-word-aligned block of memory (which
19  * many systems would stop being able to do if I went the
20  * endianness-dependent route).
21  * 
22  * This implementation reads and stores words big-endian, but
23  * that's a minor implementation detail. By flipping the endianness
24  * of everything in the E0..E3, D0..D3 tables, and substituting
25  * GET_32BIT_LSB_FIRST for GET_32BIT_MSB_FIRST, I could create an
26  * implementation that worked internally little-endian and gave the
27  * same answers at the same speed.
28  */
29
30 #include <assert.h>
31 #include <stdlib.h>
32
33 #include "ssh.h"
34
35 typedef unsigned int word32;
36
37 #define MAX_NR 14                      /* max no of rounds */
38 #define MAX_NK 8                       /* max no of words in input key */
39 #define MAX_NB 8                       /* max no of words in cipher blk */
40
41 #define mulby2(x) ( ((x&0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0) )
42
43 #define GET_32BIT_MSB_FIRST(cp) \
44   (((unsigned long)(unsigned char)(cp)[3]) | \
45   ((unsigned long)(unsigned char)(cp)[2] << 8) | \
46   ((unsigned long)(unsigned char)(cp)[1] << 16) | \
47   ((unsigned long)(unsigned char)(cp)[0] << 24))
48
49 #define PUT_32BIT_MSB_FIRST(cp, value) do { \
50   (cp)[3] = (value); \
51   (cp)[2] = (value) >> 8; \
52   (cp)[1] = (value) >> 16; \
53   (cp)[0] = (value) >> 24; } while (0)
54
55 typedef struct AESContext AESContext;
56
57 struct AESContext {
58     word32 keysched[(MAX_NR+1) * MAX_NB];
59     word32 invkeysched[(MAX_NR+1) * MAX_NB];
60     void (*encrypt)(AESContext *ctx, word32 *block);
61     void (*decrypt)(AESContext *ctx, word32 *block);
62     word32 iv[MAX_NB];
63     int Nb, Nr;
64 };
65
66 static const unsigned char Sbox[256], Sboxinv[256];
67 static const word32 E0[256], E1[256], E2[256], E3[256];
68 static const word32 D0[256], D1[256], D2[256], D3[256];
69
70 /*
71  * Common macros in both the encryption and decryption routines.
72  */
73 #define ADD_ROUND_KEY_4 (block[0]^=*keysched++, block[1]^=*keysched++, \
74                          block[2]^=*keysched++, block[3]^=*keysched++)
75 #define ADD_ROUND_KEY_6 (block[0]^=*keysched++, block[1]^=*keysched++, \
76                          block[2]^=*keysched++, block[3]^=*keysched++, \
77                          block[4]^=*keysched++, block[5]^=*keysched++)
78 #define ADD_ROUND_KEY_8 (block[0]^=*keysched++, block[1]^=*keysched++, \
79                          block[2]^=*keysched++, block[3]^=*keysched++, \
80                          block[4]^=*keysched++, block[5]^=*keysched++, \
81                          block[6]^=*keysched++, block[7]^=*keysched++)
82 #define MOVEWORD(i) ( block[i] = newstate[i] )
83
84 /*
85  * Macros for the encryption routine. There are three encryption
86  * cores, for Nb=4,6,8.
87  */
88 #define MAKEWORD(i) ( newstate[i] = (E0[(block[i] >> 24) & 0xFF] ^ \
89                                      E1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \
90                                      E2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \
91                                      E3[block[(i+C3)%Nb] & 0xFF]) )
92 #define LASTWORD(i) ( newstate[i] = (Sbox[(block[i] >> 24) & 0xFF] << 24) | \
93                             (Sbox[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \
94                             (Sbox[(block[(i+C2)%Nb] >>  8) & 0xFF] <<  8) | \
95                             (Sbox[(block[(i+C3)%Nb]      ) & 0xFF]      ) )
96
97 /*
98  * Core encrypt routines, expecting word32 inputs read big-endian
99  * from the byte-oriented input stream.
100  */
101 static void aes_encrypt_nb_4(AESContext *ctx, word32 *block) {
102     int i;
103     static const int C1 = 1, C2 = 2, C3 = 3, Nb = 4;
104     word32 *keysched = ctx->keysched;
105     word32 newstate[4];
106     for (i = 0; i < ctx->Nr-1; i++) {
107         ADD_ROUND_KEY_4;
108         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2); MAKEWORD(3);
109         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
110     }
111     ADD_ROUND_KEY_4;
112     LASTWORD(0); LASTWORD(1); LASTWORD(2); LASTWORD(3);
113     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
114     ADD_ROUND_KEY_4;
115 }
116 static void aes_encrypt_nb_6(AESContext *ctx, word32 *block) {
117     int i;
118     static const int C1 = 1, C2 = 2, C3 = 3, Nb = 6;
119     word32 *keysched = ctx->keysched;
120     word32 newstate[6];
121     for (i = 0; i < ctx->Nr-1; i++) {
122         ADD_ROUND_KEY_6;
123         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2);
124         MAKEWORD(3); MAKEWORD(4); MAKEWORD(5);
125         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2);
126         MOVEWORD(3); MOVEWORD(4); MOVEWORD(5);
127     }
128     ADD_ROUND_KEY_6;
129     LASTWORD(0); LASTWORD(1); LASTWORD(2);
130     LASTWORD(3); LASTWORD(4); LASTWORD(5);
131     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2);
132     MOVEWORD(3); MOVEWORD(4); MOVEWORD(5);
133     ADD_ROUND_KEY_6;
134 }
135 static void aes_encrypt_nb_8(AESContext *ctx, word32 *block) {
136     int i;
137     static const int C1 = 1, C2 = 3, C3 = 4, Nb = 8;
138     word32 *keysched = ctx->keysched;
139     word32 newstate[8];
140     for (i = 0; i < ctx->Nr-1; i++) {
141         ADD_ROUND_KEY_8;
142         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2); MAKEWORD(3);
143         MAKEWORD(4); MAKEWORD(5); MAKEWORD(6); MAKEWORD(7);
144         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
145         MOVEWORD(4); MOVEWORD(5); MOVEWORD(6); MOVEWORD(7);
146     }
147     ADD_ROUND_KEY_8;
148     LASTWORD(0); LASTWORD(1); LASTWORD(2); LASTWORD(3);
149     LASTWORD(4); LASTWORD(5); LASTWORD(6); LASTWORD(7);
150     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
151     MOVEWORD(4); MOVEWORD(5); MOVEWORD(6); MOVEWORD(7);
152     ADD_ROUND_KEY_8;
153 }
154 #undef MAKEWORD
155 #undef LASTWORD
156
157 /*
158  * Macros for the decryption routine. There are three decryption
159  * cores, for Nb=4,6,8.
160  */
161 #define MAKEWORD(i) ( newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \
162                                      D1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \
163                                      D2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \
164                                      D3[block[(i+C3)%Nb] & 0xFF]) )
165 #define LASTWORD(i) (newstate[i] = (Sboxinv[(block[i] >> 24) & 0xFF] << 24) | \
166                            (Sboxinv[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \
167                            (Sboxinv[(block[(i+C2)%Nb] >>  8) & 0xFF] <<  8) | \
168                            (Sboxinv[(block[(i+C3)%Nb]      ) & 0xFF]      ) )
169
170 /*
171  * Core decrypt routines, expecting word32 inputs read big-endian
172  * from the byte-oriented input stream.
173  */
174 static void aes_decrypt_nb_4(AESContext *ctx, word32 *block) {
175     int i;
176     static const int C1 = 4-1, C2 = 4-2, C3 = 4-3, Nb = 4;
177     word32 *keysched = ctx->invkeysched;
178     word32 newstate[4];
179     for (i = 0; i < ctx->Nr-1; i++) {
180         ADD_ROUND_KEY_4;
181         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2); MAKEWORD(3);
182         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
183     }
184     ADD_ROUND_KEY_4;
185     LASTWORD(0); LASTWORD(1); LASTWORD(2); LASTWORD(3);
186     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
187     ADD_ROUND_KEY_4;
188 }
189 static void aes_decrypt_nb_6(AESContext *ctx, word32 *block) {
190     int i;
191     static const int C1 = 6-1, C2 = 6-2, C3 = 6-3, Nb = 6;
192     word32 *keysched = ctx->invkeysched;
193     word32 newstate[6];
194     for (i = 0; i < ctx->Nr-1; i++) {
195         ADD_ROUND_KEY_6;
196         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2);
197         MAKEWORD(3); MAKEWORD(4); MAKEWORD(5);
198         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2);
199         MOVEWORD(3); MOVEWORD(4); MOVEWORD(5);
200     }
201     ADD_ROUND_KEY_6;
202     LASTWORD(0); LASTWORD(1); LASTWORD(2);
203     LASTWORD(3); LASTWORD(4); LASTWORD(5);
204     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2);
205     MOVEWORD(3); MOVEWORD(4); MOVEWORD(5);
206     ADD_ROUND_KEY_6;
207 }
208 static void aes_decrypt_nb_8(AESContext *ctx, word32 *block) {
209     int i;
210     static const int C1 = 8-1, C2 = 8-3, C3 = 8-4, Nb = 8;
211     word32 *keysched = ctx->invkeysched;
212     word32 newstate[8];
213     for (i = 0; i < ctx->Nr-1; i++) {
214         ADD_ROUND_KEY_8;
215         MAKEWORD(0); MAKEWORD(1); MAKEWORD(2); MAKEWORD(3);
216         MAKEWORD(4); MAKEWORD(5); MAKEWORD(6); MAKEWORD(7);
217         MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
218         MOVEWORD(4); MOVEWORD(5); MOVEWORD(6); MOVEWORD(7);
219     }
220     ADD_ROUND_KEY_8;
221     LASTWORD(0); LASTWORD(1); LASTWORD(2); LASTWORD(3);
222     LASTWORD(4); LASTWORD(5); LASTWORD(6); LASTWORD(7);
223     MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3);
224     MOVEWORD(4); MOVEWORD(5); MOVEWORD(6); MOVEWORD(7);
225     ADD_ROUND_KEY_8;
226 }
227 #undef MAKEWORD
228 #undef LASTWORD
229
230 static const unsigned char Sbox[256] = {
231     0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
232     0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
233     0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
234     0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
235     0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
236     0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
237     0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
238     0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
239     0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
240     0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
241     0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
242     0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
243     0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
244     0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
245     0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
246     0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
247     0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
248     0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
249     0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
250     0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
251     0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
252     0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
253     0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
254     0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
255     0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
256     0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
257     0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
258     0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
259     0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
260     0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
261     0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
262     0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
263 };
264
265 static const unsigned char Sboxinv[256] = {
266     0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
267     0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
268     0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
269     0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
270     0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
271     0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
272     0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
273     0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
274     0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
275     0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
276     0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
277     0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
278     0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
279     0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
280     0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
281     0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
282     0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
283     0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
284     0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
285     0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
286     0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
287     0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
288     0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
289     0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
290     0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
291     0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
292     0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
293     0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
294     0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
295     0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
296     0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
297     0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
298 };
299
300 static const word32 E0[256] = {
301     0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d,
302     0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
303     0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
304     0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
305     0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87,
306     0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
307     0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea,
308     0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
309     0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
310     0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
311     0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108,
312     0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
313     0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e,
314     0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
315     0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
316     0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
317     0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e,
318     0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
319     0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
320     0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
321     0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
322     0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
323     0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b,
324     0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
325     0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16,
326     0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
327     0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
328     0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
329     0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a,
330     0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
331     0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163,
332     0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
333     0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
334     0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
335     0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47,
336     0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
337     0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f,
338     0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
339     0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
340     0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
341     0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
342     0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
343     0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6,
344     0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
345     0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
346     0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
347     0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25,
348     0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
349     0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72,
350     0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
351     0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
352     0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
353     0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa,
354     0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
355     0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0,
356     0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
357     0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
358     0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
359     0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920,
360     0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
361     0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17,
362     0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
363     0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
364     0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
365 };
366 static const word32 E1[256] = {
367     0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b,
368     0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
369     0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b,
370     0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
371     0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d,
372     0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
373     0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf,
374     0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
375     0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626,
376     0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
377     0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1,
378     0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
379     0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3,
380     0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
381     0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2,
382     0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
383     0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a,
384     0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
385     0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3,
386     0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
387     0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded,
388     0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
389     0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939,
390     0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
391     0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb,
392     0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
393     0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f,
394     0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
395     0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f,
396     0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
397     0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121,
398     0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
399     0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec,
400     0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
401     0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d,
402     0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
403     0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc,
404     0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
405     0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414,
406     0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
407     0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a,
408     0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
409     0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262,
410     0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
411     0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d,
412     0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
413     0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea,
414     0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
415     0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e,
416     0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
417     0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f,
418     0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
419     0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666,
420     0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
421     0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9,
422     0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
423     0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111,
424     0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
425     0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9,
426     0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
427     0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d,
428     0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
429     0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f,
430     0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
431 };
432 static const word32 E2[256] = {
433     0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b,
434     0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
435     0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b,
436     0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
437     0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d,
438     0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
439     0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af,
440     0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
441     0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26,
442     0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
443     0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1,
444     0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
445     0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3,
446     0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
447     0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2,
448     0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
449     0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a,
450     0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
451     0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3,
452     0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
453     0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed,
454     0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
455     0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239,
456     0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
457     0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb,
458     0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
459     0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f,
460     0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
461     0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f,
462     0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
463     0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221,
464     0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
465     0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec,
466     0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
467     0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d,
468     0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
469     0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc,
470     0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
471     0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814,
472     0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
473     0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a,
474     0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
475     0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462,
476     0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
477     0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d,
478     0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
479     0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea,
480     0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
481     0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e,
482     0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
483     0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f,
484     0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
485     0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66,
486     0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
487     0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9,
488     0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
489     0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211,
490     0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
491     0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9,
492     0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
493     0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d,
494     0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
495     0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f,
496     0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
497 };
498 static const word32 E3[256] = {
499     0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6,
500     0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
501     0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56,
502     0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
503     0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa,
504     0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
505     0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45,
506     0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
507     0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c,
508     0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
509     0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9,
510     0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
511     0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d,
512     0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
513     0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf,
514     0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
515     0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34,
516     0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
517     0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d,
518     0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
519     0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1,
520     0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
521     0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72,
522     0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
523     0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed,
524     0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
525     0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe,
526     0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
527     0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05,
528     0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
529     0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342,
530     0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
531     0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3,
532     0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
533     0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a,
534     0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
535     0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3,
536     0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
537     0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28,
538     0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
539     0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14,
540     0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
541     0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4,
542     0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
543     0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da,
544     0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
545     0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf,
546     0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
547     0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c,
548     0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
549     0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e,
550     0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
551     0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc,
552     0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
553     0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069,
554     0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
555     0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322,
556     0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
557     0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9,
558     0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
559     0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a,
560     0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
561     0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
562     0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
563 };
564 static const word32 D0[256] = {
565     0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96,
566     0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
567     0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
568     0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
569     0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1,
570     0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
571     0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da,
572     0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
573     0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
574     0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
575     0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45,
576     0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
577     0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7,
578     0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
579     0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
580     0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
581     0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1,
582     0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
583     0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
584     0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
585     0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
586     0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
587     0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77,
588     0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
589     0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000,
590     0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
591     0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
592     0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
593     0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e,
594     0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
595     0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d,
596     0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
597     0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
598     0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
599     0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163,
600     0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
601     0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d,
602     0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
603     0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
604     0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
605     0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
606     0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
607     0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662,
608     0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
609     0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
610     0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
611     0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8,
612     0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
613     0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6,
614     0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
615     0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
616     0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
617     0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df,
618     0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
619     0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e,
620     0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
621     0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
622     0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
623     0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf,
624     0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
625     0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f,
626     0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
627     0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
628     0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
629 };
630 static const word32 D1[256] = {
631     0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e,
632     0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
633     0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c,
634     0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
635     0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0,
636     0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
637     0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259,
638     0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
639     0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971,
640     0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
641     0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f,
642     0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
643     0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8,
644     0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
645     0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708,
646     0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
647     0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2,
648     0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
649     0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb,
650     0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
651     0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd,
652     0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
653     0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e,
654     0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
655     0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000,
656     0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
657     0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39,
658     0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
659     0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91,
660     0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
661     0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17,
662     0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
663     0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60,
664     0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
665     0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1,
666     0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
667     0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1,
668     0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
669     0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964,
670     0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
671     0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b,
672     0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
673     0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46,
674     0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
675     0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512,
676     0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
677     0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a,
678     0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
679     0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c,
680     0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
681     0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8,
682     0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
683     0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604,
684     0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
685     0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41,
686     0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
687     0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c,
688     0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
689     0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737,
690     0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
691     0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340,
692     0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
693     0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1,
694     0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
695 };
696 static const word32 D2[256] = {
697     0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27,
698     0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
699     0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502,
700     0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
701     0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe,
702     0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
703     0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552,
704     0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
705     0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9,
706     0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
707     0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253,
708     0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
709     0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b,
710     0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
711     0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337,
712     0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
713     0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69,
714     0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
715     0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6,
716     0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
717     0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6,
718     0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
719     0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9,
720     0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
721     0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000,
722     0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
723     0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d,
724     0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
725     0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b,
726     0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
727     0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b,
728     0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
729     0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f,
730     0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
731     0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4,
732     0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
733     0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729,
734     0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
735     0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9,
736     0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
737     0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4,
738     0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
739     0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e,
740     0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
741     0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25,
742     0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
743     0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f,
744     0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
745     0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0,
746     0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
747     0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7,
748     0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
749     0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496,
750     0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
751     0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b,
752     0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
753     0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13,
754     0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
755     0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7,
756     0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
757     0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3,
758     0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
759     0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456,
760     0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
761 };
762 static const word32 D3[256] = {
763     0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a,
764     0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
765     0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5,
766     0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
767     0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d,
768     0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
769     0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95,
770     0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
771     0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27,
772     0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
773     0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562,
774     0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
775     0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752,
776     0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
777     0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3,
778     0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
779     0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e,
780     0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
781     0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4,
782     0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
783     0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d,
784     0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
785     0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767,
786     0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
787     0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000,
788     0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
789     0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736,
790     0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
791     0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b,
792     0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
793     0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12,
794     0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
795     0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3,
796     0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
797     0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8,
798     0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
799     0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7,
800     0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
801     0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247,
802     0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
803     0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698,
804     0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
805     0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254,
806     0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
807     0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf,
808     0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
809     0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883,
810     0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
811     0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629,
812     0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
813     0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533,
814     0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
815     0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4,
816     0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
817     0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb,
818     0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
819     0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb,
820     0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
821     0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73,
822     0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
823     0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2,
824     0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
825     0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064,
826     0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
827 };
828
829 /*
830  * Set up an AESContext. `keylen' and `blocklen' are measured in
831  * bytes; each can be either 16 (128-bit), 24 (192-bit), or 32
832  * (256-bit).
833  */
834 void aes_setup(AESContext *ctx, int blocklen,
835                unsigned char *key, int keylen) {
836     int i, j, Nk, rconst;
837
838     assert(blocklen == 16 || blocklen == 24 || blocklen == 32);
839     assert(keylen == 16 || keylen == 24 || keylen == 32);
840
841     /*
842      * Basic parameters. Words per block, words in key, rounds.
843      */
844     Nk = keylen / 4;
845     ctx->Nb = blocklen / 4;
846     ctx->Nr = 6 + (ctx->Nb > Nk ? ctx->Nb : Nk);
847
848     /*
849      * Assign core-function pointers.
850      */
851     if (ctx->Nb == 8)
852         ctx->encrypt = aes_encrypt_nb_8, ctx->decrypt = aes_decrypt_nb_8;
853     else if (ctx->Nb == 6)
854         ctx->encrypt = aes_encrypt_nb_6, ctx->decrypt = aes_decrypt_nb_6;
855     else if (ctx->Nb == 4)
856         ctx->encrypt = aes_encrypt_nb_4, ctx->decrypt = aes_decrypt_nb_4;
857
858     /*
859      * Now do the key setup itself.
860      */
861     rconst = 1;
862     for (i = 0; i < (ctx->Nr+1) * ctx->Nb; i++) {
863         if (i < Nk)
864             ctx->keysched[i] = GET_32BIT_MSB_FIRST(key + 4*i);
865         else {
866             word32 temp = ctx->keysched[i-1];
867             if (i % Nk == 0) {
868                 int a, b, c, d;
869                 a = (temp >> 16) & 0xFF;
870                 b = (temp >>  8) & 0xFF;
871                 c = (temp >>  0) & 0xFF;
872                 d = (temp >> 24) & 0xFF;
873                 temp = Sbox[a] ^ rconst;
874                 temp = (temp << 8) | Sbox[b];
875                 temp = (temp << 8) | Sbox[c];
876                 temp = (temp << 8) | Sbox[d];
877                 rconst = mulby2(rconst);
878             } else if (i % Nk == 4 && Nk > 6) {
879                 int a, b, c, d;
880                 a = (temp >> 24) & 0xFF;
881                 b = (temp >> 16) & 0xFF;
882                 c = (temp >>  8) & 0xFF;
883                 d = (temp >>  0) & 0xFF;
884                 temp = Sbox[a];
885                 temp = (temp << 8) | Sbox[b];
886                 temp = (temp << 8) | Sbox[c];
887                 temp = (temp << 8) | Sbox[d];           
888             }
889             ctx->keysched[i] = ctx->keysched[i-Nk] ^ temp;
890         }
891     }
892
893     /*
894      * Now prepare the modified keys for the inverse cipher.
895      */
896     for (i = 0; i <= ctx->Nr; i++) {
897         for (j = 0; j < ctx->Nb; j++) {
898             word32 temp;
899             temp = ctx->keysched[(ctx->Nr - i) * ctx->Nb + j];
900             if (i != 0 && i != ctx->Nr) {
901                 /*
902                  * Perform the InvMixColumn operation on i. The D
903                  * tables give the result of InvMixColumn applied
904                  * to Sboxinv on individual bytes, so we should
905                  * compose Sbox with the D tables for this.
906                  */
907                 int a, b, c, d;
908                 a = (temp >> 24) & 0xFF;
909                 b = (temp >> 16) & 0xFF;
910                 c = (temp >>  8) & 0xFF;
911                 d = (temp >>  0) & 0xFF;
912                 temp = D0[Sbox[a]];
913                 temp ^= D1[Sbox[b]];
914                 temp ^= D2[Sbox[c]];
915                 temp ^= D3[Sbox[d]];
916             }
917             ctx->invkeysched[i * ctx->Nb + j] = temp;
918         }
919     }
920 }
921
922 static void aes_encrypt(AESContext *ctx, word32 *block) {
923     ctx->encrypt(ctx, block);
924 }
925
926 static void aes_decrypt(AESContext *ctx, word32 *block) {
927     ctx->decrypt(ctx, block);
928 }
929
930 static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext *ctx) {
931     word32 iv[4];
932     int i;
933
934     assert((len & 15) == 0);
935
936     memcpy(iv, ctx->iv, sizeof(iv));
937
938     while (len > 0) {
939         for (i = 0; i < 4; i++)
940             iv[i] ^= GET_32BIT_MSB_FIRST(blk+4*i);
941         aes_encrypt(ctx, iv);
942         for (i = 0; i < 4; i++)
943             PUT_32BIT_MSB_FIRST(blk+4*i, iv[i]);
944         blk += 16;
945         len -= 16;
946     }
947
948     memcpy(ctx->iv, iv, sizeof(iv));
949 }
950
951 static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext *ctx) {
952     word32 iv[4], x[4], ct[4];
953     int i;
954
955     assert((len & 15) == 0);
956
957     memcpy(iv, ctx->iv, sizeof(iv));
958
959     while (len > 0) {
960         for (i = 0; i < 4; i++)
961             x[i] = ct[i] = GET_32BIT_MSB_FIRST(blk+4*i);
962         aes_decrypt(ctx, x);
963         for (i = 0; i < 4; i++) {
964             PUT_32BIT_MSB_FIRST(blk+4*i, iv[i] ^ x[i]);
965             iv[i] = ct[i];
966         }
967         blk += 16;
968         len -= 16;
969     }
970
971     memcpy(ctx->iv, iv, sizeof(iv));
972 }
973
974 static AESContext csctx, scctx;
975
976 static void aes128_cskey(unsigned char *key) {
977     aes_setup(&csctx, 16, key, 16);
978     logevent("Initialised AES-128 client->server encryption");
979 }
980
981 static void aes128_sckey(unsigned char *key) {
982     aes_setup(&scctx, 16, key, 16);
983     logevent("Initialised AES-128 server->client encryption");
984 }
985
986 static void aes192_cskey(unsigned char *key) {
987     aes_setup(&csctx, 16, key, 24);
988     logevent("Initialised AES-192 client->server encryption");
989 }
990
991 static void aes192_sckey(unsigned char *key) {
992     aes_setup(&scctx, 16, key, 24);
993     logevent("Initialised AES-192 server->client encryption");
994 }
995
996 static void aes256_cskey(unsigned char *key) {
997     aes_setup(&csctx, 16, key, 32);
998     logevent("Initialised AES-256 client->server encryption");
999 }
1000
1001 static void aes256_sckey(unsigned char *key) {
1002     aes_setup(&scctx, 16, key, 32);
1003     logevent("Initialised AES-256 server->client encryption");
1004 }
1005
1006 static void aes_csiv(unsigned char *iv) {
1007     int i;
1008     for (i = 0; i < 4; i++)
1009         csctx.iv[i] = GET_32BIT_MSB_FIRST(iv+4*i);
1010 }
1011
1012 static void aes_sciv(unsigned char *iv) {
1013     int i;
1014     for (i = 0; i < 4; i++)
1015         scctx.iv[i] = GET_32BIT_MSB_FIRST(iv+4*i);
1016 }
1017
1018 static void aes_ssh2_encrypt_blk(unsigned char *blk, int len) {
1019     aes_encrypt_cbc(blk, len, &csctx);
1020 }
1021
1022 static void aes_ssh2_decrypt_blk(unsigned char *blk, int len) {
1023     aes_decrypt_cbc(blk, len, &scctx);
1024 }
1025
1026 void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) {
1027     AESContext ctx;
1028     aes_setup(&ctx, 16, key, 32);
1029     memset(ctx.iv, 0, sizeof(ctx.iv));
1030     aes_encrypt_cbc(blk, len, &ctx);
1031 }
1032
1033 void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) {
1034     AESContext ctx;
1035     aes_setup(&ctx, 16, key, 32);
1036     memset(ctx.iv, 0, sizeof(ctx.iv));
1037     aes_decrypt_cbc(blk, len, &ctx);
1038 }
1039
1040 static const struct ssh2_cipher ssh_aes128 = {
1041     aes_csiv, aes128_cskey,
1042     aes_sciv, aes128_sckey,
1043     aes_ssh2_encrypt_blk,
1044     aes_ssh2_decrypt_blk,
1045     "aes128-cbc",
1046     16, 128
1047 };
1048
1049 static const struct ssh2_cipher ssh_aes192 = {
1050     aes_csiv, aes192_cskey,
1051     aes_sciv, aes192_sckey,
1052     aes_ssh2_encrypt_blk,
1053     aes_ssh2_decrypt_blk,
1054     "aes192-cbc",
1055     16, 192
1056 };
1057
1058 static const struct ssh2_cipher ssh_aes256 = {
1059     aes_csiv, aes256_cskey,
1060     aes_sciv, aes256_sckey,
1061     aes_ssh2_encrypt_blk,
1062     aes_ssh2_decrypt_blk,
1063     "aes256-cbc",
1064     16, 256
1065 };
1066
1067 static const struct ssh2_cipher ssh_rijndael128 = {
1068     aes_csiv, aes128_cskey,
1069     aes_sciv, aes128_sckey,
1070     aes_ssh2_encrypt_blk,
1071     aes_ssh2_decrypt_blk,
1072     "rijndael128-cbc",
1073     16, 128
1074 };
1075
1076 static const struct ssh2_cipher ssh_rijndael192 = {
1077     aes_csiv, aes192_cskey,
1078     aes_sciv, aes192_sckey,
1079     aes_ssh2_encrypt_blk,
1080     aes_ssh2_decrypt_blk,
1081     "rijndael192-cbc",
1082     16, 192
1083 };
1084
1085 static const struct ssh2_cipher ssh_rijndael256 = {
1086     aes_csiv, aes256_cskey,
1087     aes_sciv, aes256_sckey,
1088     aes_ssh2_encrypt_blk,
1089     aes_ssh2_decrypt_blk,
1090     "rijndael256-cbc",
1091     16, 256
1092 };
1093
1094 static const struct ssh2_cipher ssh_rijndael_lysator = {
1095     aes_csiv, aes256_cskey,
1096     aes_sciv, aes256_sckey,
1097     aes_ssh2_encrypt_blk,
1098     aes_ssh2_decrypt_blk,
1099     "rijndael-cbc@lysator.liu.se",
1100     16, 256
1101 };
1102
1103 static const struct ssh2_cipher *const aes_list[] = {
1104     &ssh_aes256,
1105     &ssh_rijndael256,
1106     &ssh_rijndael_lysator,
1107     &ssh_aes192,
1108     &ssh_rijndael192,
1109     &ssh_aes128,
1110     &ssh_rijndael128,
1111 };
1112
1113 const struct ssh2_ciphers ssh2_aes = {
1114     sizeof(aes_list) / sizeof(*aes_list),
1115     aes_list
1116 };