2016-06-01 15:07:50 -04:00
|
|
|
#include <assert.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "aes.h"
|
|
|
|
#include "block.h"
|
|
|
|
#include "cmac.h"
|
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
static const uint8_t zeros[16] = {0};
|
2016-06-01 15:07:50 -04:00
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
static uint8_t g_k1[16],
|
|
|
|
g_k2[16];
|
2016-06-01 15:07:50 -04:00
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
#ifdef HOST_BUILD
|
|
|
|
void cmac_get_subkeys(uint8_t *dest) {
|
|
|
|
/* Testing stub to get subkeys for algo check */
|
|
|
|
memcpy(dest, g_k1, 16);
|
|
|
|
memcpy(dest+16, g_k2, 16);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /* HOST_BUILD */
|
|
|
|
|
|
|
|
void cmac_aes128_init(uint8_t *key) {
|
2016-06-01 15:25:05 -04:00
|
|
|
/* Initialize AES engine and cache subkeys */
|
2016-06-05 22:36:16 -04:00
|
|
|
aes128_init(key);
|
|
|
|
cmac_aes128_expand_key(key, g_k1, g_k2);
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
void cmac_aes128_expand_key(uint8_t const * const key, uint8_t *k1, uint8_t *k2) {
|
2016-06-01 15:25:05 -04:00
|
|
|
/* Generate two required subkeys according to NIST 800-38B */
|
2016-06-05 22:36:16 -04:00
|
|
|
uint8_t l[16] = {0},
|
|
|
|
Rb[16] = {0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0x87};
|
2016-06-01 15:07:50 -04:00
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
aes128_ecb(l, zeros);
|
|
|
|
if ((l[0] >> 7) == 0) {
|
|
|
|
block_shiftl(k1, l, 1);
|
2016-06-01 15:07:50 -04:00
|
|
|
} else {
|
2016-06-05 22:36:16 -04:00
|
|
|
uint8_t tmp[16];
|
|
|
|
block_shiftl(tmp, l, 1);
|
|
|
|
block_xor(k1, tmp, Rb);
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
2016-06-05 22:36:16 -04:00
|
|
|
if (!(k1[0] >> 7)) {
|
|
|
|
block_shiftl(k2, k1, 1);
|
2016-06-01 15:07:50 -04:00
|
|
|
} else {
|
2016-06-05 22:36:16 -04:00
|
|
|
uint8_t tmp[16];
|
|
|
|
block_shiftl(tmp, k1, 1);
|
|
|
|
block_xor(k2, tmp, Rb);
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
static void cmac_truncate(uint8_t *dest, uint8_t *tag, uint_fast8_t tag_len) {
|
|
|
|
memmove(dest, tag, tag_len);
|
|
|
|
}
|
2016-06-01 15:25:05 -04:00
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
void cmac_aes128(uint8_t *dest, uint8_t *msg, size_t msg_len, uint_fast8_t tag_len) {
|
2016-06-01 15:25:05 -04:00
|
|
|
/* Simulate ceiling integer division by adding a block if remainder */
|
2016-06-05 22:36:16 -04:00
|
|
|
size_t num_blocks = msg_len / 16 + (msg_len % 16 ? 1 : 0);
|
2016-06-01 15:07:50 -04:00
|
|
|
bool last_block_complete = !(msg_len % 16 ? 1 : 0);
|
|
|
|
if (msg_len == 0) {
|
|
|
|
num_blocks = 1;
|
|
|
|
last_block_complete = false;
|
|
|
|
}
|
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
uint8_t alt_msg[num_blocks*16],
|
|
|
|
*last_block = &alt_msg[(num_blocks-1)*16];
|
|
|
|
memset(alt_msg, 0, num_blocks*16);
|
|
|
|
memmove(alt_msg, msg, msg_len);
|
2016-06-01 15:07:50 -04:00
|
|
|
|
|
|
|
if (!last_block_complete) {
|
|
|
|
/* Padding is single 1 bit, run out on 0s.. find the next byte,
|
|
|
|
set it to 0b1000000 */
|
2016-06-05 22:36:16 -04:00
|
|
|
alt_msg[msg_len] = 0x80;
|
|
|
|
block_xor(last_block, last_block, g_k2);
|
2016-06-01 15:07:50 -04:00
|
|
|
} else {
|
2016-06-05 22:36:16 -04:00
|
|
|
block_xor(last_block, last_block, g_k1);
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
uint8_t x[16] = {0},
|
|
|
|
y[16] = {0};
|
2016-06-01 15:07:50 -04:00
|
|
|
|
2016-06-05 22:36:16 -04:00
|
|
|
for (uint32_t i = 0; i < num_blocks; i++) {
|
|
|
|
uint8_t *block = &alt_msg[i*16];
|
|
|
|
block_xor(y, x, block);
|
|
|
|
aes128_ecb(x, y);
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
2016-06-05 22:36:16 -04:00
|
|
|
cmac_truncate(dest, x, tag_len);
|
|
|
|
return;
|
2016-06-01 15:07:50 -04:00
|
|
|
}
|
|
|
|
|