Merge remote-tracking branch 'mjb/master'
[fw/altos] / src / aes / ao_aes.c
1 /* Copyright (C) 2000-2009 Peter Selinger.
2    This file is part of ccrypt. It is free software and it is covered
3    by the GNU general public license. See the file COPYING for details. */
4
5 /* rijndael.c - optimized version of the Rijndeal cipher */
6 /* $Id: rijndael.c 258 2009-08-26 17:46:10Z selinger $ */
7
8 /* derived from original source: rijndael-alg-ref.c   v2.0   August '99
9  * Reference ANSI C code for NIST competition
10  * authors: Paulo Barreto
11  *          Vincent Rijmen
12  */
13
14 #include <ao.h>
15 #include <ao_aes.h>
16 #include "ao_aes_int.h"
17
18 static const int xshifts[3][2][4] = {
19   {{0, 1, 2, 3},
20    {0, 3, 2, 1}},
21
22   {{0, 1, 2, 3},
23    {0, 5, 4, 3}},
24
25   {{0, 1, 3, 4},
26    {0, 7, 5, 4}},
27 };
28
29 /* Exor corresponding text input and round key input bytes */
30 /* the result is written to res, which can be the same as a */
31 static inline void xKeyAddition(word32 res[MAXBC], word32 a[MAXBC],
32                          word32 rk[MAXBC], int BC)
33 {
34   int j;
35
36   for (j = 0; j < BC; j++) {
37     res[j] = a[j] ^ rk[j];
38   }
39 }
40
41 #if 0                           /* code included for reference */
42
43 /* shift rows a, return result in res. This avoids having to copy a
44    tmp array back to a. res must not be a. */
45 static inline void xShiftRow(word32 res[MAXBC], word32 a[MAXBC], int shift[4],
46                       int BC)
47 {
48   word8 (*a8)[4] = (word8 (*)[4]) a;
49   word8 (*res8)[4] = (word8 (*)[4]) res;
50
51   /* Row 0 remains unchanged
52    * The other three rows are shifted a variable amount
53    */
54   int i, j;
55   int s;
56
57   for (j = 0; j < BC; j++) {
58     res8[j][0] = a8[j][0];
59   }
60   for (i = 1; i < 4; i++) {
61     s = shift[i];
62     for (j = 0; j < BC; j++) {
63       res8[j][i] = a8[(j + s) % BC][i];
64     }
65   }
66 }
67
68 static inline void xSubstitution(word32 a[MAXBC], word8 box[256], int BC)
69 {
70   word8 (*a8)[4] = (word8 (*)[4]) a;
71
72   /* Replace every byte of the input by the byte at that place
73    * in the nonlinear S-box
74    */
75   int i, j;
76
77   for (i = 0; i < 4; i++) {
78     for (j = 0; j < BC; j++) {
79       a8[j][i] = box[a[j][i]];
80     }
81   }
82 }
83
84 #endif                          /* code included for reference */
85
86 /* profiling shows that the ccrypt program spends about 50% of its
87    time in the function xShiftSubst. Splitting the inner "for"
88    statement into two parts - versus using the expensive "%" modulo
89    operation, makes this function about 44% faster, thereby making the
90    entire program about 28% faster. With -O3 optimization, the time
91    savings are even more dramatic - ccrypt runs between 55% and 65%
92    faster on most platforms. */
93
94 /* do ShiftRow and Substitution together. res must not be a. */
95 static inline void xShiftSubst(word32 res[MAXBC], word32 a[MAXBC],
96                         int shift[4], int BC, const word8 box[256])
97 {
98   int i, j;
99   int s;
100   word8 (*a8)[4] = (word8 (*)[4]) a;
101   word8 (*res8)[4] = (word8 (*)[4]) res;
102
103   for (j = 0; j < BC; j++) {
104     res8[j][0] = box[a8[j][0]];
105   }
106   for (i = 1; i < 4; i++) {
107     s = shift[i];
108     for (j = 0; j < BC - s; j++) {
109       res8[j][i] = box[a8[(j + s)][i]];
110     }
111     for (j = BC - s; j < BC; j++) {
112       res8[j][i] = box[a8[(j + s) - BC][i]];
113     }
114   }
115 }
116
117 #if 0                           /* code included for reference */
118
119 /* Mix the four bytes of every column in a linear way */
120 /* the result is written to res, which may equal a */
121 static inline void xMixColumn(word32 res[MAXBC], word32 a[MAXBC], int BC)
122 {
123   int j;
124   word32 b;
125   word8 (*a8)[4] = (word8 (*)[4]) a;
126
127   for (j = 0; j < BC; j++) {
128     b = M0[0][a8[j][0]].w32;
129     b ^= M0[1][a8[j][1]].w32;
130     b ^= M0[2][a8[j][2]].w32;
131     b ^= M0[3][a8[j][3]].w32;
132     res[j] = b;
133   }
134 }
135
136 #endif                          /* code included for reference */
137
138 /* do MixColumn and KeyAddition together */
139 static inline void xMixAdd(word32 res[MAXBC], word32 a[MAXBC],
140                     word32 rk[MAXBC], int BC)
141 {
142   int j;
143   word32 b;
144   word8 (*a8)[4] = (word8 (*)[4]) a;
145
146   for (j = 0; j < BC; j++) {
147     b = M0[0][a8[j][0]].w32;
148     b ^= M0[1][a8[j][1]].w32;
149     b ^= M0[2][a8[j][2]].w32;
150     b ^= M0[3][a8[j][3]].w32;
151     b ^= rk[j];
152     res[j] = b;
153   }
154 }
155
156 /* Mix the four bytes of every column in a linear way
157  * This is the opposite operation of xMixColumn */
158 /* the result is written to res, which may equal a */
159 static inline void xInvMixColumn(word32 res[MAXBC], word32 a[MAXBC], int BC)
160 {
161   int j;
162   word32 b;
163   word8 (*a8)[4] = (word8 (*)[4]) a;
164
165   for (j = 0; j < BC; j++) {
166     b = M1[0][a8[j][0]].w32;
167     b ^= M1[1][a8[j][1]].w32;
168     b ^= M1[2][a8[j][2]].w32;
169     b ^= M1[3][a8[j][3]].w32;
170     res[j] = b;
171   }
172 }
173
174 #if 0                           /* code included for reference */
175
176 /* do KeyAddition and InvMixColumn together */
177 static inline void xAddInvMix(word32 res[MAXBC], word32 a[MAXBC],
178                        word32 rk[MAXBC], int BC)
179 {
180   int j;
181   word32 b;
182   word8 (*a8)[4] = (word8 (*)[4]) a;
183
184   for (j = 0; j < BC; j++) {
185     a[j] = a[j] ^ rk[j];
186     b = M1[0][a8[j][0]].w32;
187     b ^= M1[1][a8[j][1]].w32;
188     b ^= M1[2][a8[j][2]].w32;
189     b ^= M1[3][a8[j][3]].w32;
190     res[j] = b;
191   }
192 }
193
194 #endif                          /* code included for reference */
195
196 int xrijndaelKeySched(word32 key[], int keyBits, int blockBits,
197                       roundkey *rkk)
198 {
199   /* Calculate the necessary round keys
200    * The number of calculations depends on keyBits and blockBits */
201   int KC, BC, ROUNDS;
202   int i, j, t, rconpointer = 0;
203   word8 (*k8)[4] = (word8 (*)[4]) key;
204
205   switch (keyBits) {
206   case 128:
207     KC = 4;
208     break;
209   case 192:
210     KC = 6;
211     break;
212   case 256:
213     KC = 8;
214     break;
215   default:
216     return -1;
217   }
218
219   switch (blockBits) {
220   case 128:
221     BC = 4;
222     break;
223   case 192:
224     BC = 6;
225     break;
226   case 256:
227     BC = 8;
228     break;
229   default:
230     return -2;
231   }
232
233   ROUNDS = KC > BC ? KC + 6 : BC + 6;
234
235   t = 0;
236   /* copy values into round key array */
237   for (j = 0; (j < KC) && (t < (ROUNDS + 1) * BC); j++, t++)
238     rkk->rk[t] = key[j];
239
240   while (t < (ROUNDS + 1) * BC) {  /* while not enough round key material */
241     /* calculate new values */
242     for (i = 0; i < 4; i++) {
243       k8[0][i] ^= xS[k8[KC - 1][(i + 1) % 4]];
244     }
245     k8[0][0] ^= xrcon[rconpointer++];
246
247     if (KC != 8) {
248       for (j = 1; j < KC; j++) {
249         key[j] ^= key[j - 1];
250       }
251     } else {
252       for (j = 1; j < 4; j++) {
253         key[j] ^= key[j - 1];
254       }
255       for (i = 0; i < 4; i++) {
256         k8[4][i] ^= xS[k8[3][i]];
257       }
258       for (j = 5; j < 8; j++) {
259         key[j] ^= key[j - 1];
260       }
261     }
262     /* copy values into round key array */
263     for (j = 0; (j < KC) && (t < (ROUNDS + 1) * BC); j++, t++) {
264       rkk->rk[t] = key[j];
265     }
266   }
267
268   /* make roundkey structure */
269   rkk->BC = BC;
270   rkk->KC = KC;
271   rkk->ROUNDS = ROUNDS;
272   for (i = 0; i < 2; i++) {
273     for (j = 0; j < 4; j++) {
274       rkk->shift[i][j] = xshifts[(BC - 4) >> 1][i][j];
275     }
276   }
277
278   return 0;
279 }
280
281 /* Encryption of one block. */
282
283 void xrijndaelEncrypt(word32 block[], roundkey *rkk)
284 {
285   word32 block2[MAXBC];         /* hold intermediate result */
286   int r;
287
288   int *shift = rkk->shift[0];
289   int BC = rkk->BC;
290   int ROUNDS = rkk->ROUNDS;
291   word32 *rp = rkk->rk;
292
293   /* begin with a key addition */
294   xKeyAddition(block, block, rp, BC);
295   rp += BC;
296
297   /* ROUNDS-1 ordinary rounds */
298   for (r = 1; r < ROUNDS; r++) {
299     xShiftSubst(block2, block, shift, BC, xS);
300     xMixAdd(block, block2, rp, BC);
301     rp += BC;
302   }
303
304   /* Last round is special: there is no xMixColumn */
305   xShiftSubst(block2, block, shift, BC, xS);
306   xKeyAddition(block, block2, rp, BC);
307 }
308
309 void xrijndaelDecrypt(word32 block[], roundkey *rkk)
310 {
311   word32 block2[MAXBC];         /* hold intermediate result */
312   int r;
313
314   int *shift = rkk->shift[1];
315   int BC = rkk->BC;
316   int ROUNDS = rkk->ROUNDS;
317   word32 *rp = rkk->rk + ROUNDS * BC;
318
319   /* To decrypt: apply the inverse operations of the encrypt routine,
320    *             in opposite order
321    * 
322    * (xKeyAddition is an involution: it's equal to its inverse)
323    * (the inverse of xSubstitution with table S is xSubstitution with the 
324    * inverse table of S)
325    * (the inverse of xShiftRow is xShiftRow over a suitable distance)
326    */
327
328   /* First the special round:
329    *   without xInvMixColumn
330    *   with extra xKeyAddition
331    */
332   xKeyAddition(block2, block, rp, BC);
333   xShiftSubst(block, block2, shift, BC, xSi);
334   rp -= BC;
335
336   /* ROUNDS-1 ordinary rounds
337    */
338   for (r = ROUNDS - 1; r > 0; r--) {
339     xKeyAddition(block, block, rp, BC);
340     xInvMixColumn(block2, block, BC);
341     xShiftSubst(block, block2, shift, BC, xSi);
342     rp -= BC;
343   }
344
345   /* End with the extra key addition
346    */
347
348   xKeyAddition(block, block, rp, BC);
349 }
350
351 uint8_t ao_aes_mutex;
352 static roundkey rkk;
353
354 static uint8_t iv[16];
355
356 void
357 ao_aes_set_mode(enum ao_aes_mode mode)
358 {
359         /* we only do CBC_MAC anyways... */
360 }
361
362 void
363 ao_aes_set_key(__xdata uint8_t *in)
364 {
365         xrijndaelKeySched((word32 *) in, 128, 128, &rkk);
366 }
367
368 void
369 ao_aes_zero_iv(void)
370 {
371         memset(iv, '\0', sizeof (iv));
372 }
373
374 void
375 ao_aes_run(__xdata uint8_t *in,
376            __xdata uint8_t *out)
377 {
378         uint8_t i;
379
380         for (i = 0; i < 16; i++)
381                 iv[i] ^= in[i];
382         xrijndaelEncrypt((word32 *) iv, &rkk);
383         if (out)
384                 memcpy(out, iv, 16);
385 }
386
387 void
388 ao_aes_init(void)
389 {
390 }