2 * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
3 * One-Key CBC MAC (OMAC1) hash with AES-128
4 * AES-128 CTR mode encryption
5 * AES-128 EAX mode encryption/decryption
7 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * Alternatively, this software may be distributed under the terms of BSD
16 * See README and COPYING for more details.
27 #include <openssl/aes.h>
29 #else /* EAP_TLS_FUNCS */
36 typedef struct aes_key_st AES_KEY;
38 #define AES_set_encrypt_key(userKey, bits, key) \
39 rijndaelKeySetupEnc((key)->rk, (userKey))
40 #define AES_set_decrypt_key(userKey, bits, key) \
41 rijndaelKeySetupDec((key)->rk, (userKey))
42 #define AES_encrypt(in, out, key) \
43 rijndaelEncrypt((key)->rk, in, out)
44 #define AES_decrypt(in, out, key) \
45 rijndaelDecrypt((key)->rk, in, out)
47 #endif /* EAP_TLS_FUNCS */
51 * @kek: key encryption key (KEK)
52 * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
53 * @plain: plaintext key to be wrapped, n * 64 bit
54 * @cipher: wrapped key, (n + 1) * 64 bit
56 void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
65 /* 1) Initialize variables. */
67 memcpy(r, plain, 8 * n);
69 AES_set_encrypt_key(kek, 128, &key);
71 /* 2) Calculate intermediate values.
74 * B = AES(K, A | R[i])
75 * A = MSB(64, B) ^ t where t = (n*j)+i
78 for (j = 0; j <= 5; j++) {
80 for (i = 1; i <= n; i++) {
83 AES_encrypt(b, b, &key);
91 /* 3) Output the results.
93 * These are already in @cipher due to the location of temporary
100 * @kek: key encryption key (KEK)
101 * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
102 * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
103 * @plain: plaintext key, n * 64 bit
105 int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
111 /* 1) Initialize variables. */
112 memcpy(a, cipher, 8);
114 memcpy(r, cipher + 8, 8 * n);
116 AES_set_decrypt_key(kek, 128, &key);
118 /* 2) Compute intermediate values.
121 * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
125 for (j = 5; j >= 0; j--) {
126 r = plain + (n - 1) * 8;
127 for (i = n; i >= 1; i--) {
132 AES_decrypt(b, b, &key);
139 /* 3) Output results.
141 * These are already in @plain due to the location of temporary
142 * variables. Just verify that the IV matches with the expected value.
144 for (i = 0; i < 8; i++) {
153 #define BLOCK_SIZE 16
155 static void gf_mulx(u8 *pad)
159 carry = pad[0] & 0x80;
160 for (i = 0; i < BLOCK_SIZE - 1; i++)
161 pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
162 pad[BLOCK_SIZE - 1] <<= 1;
164 pad[BLOCK_SIZE - 1] ^= 0x87;
168 void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
171 u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
172 const u8 *pos = data;
174 size_t left = data_len;
176 AES_set_encrypt_key(key, 128, &akey);
177 memset(cbc, 0, BLOCK_SIZE);
179 while (left >= BLOCK_SIZE) {
180 for (i = 0; i < BLOCK_SIZE; i++)
182 if (left > BLOCK_SIZE)
183 AES_encrypt(cbc, cbc, &akey);
187 memset(pad, 0, BLOCK_SIZE);
188 AES_encrypt(pad, pad, &akey);
191 if (left || data_len == 0) {
192 for (i = 0; i < left; i++)
198 for (i = 0; i < BLOCK_SIZE; i++)
200 AES_encrypt(pad, mac, &akey);
204 void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
207 AES_set_encrypt_key(key, 128, &akey);
208 AES_encrypt(in, out, &akey);
212 void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
213 u8 *data, size_t data_len)
216 size_t len, left = data_len;
219 u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
221 AES_set_encrypt_key(key, 128, &akey);
222 memcpy(counter, nonce, BLOCK_SIZE);
225 AES_encrypt(counter, buf, &akey);
227 len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
228 for (i = 0; i < len; i++)
233 for (i = BLOCK_SIZE - 1; i >= 0; i--) {
242 int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
243 const u8 *hdr, size_t hdr_len,
244 u8 *data, size_t data_len, u8 *tag)
248 u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE];
251 if (nonce_len > data_len)
255 if (hdr_len > buf_len)
259 buf = malloc(buf_len);
266 memcpy(buf + 16, nonce, nonce_len);
267 omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
270 memcpy(buf + 16, hdr, hdr_len);
271 omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
273 aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
275 memcpy(buf + 16, data, data_len);
276 omac1_aes_128(key, buf, 16 + data_len, data_mac);
280 for (i = 0; i < BLOCK_SIZE; i++)
281 tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
287 int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
288 const u8 *hdr, size_t hdr_len,
289 u8 *data, size_t data_len, const u8 *tag)
293 u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE];
296 if (nonce_len > data_len)
300 if (hdr_len > buf_len)
304 buf = malloc(buf_len);
311 memcpy(buf + 16, nonce, nonce_len);
312 omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
315 memcpy(buf + 16, hdr, hdr_len);
316 omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
319 memcpy(buf + 16, data, data_len);
320 omac1_aes_128(key, buf, 16 + data_len, data_mac);
324 for (i = 0; i < BLOCK_SIZE; i++) {
325 if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
329 aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
335 void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
343 AES_set_encrypt_key(key, 128, &akey);
344 memcpy(cbc, iv, BLOCK_SIZE);
346 blocks = data_len / BLOCK_SIZE;
347 for (i = 0; i < blocks; i++) {
348 for (j = 0; j < BLOCK_SIZE; j++)
350 AES_encrypt(cbc, cbc, &akey);
351 memcpy(pos, cbc, BLOCK_SIZE);
357 void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
361 u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE];
365 AES_set_decrypt_key(key, 128, &akey);
366 memcpy(cbc, iv, BLOCK_SIZE);
368 blocks = data_len / BLOCK_SIZE;
369 for (i = 0; i < blocks; i++) {
370 memcpy(tmp, pos, BLOCK_SIZE);
371 AES_decrypt(pos, pos, &akey);
372 for (j = 0; j < BLOCK_SIZE; j++)
374 memcpy(cbc, tmp, BLOCK_SIZE);
383 #define rdtscll(val) \
384 __asm__ __volatile__("rdtsc" : "=A" (val))
386 static void test_aes_perf(void)
388 const int num_iters = 10;
390 unsigned int start, end;
392 u8 key[16], pt[16], ct[16];
394 printf("keySetupEnc:");
395 for (i = 0; i < num_iters; i++) {
397 AES_set_encrypt_key(key, 128, &akey);
399 printf(" %d", end - start);
404 for (i = 0; i < num_iters; i++) {
406 AES_encrypt(pt, ct, &akey);
408 printf(" %d", end - start);
412 #endif /* __i386__ */
415 static int test_eax(void)
417 u8 msg[] = { 0xF7, 0xFB };
418 u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
419 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
420 u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
421 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
422 u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
423 u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
424 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
426 u8 data[sizeof(msg)], tag[BLOCK_SIZE];
428 memcpy(data, msg, sizeof(msg));
429 if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
430 data, sizeof(data), tag)) {
431 printf("AES-128 EAX mode encryption failed\n");
434 if (memcmp(data, cipher, sizeof(data)) != 0) {
435 printf("AES-128 EAX mode encryption returned invalid cipher "
439 if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
440 printf("AES-128 EAX mode encryption returned invalid tag\n");
444 if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
445 data, sizeof(data), tag)) {
446 printf("AES-128 EAX mode decryption failed\n");
449 if (memcmp(data, msg, sizeof(data)) != 0) {
450 printf("AES-128 EAX mode decryption returned invalid plain "
459 static int test_cbc(void)
461 struct cbc_test_vector {
469 { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
470 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
471 { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
472 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
474 { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
475 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
479 { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
480 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
481 { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
482 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
483 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
484 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
485 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
486 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
487 { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
488 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
489 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
490 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
497 for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
498 struct cbc_test_vector *tv = &vectors[i];
499 buf = malloc(tv->len);
504 memcpy(buf, tv->plain, tv->len);
505 aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
506 if (memcmp(buf, tv->cipher, tv->len) != 0) {
507 printf("AES-CBC encrypt %d failed\n", i);
510 memcpy(buf, tv->cipher, tv->len);
511 aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
512 if (memcmp(buf, tv->plain, tv->len) != 0) {
513 printf("AES-CBC decrypt %d failed\n", i);
523 /* OMAC1 AES-128 test vectors from
524 * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
527 struct omac1_test_vector {
534 static struct omac1_test_vector test_vectors[] =
537 { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
538 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
541 { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
542 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
545 { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
546 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
547 { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
548 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
550 { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
551 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
554 { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
555 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
556 { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
557 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
558 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
559 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
560 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
562 { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
563 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
566 { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
567 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
568 { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
569 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
570 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
571 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
572 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
573 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
574 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
575 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
577 { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
578 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
583 int main(int argc, char *argv[])
586 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
587 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
590 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
591 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
594 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
595 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
596 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
600 struct omac1_test_vector *tv;
602 aes_wrap(kek, 2, plain, result);
603 if (memcmp(result, crypt, 24) != 0) {
604 printf("AES-WRAP-128-128 failed\n");
607 if (aes_unwrap(kek, 2, crypt, result)) {
608 printf("AES-UNWRAP-128-128 reported failure\n");
611 if (memcmp(result, plain, 16) != 0) {
613 printf("AES-UNWRAP-128-128 failed\n");
615 for (i = 0; i < 16; i++)
616 printf(" %02x", result[i]);
622 #endif /* __i386__ */
624 for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
625 tv = &test_vectors[i];
626 omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
627 if (memcmp(result, tv->tag, 16) != 0) {
628 printf("OMAC1-AES-128 test vector %d failed\n", i);
642 #endif /* TEST_MAIN */