1 /* rijndael-alg-ref.c v2.0 August '99
2 * Reference ANSI C code
3 * authors: Paulo Barreto
4 * Vincent Rijmen
5 *
6 * This code is placed in the public domain.
7 *
8 * $Id: rijndael-alg-ref.c,v 1.1 2002-01-21 21:37:36 f Exp $
9 *
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include "rijndael-alg-ref.h"
16
17 #define SC ((BC - 4) >> 1)
18
19 #include "boxes-ref.dat"
20
21 static word8 shifts[3][4][2] = {
22 { { 0, 0 },
23 { 1, 3 },
24 { 2, 2 },
25 { 3, 1 } },
26
27 { { 0, 0 },
28 { 1, 5 },
29 { 2, 4 },
30 { 3, 3 } },
31
32 { { 0, 0 },
33 { 1, 7 },
34 { 3, 5 },
35 { 4, 4 } }
36 };
37
38 word8 mul(word8, word8);
39 void KeyAddition(word8 [][], word8 [][], word8);
40 void Substitution(word8 [][], word8 box[], word8);
41 void ShiftRow(word8 [][], word8, word8);
42 void MixColumn(word8 [][], word8);
43 void InvMixColumn(word8 [][], word8);
44
mul(word8 a,word8 b)45 word8 mul(word8 a, word8 b) {
46 /* multiply two elements of GF(2^m)
47 * needed for MixColumn and InvMixColumn
48 */
49 if (a && b) return Alogtable[(Logtable[a] + Logtable[b])%255];
50 else return 0;
51 }
52
KeyAddition(word8 a[4][MAXBC],word8 rk[4][MAXBC],word8 BC)53 void KeyAddition(word8 a[4][MAXBC], word8 rk[4][MAXBC], word8 BC) {
54 /* Exor corresponding text input and round key input bytes
55 */
56 int i, j;
57
58 for(i = 0; i < 4; i++)
59 for(j = 0; j < BC; j++) a[i][j] ^= rk[i][j];
60 }
61
ShiftRow(word8 a[4][MAXBC],word8 d,word8 BC)62 void ShiftRow(word8 a[4][MAXBC], word8 d, word8 BC) {
63 /* Row 0 remains unchanged
64 * The other three rows are shifted a variable amount
65 */
66 word8 tmp[MAXBC];
67 int i, j;
68
69 for(i = 1; i < 4; i++) {
70 for(j = 0; j < BC; j++) tmp[j] = a[i][(j + shifts[SC][i][d]) % BC];
71 for(j = 0; j < BC; j++) a[i][j] = tmp[j];
72 }
73 }
74
Substitution(word8 a[4][MAXBC],word8 box[256],word8 BC)75 void Substitution(word8 a[4][MAXBC], word8 box[256], word8 BC) {
76 /* Replace every byte of the input by the byte at that place
77 * in the nonlinear S-box
78 */
79 int i, j;
80
81 for(i = 0; i < 4; i++)
82 for(j = 0; j < BC; j++) a[i][j] = box[a[i][j]] ;
83 }
84
MixColumn(word8 a[4][MAXBC],word8 BC)85 void MixColumn(word8 a[4][MAXBC], word8 BC) {
86 /* Mix the four bytes of every column in a linear way
87 */
88 word8 b[4][MAXBC];
89 int i, j;
90
91 for(j = 0; j < BC; j++)
92 for(i = 0; i < 4; i++)
93 b[i][j] = mul(2,a[i][j])
94 ^ mul(3,a[(i + 1) % 4][j])
95 ^ a[(i + 2) % 4][j]
96 ^ a[(i + 3) % 4][j];
97 for(i = 0; i < 4; i++)
98 for(j = 0; j < BC; j++) a[i][j] = b[i][j];
99 }
100
InvMixColumn(word8 a[4][MAXBC],word8 BC)101 void InvMixColumn(word8 a[4][MAXBC], word8 BC) {
102 /* Mix the four bytes of every column in a linear way
103 * This is the opposite operation of Mixcolumn
104 */
105 word8 b[4][MAXBC];
106 int i, j;
107
108 for(j = 0; j < BC; j++)
109 for(i = 0; i < 4; i++)
110 b[i][j] = mul(0xe,a[i][j])
111 ^ mul(0xb,a[(i + 1) % 4][j])
112 ^ mul(0xd,a[(i + 2) % 4][j])
113 ^ mul(0x9,a[(i + 3) % 4][j]);
114 for(i = 0; i < 4; i++)
115 for(j = 0; j < BC; j++) a[i][j] = b[i][j];
116 }
117
rijndaelKeySched(word8 k[4][MAXKC],int keyBits,int blockBits,word8 W[MAXROUNDS+1][4][MAXBC])118 int rijndaelKeySched (word8 k[4][MAXKC], int keyBits, int blockBits, word8 W[MAXROUNDS+1][4][MAXBC]) {
119 /* Calculate the necessary round keys
120 * The number of calculations depends on keyBits and blockBits
121 */
122 int KC, BC, ROUNDS;
123 int i, j, t, rconpointer = 0;
124 word8 tk[4][MAXKC];
125
126 switch (keyBits) {
127 case 128: KC = 4; break;
128 case 192: KC = 6; break;
129 case 256: KC = 8; break;
130 default : return (-1);
131 }
132
133 switch (blockBits) {
134 case 128: BC = 4; break;
135 case 192: BC = 6; break;
136 case 256: BC = 8; break;
137 default : return (-2);
138 }
139
140 switch (keyBits >= blockBits ? keyBits : blockBits) {
141 case 128: ROUNDS = 10; break;
142 case 192: ROUNDS = 12; break;
143 case 256: ROUNDS = 14; break;
144 default : return (-3); /* this cannot happen */
145 }
146
147
148 for(j = 0; j < KC; j++)
149 for(i = 0; i < 4; i++)
150 tk[i][j] = k[i][j];
151 t = 0;
152 /* copy values into round key array */
153 for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
154 for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
155
156 while (t < (ROUNDS+1)*BC) { /* while not enough round key material calculated */
157 /* calculate new values */
158 for(i = 0; i < 4; i++)
159 tk[i][0] ^= S[tk[(i+1)%4][KC-1]];
160 tk[0][0] ^= rcon[rconpointer++];
161
162 if (KC != 8)
163 for(j = 1; j < KC; j++)
164 for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
165 else {
166 for(j = 1; j < KC/2; j++)
167 for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
168 for(i = 0; i < 4; i++) tk[i][KC/2] ^= S[tk[i][KC/2 - 1]];
169 for(j = KC/2 + 1; j < KC; j++)
170 for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
171 }
172 /* copy values into round key array */
173 for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
174 for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
175 }
176
177 return 0;
178 }
179
rijndaelEncrypt(word8 a[4][MAXBC],int keyBits,int blockBits,word8 rk[MAXROUNDS+1][4][MAXBC])180 int rijndaelEncrypt (word8 a[4][MAXBC], int keyBits, int blockBits, word8 rk[MAXROUNDS+1][4][MAXBC])
181 {
182 /* Encryption of one block.
183 */
184 int r, BC, ROUNDS;
185
186 switch (blockBits) {
187 case 128: BC = 4; break;
188 case 192: BC = 6; break;
189 case 256: BC = 8; break;
190 default : return (-2);
191 }
192
193 switch (keyBits >= blockBits ? keyBits : blockBits) {
194 case 128: ROUNDS = 10; break;
195 case 192: ROUNDS = 12; break;
196 case 256: ROUNDS = 14; break;
197 default : return (-3); /* this cannot happen */
198 }
199
200 /* begin with a key addition
201 */
202 KeyAddition(a,rk[0],BC);
203
204 /* ROUNDS-1 ordinary rounds
205 */
206 for(r = 1; r < ROUNDS; r++) {
207 Substitution(a,S,BC);
208 ShiftRow(a,0,BC);
209 MixColumn(a,BC);
210 KeyAddition(a,rk[r],BC);
211 }
212
213 /* Last round is special: there is no MixColumn
214 */
215 Substitution(a,S,BC);
216 ShiftRow(a,0,BC);
217 KeyAddition(a,rk[ROUNDS],BC);
218
219 return 0;
220 }
221
222
223
rijndaelEncryptRound(word8 a[4][MAXBC],int keyBits,int blockBits,word8 rk[MAXROUNDS+1][4][MAXBC],int rounds)224 int rijndaelEncryptRound (word8 a[4][MAXBC], int keyBits, int blockBits,
225 word8 rk[MAXROUNDS+1][4][MAXBC], int rounds)
226 /* Encrypt only a certain number of rounds.
227 * Only used in the Intermediate Value Known Answer Test.
228 */
229 {
230 int r, BC, ROUNDS;
231
232 switch (blockBits) {
233 case 128: BC = 4; break;
234 case 192: BC = 6; break;
235 case 256: BC = 8; break;
236 default : return (-2);
237 }
238
239 switch (keyBits >= blockBits ? keyBits : blockBits) {
240 case 128: ROUNDS = 10; break;
241 case 192: ROUNDS = 12; break;
242 case 256: ROUNDS = 14; break;
243 default : return (-3); /* this cannot happen */
244 }
245
246 /* make number of rounds sane */
247 if (rounds > ROUNDS) rounds = ROUNDS;
248
249 /* begin with a key addition
250 */
251 KeyAddition(a,rk[0],BC);
252
253 /* at most ROUNDS-1 ordinary rounds
254 */
255 for(r = 1; (r <= rounds) && (r < ROUNDS); r++) {
256 Substitution(a,S,BC);
257 ShiftRow(a,0,BC);
258 MixColumn(a,BC);
259 KeyAddition(a,rk[r],BC);
260 }
261
262 /* if necessary, do the last, special, round:
263 */
264 if (rounds == ROUNDS) {
265 Substitution(a,S,BC);
266 ShiftRow(a,0,BC);
267 KeyAddition(a,rk[ROUNDS],BC);
268 }
269
270 return 0;
271 }
272
273
rijndaelDecrypt(word8 a[4][MAXBC],int keyBits,int blockBits,word8 rk[MAXROUNDS+1][4][MAXBC])274 int rijndaelDecrypt (word8 a[4][MAXBC], int keyBits, int blockBits, word8 rk[MAXROUNDS+1][4][MAXBC])
275 {
276 int r, BC, ROUNDS;
277
278 switch (blockBits) {
279 case 128: BC = 4; break;
280 case 192: BC = 6; break;
281 case 256: BC = 8; break;
282 default : return (-2);
283 }
284
285 switch (keyBits >= blockBits ? keyBits : blockBits) {
286 case 128: ROUNDS = 10; break;
287 case 192: ROUNDS = 12; break;
288 case 256: ROUNDS = 14; break;
289 default : return (-3); /* this cannot happen */
290 }
291
292 /* To decrypt: apply the inverse operations of the encrypt routine,
293 * in opposite order
294 *
295 * (KeyAddition is an involution: it 's equal to its inverse)
296 * (the inverse of Substitution with table S is Substitution with the inverse table of S)
297 * (the inverse of Shiftrow is Shiftrow over a suitable distance)
298 */
299
300 /* First the special round:
301 * without InvMixColumn
302 * with extra KeyAddition
303 */
304 KeyAddition(a,rk[ROUNDS],BC);
305 Substitution(a,Si,BC);
306 ShiftRow(a,1,BC);
307
308 /* ROUNDS-1 ordinary rounds
309 */
310 for(r = ROUNDS-1; r > 0; r--) {
311 KeyAddition(a,rk[r],BC);
312 InvMixColumn(a,BC);
313 Substitution(a,Si,BC);
314 ShiftRow(a,1,BC);
315 }
316
317 /* End with the extra key addition
318 */
319
320 KeyAddition(a,rk[0],BC);
321
322 return 0;
323 }
324
325
rijndaelDecryptRound(word8 a[4][MAXBC],int keyBits,int blockBits,word8 rk[MAXROUNDS+1][4][MAXBC],int rounds)326 int rijndaelDecryptRound (word8 a[4][MAXBC], int keyBits, int blockBits,
327 word8 rk[MAXROUNDS+1][4][MAXBC], int rounds)
328 /* Decrypt only a certain number of rounds.
329 * Only used in the Intermediate Value Known Answer Test.
330 * Operations rearranged such that the intermediate values
331 * of decryption correspond with the intermediate values
332 * of encryption.
333 */
334 {
335 int r, BC, ROUNDS;
336
337 switch (blockBits) {
338 case 128: BC = 4; break;
339 case 192: BC = 6; break;
340 case 256: BC = 8; break;
341 default : return (-2);
342 }
343
344 switch (keyBits >= blockBits ? keyBits : blockBits) {
345 case 128: ROUNDS = 10; break;
346 case 192: ROUNDS = 12; break;
347 case 256: ROUNDS = 14; break;
348 default : return (-3); /* this cannot happen */
349 }
350
351
352 /* make number of rounds sane */
353 if (rounds > ROUNDS) rounds = ROUNDS;
354
355 /* First the special round:
356 * without InvMixColumn
357 * with extra KeyAddition
358 */
359 KeyAddition(a,rk[ROUNDS],BC);
360 Substitution(a,Si,BC);
361 ShiftRow(a,1,BC);
362
363 /* ROUNDS-1 ordinary rounds
364 */
365 for(r = ROUNDS-1; r > rounds; r--) {
366 KeyAddition(a,rk[r],BC);
367 InvMixColumn(a,BC);
368 Substitution(a,Si,BC);
369 ShiftRow(a,1,BC);
370 }
371
372 if (rounds == 0) {
373 /* End with the extra key addition
374 */
375 KeyAddition(a,rk[0],BC);
376 }
377
378 return 0;
379 }
380
381
382
383