source: trunk/minix/drivers/random/aes/rijndael_api.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 15.6 KB
RevLine 
[9]1/* rijndael-api.c - Rijndael encryption programming interface.
2 * Author: Kees J. Bot
3 * 3 Nov 2000
4 * Heavily based on the original API code by Antoon Bosselaers,
5 * Vincent Rijmen, and Paulo Barreto, but with a different interface.
6 *
7 * Read this code top to bottom, not all comments are repeated.
8 */
9
10#include <stdlib.h>
11#include <string.h>
12#include <sys/types.h>
13
14#include "rijndael-alg.h"
15#include "rijndael-api.h"
16
17/* Map a byte (?) address to a word address or vv. */
18#define W(a) ((word32 *) (a))
19#define B(a) ((word8 *) (a))
20
21#if STRICT_ALIGN
22/* This machine checks alignment religiously. (The code is not proper with
23 * respect to alignment. We need a compiler that doesn't muck about with byte
24 * arrays that follow words in structs, and that places automatic variables
25 * at word boundaries if not odd-sized. Most compilers are this nice.)
26 */
27
28#define aligned(a) (((unsigned) (a) & 3) == 0)
29#define aligned2(a1, a2) aligned((unsigned) (a1) | (unsigned) (a2))
30
31static void blockcpy(void *dst, const void *src)
32{
33 int i= 0;
34
35 do {
36 B(dst)[i+0] = B(src)[i+0];
37 B(dst)[i+1] = B(src)[i+1];
38 B(dst)[i+2] = B(src)[i+2];
39 B(dst)[i+3] = B(src)[i+3];
40 } while ((i += 4) < 16);
41}
42
43#else /* !STRICT_ALIGN */
44/* This machine doesn't mind misaligned accesses much. */
45
46#define aligned(a) ((void) (a), 1)
47#define aligned2(a1, a2) ((void) (a1), (void) (a2), 1)
48
49#if __GNUC__
50__inline
51#endif
52static void blockcpy(void *dst, const void *src)
53{
54 W(dst)[0] = W(src)[0];
55 W(dst)[1] = W(src)[1];
56 W(dst)[2] = W(src)[2];
57 W(dst)[3] = W(src)[3];
58}
59
60#endif /* !STRICT_ALIGN */
61
62#define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
63
64int rijndael_makekey(rd_keyinstance *key,
65 size_t keylen, const void *keymaterial)
66{
67 word8 k[MAXKC][4];
68
69 /* Initialize key schedule: */
70 if (keylen == RD_KEY_HEX) {
71 const word8 *kp;
72 int c, b;
73
74 kp= keymaterial;
75 keylen= 0;
76
77 for (;;) {
78 c= *kp++;
79 if (between('0', c, '9')) b= (c - '0' + 0x0) << 4;
80 else
81 if (between('a', c, 'f')) b= (c - 'a' + 0xa) << 4;
82 else
83 if (between('A', c, 'F')) b= (c - 'A' + 0xA) << 4;
84 else break;
85
86 c= *kp++;
87 if (between('0', c, '9')) b |= (c - '0' + 0x0);
88 else
89 if (between('a', c, 'f')) b |= (c - 'a' + 0xa);
90 else
91 if (between('A', c, 'F')) b |= (c - 'A' + 0xA);
92 else break;
93
94 if (keylen >= 256/8) return RD_BAD_KEY_MAT;
95 B(k)[keylen++] = b;
96 }
97 if (c != 0) return RD_BAD_KEY_MAT;
98
99 if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
100 return RD_BAD_KEY_MAT;
101 }
102 } else {
103 if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
104 return RD_BAD_KEY_MAT;
105 }
106 memcpy(k, keymaterial, keylen);
107 }
108
109 key->rounds= keylen * 8 / 32 + 6;
110
111 rijndael_KeySched(k, key->encsched, key->rounds);
112 memcpy(key->decsched, key->encsched, sizeof(key->decsched));
113 rijndael_KeyEncToDec(key->decsched, key->rounds);
114
115 return 0;
116}
117
118ssize_t rijndael_ecb_encrypt(rd_keyinstance *key,
119 const void *input, void *output, size_t length, void *dummyIV)
120{
121 /* Encrypt blocks of data in Electronic Codebook mode. */
122 const word8 *inp= input;
123 word8 *outp= output;
124 size_t i, nr_blocks, extra;
125 word32 in[4], out[4];
126 word8 t;
127
128 /* Compute the number of whole blocks, and the extra bytes beyond the
129 * last block. Those extra bytes, if any, are encrypted by stealing
130 * enough bytes from the previous encrypted block to make a whole block.
131 * This is done by encrypting the last block, exchanging the first few
132 * encrypted bytes with the extra bytes, and encrypting the last whole
133 * block again.
134 */
135 nr_blocks= length / 16;
136 if ((extra= (length % 16)) > 0) {
137 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
138 nr_blocks--;
139 }
140
141 /* Encrypt a number of blocks. */
142 if (aligned2(inp, outp)) {
143 for (i= 0; i < nr_blocks; i++) {
144 rijndael_Encrypt(inp, outp, key->encsched, key->rounds);
145 inp += 16;
146 outp += 16;
147 }
148 } else {
149 for (i= 0; i < nr_blocks; i++) {
150 blockcpy(in, inp);
151 rijndael_Encrypt(in, out, key->encsched, key->rounds);
152 blockcpy(outp, out);
153 inp += 16;
154 outp += 16;
155 }
156 }
157
158 /* Encrypt extra bytes by stealing from the last full block. */
159 if (extra > 0) {
160 blockcpy(in, inp);
161 rijndael_Encrypt(in, out, key->encsched, key->rounds);
162 for (i= 0; i < extra; i++) {
163 t= B(out)[i];
164 B(out)[i] = inp[16 + i];
165 outp[16 + i] = t;
166 }
167 rijndael_Encrypt(out, out, key->encsched, key->rounds);
168 blockcpy(outp, out);
169 }
170 return length;
171}
172
173ssize_t rijndael_ecb_decrypt(rd_keyinstance *key,
174 const void *input, void *output, size_t length, void *dummyIV)
175{
176 /* Decrypt blocks of data in Electronic Codebook mode. */
177 const word8 *inp= input;
178 word8 *outp= output;
179 size_t i, nr_blocks, extra;
180 word32 in[4], out[4];
181 word8 t;
182
183 nr_blocks= length / 16;
184 if ((extra= (length % 16)) > 0) {
185 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
186 nr_blocks--;
187 }
188
189 /* Decrypt a number of blocks. */
190 if (aligned2(inp, outp)) {
191 for (i= 0; i < nr_blocks; i++) {
192 rijndael_Decrypt(inp, outp, key->decsched, key->rounds);
193 inp += 16;
194 outp += 16;
195 }
196 } else {
197 for (i= 0; i < nr_blocks; i++) {
198 blockcpy(in, inp);
199 rijndael_Decrypt(in, out, key->decsched, key->rounds);
200 blockcpy(outp, out);
201 inp += 16;
202 outp += 16;
203 }
204 }
205
206 /* Decrypt extra bytes that stole from the last full block. */
207 if (extra > 0) {
208 blockcpy(in, inp);
209 rijndael_Decrypt(in, out, key->decsched, key->rounds);
210 for (i= 0; i < extra; i++) {
211 t= B(out)[i];
212 B(out)[i] = inp[16 + i];
213 outp[16 + i] = t;
214 }
215 rijndael_Decrypt(out, out, key->decsched, key->rounds);
216 blockcpy(outp, out);
217 }
218 return length;
219}
220
221ssize_t rijndael_cbc_encrypt(rd_keyinstance *key,
222 const void *input, void *output, size_t length, void *IV)
223{
224 /* Encrypt blocks of data in Cypher Block Chaining mode. */
225 const word8 *inp= input;
226 word8 *outp= output;
227 size_t i, nr_blocks, extra;
228 word32 in[4], out[4], iv[4], *ivp;
229 word8 t;
230
231 nr_blocks= length / 16;
232 if ((extra= (length % 16)) > 0) {
233 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
234 nr_blocks--;
235 }
236
237 /* Each input block is first XORed with the previous encryption result.
238 * The "Initialization Vector" is used to XOR the first block with.
239 * When done the last crypted block is stored back as the new IV to be
240 * used for another call to this function.
241 */
242 ivp= aligned(IV) ? IV : (blockcpy(iv, IV), iv);
243
244 if (aligned2(inp, outp)) {
245 for (i= 0; i < nr_blocks; i++) {
246 in[0] = W(inp)[0] ^ ivp[0];
247 in[1] = W(inp)[1] ^ ivp[1];
248 in[2] = W(inp)[2] ^ ivp[2];
249 in[3] = W(inp)[3] ^ ivp[3];
250 rijndael_Encrypt(in, outp, key->encsched, key->rounds);
251 ivp= W(outp);
252 inp += 16;
253 outp += 16;
254 }
255 } else {
256 for (i= 0; i < nr_blocks; i++) {
257 blockcpy(in, inp);
258 in[0] ^= ivp[0];
259 in[1] ^= ivp[1];
260 in[2] ^= ivp[2];
261 in[3] ^= ivp[3];
262 rijndael_Encrypt(in, out, key->encsched, key->rounds);
263 blockcpy(outp, out);
264 ivp= out;
265 inp += 16;
266 outp += 16;
267 }
268 }
269 if (extra > 0) {
270 blockcpy(in, inp);
271 in[0] ^= ivp[0];
272 in[1] ^= ivp[1];
273 in[2] ^= ivp[2];
274 in[3] ^= ivp[3];
275 rijndael_Encrypt(in, out, key->encsched, key->rounds);
276 for (i= 0; i < extra; i++) {
277 t= B(out)[i];
278 B(out)[i] ^= inp[16 + i];
279 outp[16 + i] = t;
280 }
281 rijndael_Encrypt(out, out, key->encsched, key->rounds);
282 blockcpy(outp, out);
283 ivp= out;
284 }
285 blockcpy(IV, ivp); /* Store last IV back. */
286 return length;
287}
288
289ssize_t rijndael_cbc_decrypt(rd_keyinstance *key,
290 const void *input, void *output, size_t length, void *IV)
291{
292 /* Decrypt blocks of data in Cypher Block Chaining mode. */
293 const word8 *inp= input;
294 word8 *outp= output;
295 size_t i, nr_blocks, extra;
296 word32 in[4], out[4], iv[4];
297 word8 t;
298
299 nr_blocks= length / 16;
300 if ((extra= (length % 16)) > 0) {
301 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
302 nr_blocks--;
303 }
304
305 blockcpy(iv, IV);
306
307 if (aligned2(inp, outp)) {
308 for (i= 0; i < nr_blocks; i++) {
309 rijndael_Decrypt(inp, out, key->decsched, key->rounds);
310 out[0] ^= iv[0];
311 out[1] ^= iv[1];
312 out[2] ^= iv[2];
313 out[3] ^= iv[3];
314 iv[0] = W(inp)[0];
315 iv[1] = W(inp)[1];
316 iv[2] = W(inp)[2];
317 iv[3] = W(inp)[3];
318 W(outp)[0] = out[0];
319 W(outp)[1] = out[1];
320 W(outp)[2] = out[2];
321 W(outp)[3] = out[3];
322 inp += 16;
323 outp += 16;
324 }
325 } else {
326 for (i= 0; i < nr_blocks; i++) {
327 blockcpy(in, inp);
328 rijndael_Decrypt(in, out, key->decsched, key->rounds);
329 out[0] ^= iv[0];
330 out[1] ^= iv[1];
331 out[2] ^= iv[2];
332 out[3] ^= iv[3];
333 iv[0] = in[0];
334 iv[1] = in[1];
335 iv[2] = in[2];
336 iv[3] = in[3];
337 blockcpy(outp, out);
338 inp += 16;
339 outp += 16;
340 }
341 }
342 if (extra > 0) {
343 blockcpy(in, inp);
344 blockcpy(IV, in);
345 rijndael_Decrypt(in, out, key->decsched, key->rounds);
346 for (i= 0; i < extra; i++) {
347 t= B(out)[i] ^ inp[16 + i];
348 B(out)[i] = inp[16 + i];
349 outp[16 + i] = t;
350 }
351 rijndael_Decrypt(out, out, key->decsched, key->rounds);
352 out[0] ^= iv[0];
353 out[1] ^= iv[1];
354 out[2] ^= iv[2];
355 out[3] ^= iv[3];
356 blockcpy(outp, out);
357 } else {
358 blockcpy(IV, iv);
359 }
360 return length;
361}
362
363ssize_t rijndael_cfb1_encrypt(rd_keyinstance *key,
364 const void *input, void *output, size_t length, void *IV)
365{
366 /* Encrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
367 const word8 *inp= input;
368 word8 *outp= output;
369 word8 t;
370 size_t i;
371 int b;
372 word32 iv[4], civ[4];
373
374 blockcpy(iv, IV);
375
376 for (i= 0; i < length; i++) {
377 t= *inp++;
378 for (b= 0; b < 8; b++) {
379 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
380 t ^= (B(civ)[0] & 0x80) >> b;
381 B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
382 B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
383 B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
384 B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
385 B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
386 B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
387 B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
388 B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
389 B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
390 B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
391 B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
392 B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
393 B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
394 B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
395 B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
396 B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
397 }
398 *outp++ = t;
399 }
400 blockcpy(IV, iv);
401 return length;
402}
403
404ssize_t rijndael_cfb1_decrypt(rd_keyinstance *key,
405 const void *input, void *output, size_t length, void *IV)
406{
407 /* Decrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
408 const word8 *inp= input;
409 word8 *outp= output;
410 word8 t;
411 size_t i;
412 int b;
413 word32 iv[4], civ[4];
414
415 blockcpy(iv, IV);
416
417 for (i= 0; i < length; i++) {
418 t= *inp++;
419 for (b= 0; b < 8; b++) {
420 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
421 B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
422 B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
423 B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
424 B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
425 B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
426 B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
427 B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
428 B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
429 B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
430 B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
431 B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
432 B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
433 B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
434 B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
435 B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
436 B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
437 t ^= (B(civ)[0] & 0x80) >> b;
438 }
439 *outp++ = t;
440 }
441 blockcpy(IV, iv);
442 return length;
443}
444
445ssize_t rijndael_cfb8_encrypt(rd_keyinstance *key,
446 const void *input, void *output, size_t length, void *IV)
447{
448 /* Encrypt blocks of data in Cypher Feedback mode, 8 bits at a time. */
449 const word8 *inp= input;
450 word8 *outp= output;
451 word8 t;
452 size_t i;
453 word32 iv[4], civ[4];
454
455 blockcpy(iv, IV);
456
457 for (i= 0; i < length; i++) {
458 t= *inp++;
459 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
460 t ^= B(civ)[0];
461 B(iv)[ 0] = B(iv)[ 1];
462 B(iv)[ 1] = B(iv)[ 2];
463 B(iv)[ 2] = B(iv)[ 3];
464 B(iv)[ 3] = B(iv)[ 4];
465 B(iv)[ 4] = B(iv)[ 5];
466 B(iv)[ 5] = B(iv)[ 6];
467 B(iv)[ 6] = B(iv)[ 7];
468 B(iv)[ 7] = B(iv)[ 8];
469 B(iv)[ 8] = B(iv)[ 9];
470 B(iv)[ 9] = B(iv)[10];
471 B(iv)[10] = B(iv)[11];
472 B(iv)[11] = B(iv)[12];
473 B(iv)[12] = B(iv)[13];
474 B(iv)[13] = B(iv)[14];
475 B(iv)[14] = B(iv)[15];
476 B(iv)[15] = t;
477 *outp++ = t;
478 }
479 blockcpy(IV, iv);
480 return length;
481}
482
483ssize_t rijndael_cfb8_decrypt(rd_keyinstance *key,
484 const void *input, void *output, size_t length, void *IV)
485{
486 /* Decrypt blocks of data in Cypher Feedback mode, 1 byte at a time. */
487 const word8 *inp= input;
488 word8 *outp= output;
489 word8 t;
490 size_t i;
491 word32 iv[4], civ[4];
492
493 blockcpy(iv, IV);
494
495 for (i= 0; i < length; i++) {
496 t= *inp++;
497 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
498 B(iv)[ 0] = B(iv)[ 1];
499 B(iv)[ 1] = B(iv)[ 2];
500 B(iv)[ 2] = B(iv)[ 3];
501 B(iv)[ 3] = B(iv)[ 4];
502 B(iv)[ 4] = B(iv)[ 5];
503 B(iv)[ 5] = B(iv)[ 6];
504 B(iv)[ 6] = B(iv)[ 7];
505 B(iv)[ 7] = B(iv)[ 8];
506 B(iv)[ 8] = B(iv)[ 9];
507 B(iv)[ 9] = B(iv)[10];
508 B(iv)[10] = B(iv)[11];
509 B(iv)[11] = B(iv)[12];
510 B(iv)[12] = B(iv)[13];
511 B(iv)[13] = B(iv)[14];
512 B(iv)[14] = B(iv)[15];
513 B(iv)[15] = t;
514 t ^= B(civ)[0];
515 *outp++ = t;
516 }
517 blockcpy(IV, iv);
518 return length;
519}
520
521ssize_t rijndael_pad(void *input, size_t length)
522{
523 /* Adds at most one block of RFC-2040 style padding to the input to make
524 * it a whole number of blocks for easier encryption. To be used if the
525 * input may be less then one block in size, otherwise let the encryption
526 * routines use cypher stealing. The input buffer should allow enough
527 * space for the padding. The new length of the input is returned.
528 */
529 word8 *inp= input;
530 size_t padlen;
531
532 /* Add padding up until the next block boundary. */
533 padlen= 16 - (length % 16);
534 memset(inp + length, padlen, padlen);
535 return length + padlen;
536}
537
538ssize_t rijndael_unpad(const void *input, size_t length)
539{
540 /* Remove RFC-2040 style padding after decryption. The true length of
541 * the input is returned, or the usual errors if the padding is incorrect.
542 */
543 const word8 *inp= input;
544 size_t i, padlen;
545
546 if (length == 0 || (length % 16) != 0) return RD_BAD_BLOCK_LENGTH;
547 padlen = inp[length-1];
548 if (padlen <= 0 || padlen > 16) return RD_BAD_DATA;
549 for (i= 2; i <= padlen; i++) {
550 if (inp[length-i] != padlen) return RD_BAD_DATA;
551 }
552 return length - padlen;
553}
554
555#ifdef INTERMEDIATE_VALUE_KAT
556
557void cipherEncryptUpdateRounds(rd_keyinstance *key,
558 const void *input, void *output, int rounds)
559{
560 /* Encrypt a block only a specified number of rounds. */
561 word8 block[4][4];
562
563 blockcpy(block, input);
564
565 rijndaelEncryptRound(block, key->encsched, key->rounds, rounds);
566
567 blockcpy(output, block);
568}
569
570void cipherDecryptUpdateRounds(rd_keyinstance *key,
571 const void *input, void *output, int rounds)
572{
573 /* Decrypt a block only a specified number of rounds. */
574 word8 block[4][4];
575
576 blockcpy(block, input);
577
578 rijndaelDecryptRound(block, key->decsched, key->rounds, rounds);
579
580 blockcpy(output, block);
581}
582#endif /* INTERMEDIATE_VALUE_KAT */
583
584/*
585 * $PchId: rijndael_api.c,v 1.2 2001/01/10 22:01:20 philip Exp $
586 */
Note: See TracBrowser for help on using the repository browser.