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