vm: fix region reporting bug
[minix.git] / drivers / random / aes / rijndael_api.c
blob9a564001aa7fbafee7cd6e936d0136991a01aa6b
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.
7 * Read this code top to bottom, not all comments are repeated.
8 */
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
14 #include "rijndael-alg.h"
15 #include "rijndael-api.h"
17 /* Map a byte (?) address to a word address or vv. */
18 #define W(a) ((word32 *) (a))
19 #define B(a) ((word8 *) (a))
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.)
28 #define aligned(a) (((unsigned) (a) & 3) == 0)
29 #define aligned2(a1, a2) aligned((unsigned) (a1) | (unsigned) (a2))
31 static void blockcpy(void *dst, const void *src)
33 int i= 0;
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);
43 #else /* !STRICT_ALIGN */
44 /* This machine doesn't mind misaligned accesses much. */
46 #define aligned(a) ((void) (a), 1)
47 #define aligned2(a1, a2) ((void) (a1), (void) (a2), 1)
49 #if __GNUC__
50 __inline
51 #endif
52 static void blockcpy(void *dst, const void *src)
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];
60 #endif /* !STRICT_ALIGN */
62 #define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
64 int rijndael_makekey(rd_keyinstance *key,
65 size_t keylen, const void *keymaterial)
67 word8 k[MAXKC][4];
69 /* Initialize key schedule: */
70 if (keylen == RD_KEY_HEX) {
71 const word8 *kp;
72 int c, b;
74 kp= keymaterial;
75 keylen= 0;
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;
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;
94 if (keylen >= 256/8) return RD_BAD_KEY_MAT;
95 k[keylen/4][keylen%4] = b;
96 keylen++;
98 if (c != 0) return RD_BAD_KEY_MAT;
100 if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
101 return RD_BAD_KEY_MAT;
103 } else {
104 if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
105 return RD_BAD_KEY_MAT;
107 memcpy(k, keymaterial, keylen);
110 key->rounds= keylen * 8 / 32 + 6;
112 rijndael_KeySched(k, key->encsched, key->rounds);
113 memcpy(key->decsched, key->encsched, sizeof(key->decsched));
114 rijndael_KeyEncToDec(key->decsched, key->rounds);
116 return 0;
119 ssize_t rijndael_ecb_encrypt(rd_keyinstance *key,
120 const void *input, void *output, size_t length, void *dummyIV)
122 /* Encrypt blocks of data in Electronic Codebook mode. */
123 const word8 *inp= input;
124 word8 *outp= output;
125 size_t i, nr_blocks, extra;
126 word32 in[4], out[4];
127 word8 t;
129 /* Compute the number of whole blocks, and the extra bytes beyond the
130 * last block. Those extra bytes, if any, are encrypted by stealing
131 * enough bytes from the previous encrypted block to make a whole block.
132 * This is done by encrypting the last block, exchanging the first few
133 * encrypted bytes with the extra bytes, and encrypting the last whole
134 * block again.
136 nr_blocks= length / 16;
137 if ((extra= (length % 16)) > 0) {
138 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
139 nr_blocks--;
142 /* Encrypt a number of blocks. */
143 if (aligned2(inp, outp)) {
144 for (i= 0; i < nr_blocks; i++) {
145 rijndael_Encrypt(inp, outp, key->encsched, key->rounds);
146 inp += 16;
147 outp += 16;
149 } else {
150 for (i= 0; i < nr_blocks; i++) {
151 blockcpy(in, inp);
152 rijndael_Encrypt(in, out, key->encsched, key->rounds);
153 blockcpy(outp, out);
154 inp += 16;
155 outp += 16;
159 /* Encrypt extra bytes by stealing from the last full block. */
160 if (extra > 0) {
161 blockcpy(in, inp);
162 rijndael_Encrypt(in, out, key->encsched, key->rounds);
163 for (i= 0; i < extra; i++) {
164 t= B(out)[i];
165 B(out)[i] = inp[16 + i];
166 outp[16 + i] = t;
168 rijndael_Encrypt(out, out, key->encsched, key->rounds);
169 blockcpy(outp, out);
171 return length;
174 ssize_t rijndael_ecb_decrypt(rd_keyinstance *key,
175 const void *input, void *output, size_t length, void *dummyIV)
177 /* Decrypt blocks of data in Electronic Codebook mode. */
178 const word8 *inp= input;
179 word8 *outp= output;
180 size_t i, nr_blocks, extra;
181 word32 in[4], out[4];
182 word8 t;
184 nr_blocks= length / 16;
185 if ((extra= (length % 16)) > 0) {
186 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
187 nr_blocks--;
190 /* Decrypt a number of blocks. */
191 if (aligned2(inp, outp)) {
192 for (i= 0; i < nr_blocks; i++) {
193 rijndael_Decrypt(inp, outp, key->decsched, key->rounds);
194 inp += 16;
195 outp += 16;
197 } else {
198 for (i= 0; i < nr_blocks; i++) {
199 blockcpy(in, inp);
200 rijndael_Decrypt(in, out, key->decsched, key->rounds);
201 blockcpy(outp, out);
202 inp += 16;
203 outp += 16;
207 /* Decrypt extra bytes that stole from the last full block. */
208 if (extra > 0) {
209 blockcpy(in, inp);
210 rijndael_Decrypt(in, out, key->decsched, key->rounds);
211 for (i= 0; i < extra; i++) {
212 t= B(out)[i];
213 B(out)[i] = inp[16 + i];
214 outp[16 + i] = t;
216 rijndael_Decrypt(out, out, key->decsched, key->rounds);
217 blockcpy(outp, out);
219 return length;
222 ssize_t rijndael_cbc_encrypt(rd_keyinstance *key,
223 const void *input, void *output, size_t length, void *IV)
225 /* Encrypt blocks of data in Cypher Block Chaining mode. */
226 const word8 *inp= input;
227 word8 *outp= output;
228 size_t i, nr_blocks, extra;
229 word32 in[4], out[4], iv[4], *ivp;
230 word8 t;
232 nr_blocks= length / 16;
233 if ((extra= (length % 16)) > 0) {
234 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
235 nr_blocks--;
238 /* Each input block is first XORed with the previous encryption result.
239 * The "Initialization Vector" is used to XOR the first block with.
240 * When done the last crypted block is stored back as the new IV to be
241 * used for another call to this function.
243 ivp= aligned(IV) ? IV : (blockcpy(iv, IV), iv);
245 if (aligned2(inp, outp)) {
246 for (i= 0; i < nr_blocks; i++) {
247 in[0] = W(inp)[0] ^ ivp[0];
248 in[1] = W(inp)[1] ^ ivp[1];
249 in[2] = W(inp)[2] ^ ivp[2];
250 in[3] = W(inp)[3] ^ ivp[3];
251 rijndael_Encrypt(in, outp, key->encsched, key->rounds);
252 ivp= W(outp);
253 inp += 16;
254 outp += 16;
256 } else {
257 for (i= 0; i < nr_blocks; i++) {
258 blockcpy(in, inp);
259 in[0] ^= ivp[0];
260 in[1] ^= ivp[1];
261 in[2] ^= ivp[2];
262 in[3] ^= ivp[3];
263 rijndael_Encrypt(in, out, key->encsched, key->rounds);
264 blockcpy(outp, out);
265 ivp= out;
266 inp += 16;
267 outp += 16;
270 if (extra > 0) {
271 blockcpy(in, inp);
272 in[0] ^= ivp[0];
273 in[1] ^= ivp[1];
274 in[2] ^= ivp[2];
275 in[3] ^= ivp[3];
276 rijndael_Encrypt(in, out, key->encsched, key->rounds);
277 for (i= 0; i < extra; i++) {
278 t= B(out)[i];
279 B(out)[i] ^= inp[16 + i];
280 outp[16 + i] = t;
282 rijndael_Encrypt(out, out, key->encsched, key->rounds);
283 blockcpy(outp, out);
284 ivp= out;
286 blockcpy(IV, ivp); /* Store last IV back. */
287 return length;
290 ssize_t rijndael_cbc_decrypt(rd_keyinstance *key,
291 const void *input, void *output, size_t length, void *IV)
293 /* Decrypt blocks of data in Cypher Block Chaining mode. */
294 const word8 *inp= input;
295 word8 *outp= output;
296 size_t i, nr_blocks, extra;
297 word32 in[4], out[4], iv[4];
298 word8 t;
300 nr_blocks= length / 16;
301 if ((extra= (length % 16)) > 0) {
302 if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
303 nr_blocks--;
306 blockcpy(iv, IV);
308 if (aligned2(inp, outp)) {
309 for (i= 0; i < nr_blocks; i++) {
310 rijndael_Decrypt(inp, out, key->decsched, key->rounds);
311 out[0] ^= iv[0];
312 out[1] ^= iv[1];
313 out[2] ^= iv[2];
314 out[3] ^= iv[3];
315 iv[0] = W(inp)[0];
316 iv[1] = W(inp)[1];
317 iv[2] = W(inp)[2];
318 iv[3] = W(inp)[3];
319 W(outp)[0] = out[0];
320 W(outp)[1] = out[1];
321 W(outp)[2] = out[2];
322 W(outp)[3] = out[3];
323 inp += 16;
324 outp += 16;
326 } else {
327 for (i= 0; i < nr_blocks; i++) {
328 blockcpy(in, inp);
329 rijndael_Decrypt(in, out, key->decsched, key->rounds);
330 out[0] ^= iv[0];
331 out[1] ^= iv[1];
332 out[2] ^= iv[2];
333 out[3] ^= iv[3];
334 iv[0] = in[0];
335 iv[1] = in[1];
336 iv[2] = in[2];
337 iv[3] = in[3];
338 blockcpy(outp, out);
339 inp += 16;
340 outp += 16;
343 if (extra > 0) {
344 blockcpy(in, inp);
345 blockcpy(IV, in);
346 rijndael_Decrypt(in, out, key->decsched, key->rounds);
347 for (i= 0; i < extra; i++) {
348 t= B(out)[i] ^ inp[16 + i];
349 B(out)[i] = inp[16 + i];
350 outp[16 + i] = t;
352 rijndael_Decrypt(out, out, key->decsched, key->rounds);
353 out[0] ^= iv[0];
354 out[1] ^= iv[1];
355 out[2] ^= iv[2];
356 out[3] ^= iv[3];
357 blockcpy(outp, out);
358 } else {
359 blockcpy(IV, iv);
361 return length;
364 ssize_t rijndael_cfb1_encrypt(rd_keyinstance *key,
365 const void *input, void *output, size_t length, void *IV)
367 /* Encrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
368 const word8 *inp= input;
369 word8 *outp= output;
370 word8 t;
371 size_t i;
372 int b;
373 word32 iv[4], civ[4];
375 blockcpy(iv, IV);
377 for (i= 0; i < length; i++) {
378 t= *inp++;
379 for (b= 0; b < 8; b++) {
380 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
381 t ^= (B(civ)[0] & 0x80) >> b;
382 B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
383 B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
384 B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
385 B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
386 B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
387 B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
388 B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
389 B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
390 B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
391 B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
392 B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
393 B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
394 B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
395 B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
396 B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
397 B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
399 *outp++ = t;
401 blockcpy(IV, iv);
402 return length;
405 ssize_t rijndael_cfb1_decrypt(rd_keyinstance *key,
406 const void *input, void *output, size_t length, void *IV)
408 /* Decrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
409 const word8 *inp= input;
410 word8 *outp= output;
411 word8 t;
412 size_t i;
413 int b;
414 word32 iv[4], civ[4];
416 blockcpy(iv, IV);
418 for (i= 0; i < length; i++) {
419 t= *inp++;
420 for (b= 0; b < 8; b++) {
421 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
422 B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
423 B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
424 B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
425 B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
426 B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
427 B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
428 B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
429 B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
430 B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
431 B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
432 B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
433 B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
434 B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
435 B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
436 B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
437 B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
438 t ^= (B(civ)[0] & 0x80) >> b;
440 *outp++ = t;
442 blockcpy(IV, iv);
443 return length;
446 ssize_t rijndael_cfb8_encrypt(rd_keyinstance *key,
447 const void *input, void *output, size_t length, void *IV)
449 /* Encrypt blocks of data in Cypher Feedback mode, 8 bits at a time. */
450 const word8 *inp= input;
451 word8 *outp= output;
452 word8 t;
453 size_t i;
454 word32 iv[4], civ[4];
456 blockcpy(iv, IV);
458 for (i= 0; i < length; i++) {
459 t= *inp++;
460 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
461 t ^= B(civ)[0];
462 B(iv)[ 0] = B(iv)[ 1];
463 B(iv)[ 1] = B(iv)[ 2];
464 B(iv)[ 2] = B(iv)[ 3];
465 B(iv)[ 3] = B(iv)[ 4];
466 B(iv)[ 4] = B(iv)[ 5];
467 B(iv)[ 5] = B(iv)[ 6];
468 B(iv)[ 6] = B(iv)[ 7];
469 B(iv)[ 7] = B(iv)[ 8];
470 B(iv)[ 8] = B(iv)[ 9];
471 B(iv)[ 9] = B(iv)[10];
472 B(iv)[10] = B(iv)[11];
473 B(iv)[11] = B(iv)[12];
474 B(iv)[12] = B(iv)[13];
475 B(iv)[13] = B(iv)[14];
476 B(iv)[14] = B(iv)[15];
477 B(iv)[15] = t;
478 *outp++ = t;
480 blockcpy(IV, iv);
481 return length;
484 ssize_t rijndael_cfb8_decrypt(rd_keyinstance *key,
485 const void *input, void *output, size_t length, void *IV)
487 /* Decrypt blocks of data in Cypher Feedback mode, 1 byte at a time. */
488 const word8 *inp= input;
489 word8 *outp= output;
490 word8 t;
491 size_t i;
492 word32 iv[4], civ[4];
494 blockcpy(iv, IV);
496 for (i= 0; i < length; i++) {
497 t= *inp++;
498 rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
499 B(iv)[ 0] = B(iv)[ 1];
500 B(iv)[ 1] = B(iv)[ 2];
501 B(iv)[ 2] = B(iv)[ 3];
502 B(iv)[ 3] = B(iv)[ 4];
503 B(iv)[ 4] = B(iv)[ 5];
504 B(iv)[ 5] = B(iv)[ 6];
505 B(iv)[ 6] = B(iv)[ 7];
506 B(iv)[ 7] = B(iv)[ 8];
507 B(iv)[ 8] = B(iv)[ 9];
508 B(iv)[ 9] = B(iv)[10];
509 B(iv)[10] = B(iv)[11];
510 B(iv)[11] = B(iv)[12];
511 B(iv)[12] = B(iv)[13];
512 B(iv)[13] = B(iv)[14];
513 B(iv)[14] = B(iv)[15];
514 B(iv)[15] = t;
515 t ^= B(civ)[0];
516 *outp++ = t;
518 blockcpy(IV, iv);
519 return length;
522 ssize_t rijndael_pad(void *input, size_t length)
524 /* Adds at most one block of RFC-2040 style padding to the input to make
525 * it a whole number of blocks for easier encryption. To be used if the
526 * input may be less then one block in size, otherwise let the encryption
527 * routines use cypher stealing. The input buffer should allow enough
528 * space for the padding. The new length of the input is returned.
530 word8 *inp= input;
531 size_t padlen;
533 /* Add padding up until the next block boundary. */
534 padlen= 16 - (length % 16);
535 memset(inp + length, padlen, padlen);
536 return length + padlen;
539 ssize_t rijndael_unpad(const void *input, size_t length)
541 /* Remove RFC-2040 style padding after decryption. The true length of
542 * the input is returned, or the usual errors if the padding is incorrect.
544 const word8 *inp= input;
545 size_t i, padlen;
547 if (length == 0 || (length % 16) != 0) return RD_BAD_BLOCK_LENGTH;
548 padlen = inp[length-1];
549 if (padlen <= 0 || padlen > 16) return RD_BAD_DATA;
550 for (i= 2; i <= padlen; i++) {
551 if (inp[length-i] != padlen) return RD_BAD_DATA;
553 return length - padlen;
556 #ifdef INTERMEDIATE_VALUE_KAT
558 void cipherEncryptUpdateRounds(rd_keyinstance *key,
559 const void *input, void *output, int rounds)
561 /* Encrypt a block only a specified number of rounds. */
562 word8 block[4][4];
564 blockcpy(block, input);
566 rijndaelEncryptRound(block, key->encsched, key->rounds, rounds);
568 blockcpy(output, block);
571 void cipherDecryptUpdateRounds(rd_keyinstance *key,
572 const void *input, void *output, int rounds)
574 /* Decrypt a block only a specified number of rounds. */
575 word8 block[4][4];
577 blockcpy(block, input);
579 rijndaelDecryptRound(block, key->decsched, key->rounds, rounds);
581 blockcpy(output, block);
583 #endif /* INTERMEDIATE_VALUE_KAT */
586 * $PchId: rijndael_api.c,v 1.2 2001/01/10 22:01:20 philip Exp $