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