1 /* rijndael-api.c - Rijndael encryption programming interface.
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.
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))
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
)
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)
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
)
69 /* Initialize key schedule: */
70 if (keylen
== RD_KEY_HEX
) {
79 if (between('0', c
, '9')) b
= (c
- '0' + 0x0) << 4;
81 if (between('a', c
, 'f')) b
= (c
- 'a' + 0xa) << 4;
83 if (between('A', c
, 'F')) b
= (c
- 'A' + 0xA) << 4;
87 if (between('0', c
, '9')) b
|= (c
- '0' + 0x0);
89 if (between('a', c
, 'f')) b
|= (c
- 'a' + 0xa);
91 if (between('A', c
, 'F')) b
|= (c
- 'A' + 0xA);
94 if (keylen
>= 256/8) return RD_BAD_KEY_MAT
;
95 k
[keylen
/4][keylen
%4] = b
;
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
;
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
);
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
;
125 size_t i
, nr_blocks
, extra
;
126 word32 in
[4], out
[4];
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
136 nr_blocks
= length
/ 16;
137 if ((extra
= (length
% 16)) > 0) {
138 if (nr_blocks
== 0) return RD_BAD_BLOCK_LENGTH
;
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
);
150 for (i
= 0; i
< nr_blocks
; i
++) {
152 rijndael_Encrypt(in
, out
, key
->encsched
, key
->rounds
);
159 /* Encrypt extra bytes by stealing from the last full block. */
162 rijndael_Encrypt(in
, out
, key
->encsched
, key
->rounds
);
163 for (i
= 0; i
< extra
; i
++) {
165 B(out
)[i
] = inp
[16 + i
];
168 rijndael_Encrypt(out
, out
, key
->encsched
, key
->rounds
);
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
;
180 size_t i
, nr_blocks
, extra
;
181 word32 in
[4], out
[4];
184 nr_blocks
= length
/ 16;
185 if ((extra
= (length
% 16)) > 0) {
186 if (nr_blocks
== 0) return RD_BAD_BLOCK_LENGTH
;
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
);
198 for (i
= 0; i
< nr_blocks
; i
++) {
200 rijndael_Decrypt(in
, out
, key
->decsched
, key
->rounds
);
207 /* Decrypt extra bytes that stole from the last full block. */
210 rijndael_Decrypt(in
, out
, key
->decsched
, key
->rounds
);
211 for (i
= 0; i
< extra
; i
++) {
213 B(out
)[i
] = inp
[16 + i
];
216 rijndael_Decrypt(out
, out
, key
->decsched
, key
->rounds
);
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
;
228 size_t i
, nr_blocks
, extra
;
229 word32 in
[4], out
[4], iv
[4], *ivp
;
232 nr_blocks
= length
/ 16;
233 if ((extra
= (length
% 16)) > 0) {
234 if (nr_blocks
== 0) return RD_BAD_BLOCK_LENGTH
;
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
);
257 for (i
= 0; i
< nr_blocks
; i
++) {
263 rijndael_Encrypt(in
, out
, key
->encsched
, key
->rounds
);
276 rijndael_Encrypt(in
, out
, key
->encsched
, key
->rounds
);
277 for (i
= 0; i
< extra
; i
++) {
279 B(out
)[i
] ^= inp
[16 + i
];
282 rijndael_Encrypt(out
, out
, key
->encsched
, key
->rounds
);
286 blockcpy(IV
, ivp
); /* Store last IV back. */
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
;
296 size_t i
, nr_blocks
, extra
;
297 word32 in
[4], out
[4], iv
[4];
300 nr_blocks
= length
/ 16;
301 if ((extra
= (length
% 16)) > 0) {
302 if (nr_blocks
== 0) return RD_BAD_BLOCK_LENGTH
;
308 if (aligned2(inp
, outp
)) {
309 for (i
= 0; i
< nr_blocks
; i
++) {
310 rijndael_Decrypt(inp
, out
, key
->decsched
, key
->rounds
);
327 for (i
= 0; i
< nr_blocks
; i
++) {
329 rijndael_Decrypt(in
, out
, key
->decsched
, key
->rounds
);
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
];
352 rijndael_Decrypt(out
, out
, key
->decsched
, key
->rounds
);
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
;
373 word32 iv
[4], civ
[4];
377 for (i
= 0; i
< length
; i
++) {
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);
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
;
414 word32 iv
[4], civ
[4];
418 for (i
= 0; i
< length
; i
++) {
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
;
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
;
454 word32 iv
[4], civ
[4];
458 for (i
= 0; i
< length
; i
++) {
460 rijndael_Encrypt(iv
, civ
, key
->encsched
, key
->rounds
);
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];
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
;
492 word32 iv
[4], civ
[4];
496 for (i
= 0; i
< length
; i
++) {
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];
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.
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
;
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. */
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. */
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 $