

6 changed files with 323 additions and 0 deletions
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Fundación Inria Chile |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup sys_hashes_cmac |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief AES_CMAC implementation |
||||
* |
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <inttypes.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include "crypto/ciphers.h" |
||||
#include "hashes/cmac.h" |
||||
|
||||
#define MIN(a, b) a < b ? a : b |
||||
|
||||
static void _xor128(uint8_t *x, uint8_t *y) |
||||
{ |
||||
for (unsigned i = 0; i < 16; i++) { |
||||
y[i] = x[i] ^ y[i]; |
||||
} |
||||
} |
||||
|
||||
static void _leftshift(uint8_t *x, uint8_t *y) |
||||
{ |
||||
for (unsigned i = 0; i < 15; i++) { |
||||
y[i] = (x[i] << 1) | (x[i + 1] >> 7); |
||||
} |
||||
y[15] = x[15] << 1; |
||||
} |
||||
|
||||
int cmac_init(cmac_context_t *ctx, const uint8_t *key, uint8_t key_size) |
||||
{ |
||||
if (key_size != CMAC_BLOCK_SIZE) { |
||||
return CIPHER_ERR_INVALID_KEY_SIZE; |
||||
} |
||||
|
||||
memset(ctx, 0, sizeof(cmac_context_t)); |
||||
return cipher_init(&(ctx->aes_ctx), CIPHER_AES_128, key, key_size); |
||||
} |
||||
|
||||
void cmac_update(cmac_context_t *ctx, const void *data, size_t len) |
||||
{ |
||||
uint8_t d[16]; |
||||
|
||||
while (len) { |
||||
uint8_t c; |
||||
if (ctx->M_n == 16) { |
||||
ctx->M_n = 0; |
||||
_xor128(ctx->M_last, ctx->X); |
||||
cipher_encrypt(&ctx->aes_ctx, ctx->X, d); |
||||
memcpy(ctx->X, d, CMAC_BLOCK_SIZE); |
||||
} |
||||
c = MIN(CMAC_BLOCK_SIZE - ctx->M_n, len); |
||||
memcpy(ctx->M_last + ctx->M_n, data, c); |
||||
ctx->M_n += c; |
||||
len -= c; |
||||
data = (void *) (((uint8_t *) data) + c); |
||||
|
||||
if (ctx->M_n < CMAC_BLOCK_SIZE) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void cmac_final(cmac_context_t *ctx, void *digest) |
||||
{ |
||||
/* Generate subkeys */ |
||||
uint8_t K[CMAC_BLOCK_SIZE]; |
||||
uint8_t L[CMAC_BLOCK_SIZE]; |
||||
|
||||
memset(K, 0, CMAC_BLOCK_SIZE); |
||||
cipher_encrypt(&ctx->aes_ctx, K, L); |
||||
|
||||
if (L[0] & 0x80) { |
||||
_leftshift(L, K); |
||||
K[15] ^= 0x87; |
||||
} |
||||
else { |
||||
_leftshift(L, K); |
||||
} |
||||
|
||||
if (ctx->M_n != 16) { |
||||
/* Generate K2 */ |
||||
if (K[0] & 0x80) { |
||||
_leftshift(K, K); |
||||
K[15] ^= 0x87; |
||||
} |
||||
else { |
||||
_leftshift(K, K); |
||||
} |
||||
/* Padding */ |
||||
memset(ctx->M_last + ctx->M_n, 0, CMAC_BLOCK_SIZE - ctx->M_n); |
||||
ctx->M_last[ctx->M_n] = 0x80; |
||||
} |
||||
_xor128(K, ctx->M_last); |
||||
_xor128(ctx->M_last, ctx->X); |
||||
cipher_encrypt(&ctx->aes_ctx, ctx->X, L); |
||||
memcpy(digest, L, CMAC_BLOCK_SIZE); |
||||
} |
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Fundación Inria Chile |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup sys_hashes_cmac AES_CMAC |
||||
* @ingroup sys_hashes |
||||
* @brief Implementation of the AES CMAC hashing function |
||||
|
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief AES_CMAC interface definition |
||||
* |
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl> |
||||
*/ |
||||
|
||||
#ifndef HASHES_CMAC_H |
||||
#define HASHES_CMAC_H |
||||
|
||||
#include <stdio.h> |
||||
#include "crypto/ciphers.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Length of AES_CMAC block in bytes |
||||
*/ |
||||
#define CMAC_BLOCK_SIZE 16 |
||||
|
||||
/**
|
||||
* @brief AES_CMAC calculation context |
||||
*/ |
||||
typedef struct { |
||||
/** AES128 context */ |
||||
cipher_t aes_ctx; |
||||
/** auxiliar array for CMAC calculations **/ |
||||
uint8_t X[CMAC_BLOCK_SIZE]; |
||||
/** current last block **/ |
||||
uint8_t M_last[CMAC_BLOCK_SIZE]; |
||||
/** last byte in last block */ |
||||
uint32_t M_n; |
||||
} cmac_context_t; |
||||
|
||||
/**
|
||||
* @brief Initialize CMAC message digest context |
||||
* |
||||
* @param[in] ctx Pointer to the CMAC context to initialize |
||||
* @param[in] key Key to be set |
||||
* @param[in] key_size Size of the key |
||||
* |
||||
* @return CIPHER_INIT_SUCCESS if the initialization was successful. |
||||
* CIPHER_ERR_INVALID_KEY_SIZE if the key size is not valid. |
||||
*/ |
||||
int cmac_init(cmac_context_t *ctx, const uint8_t *key, uint8_t key_size); |
||||
|
||||
/**
|
||||
* @brief Update the CMAC context with a portion of the message being hashed |
||||
* |
||||
* @param[in] ctx Pointer to the CMAC context to update |
||||
* @param[in] data Input data |
||||
* @param[in] len Length of @p data |
||||
*/ |
||||
void cmac_update(cmac_context_t *ctx, const void *data, size_t len); |
||||
|
||||
/**
|
||||
* @brief Finalizes the CMAC message digest |
||||
* |
||||
* @param[in] ctx Pointer to the CMAC context |
||||
* @param[out] digest Result location |
||||
*/ |
||||
void cmac_final(cmac_context_t *ctx, void *digest); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* HASHES_CMAC_H */ |
||||
/** @} */ |
@ -1 +1,3 @@
|
||||
USEMODULE += hashes
|
||||
USEMODULE += crypto
|
||||
CFLAGS += -DCRYPTO_AES
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Fundación Inria Chile |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup unittests |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Test cases for the AES-CMAC hash implementation |
||||
* |
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <inttypes.h> |
||||
#include <string.h> |
||||
|
||||
#include "tests-hashes.h" |
||||
#include "embUnit/embUnit.h" |
||||
#include "hashes/cmac.h" |
||||
#include "crypto/ciphers.h" |
||||
|
||||
static const uint8_t CMAC_KEY[16] = { |
||||
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, |
||||
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c |
||||
}; |
||||
|
||||
static const uint8_t TEST_EMPTY_EXP[16] = { |
||||
0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, |
||||
0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 |
||||
}; |
||||
|
||||
static const uint8_t TEST_1_INP[16] = { |
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, |
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a |
||||
}; |
||||
|
||||
static const uint8_t TEST_1_EXP[16] = { |
||||
0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, |
||||
0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c |
||||
}; |
||||
|
||||
static const uint8_t TEST_2_INP[40] = { |
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, |
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, |
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, |
||||
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, |
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 |
||||
}; |
||||
|
||||
static const uint8_t TEST_2_EXP[16] = { |
||||
0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, |
||||
0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 |
||||
}; |
||||
|
||||
static const uint8_t TEST_3_INP[64] = { |
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, |
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, |
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, |
||||
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, |
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, |
||||
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, |
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, |
||||
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 |
||||
}; |
||||
|
||||
static const uint8_t TEST_3_EXP[16] = { |
||||
0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, |
||||
0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe |
||||
}; |
||||
|
||||
static int calc_and_compare_hash(const uint8_t *hash, size_t size, const uint8_t *expected) |
||||
{ |
||||
uint8_t digest[16]; |
||||
cmac_context_t ctx; |
||||
|
||||
cmac_init(&ctx, CMAC_KEY, 16); |
||||
cmac_update(&ctx, hash, size); |
||||
cmac_final(&ctx, digest); |
||||
return memcmp(digest, expected, 16); |
||||
} |
||||
|
||||
static void test_hashes_cmac(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(calc_and_compare_hash(NULL, 0, TEST_EMPTY_EXP), 0); |
||||
TEST_ASSERT_EQUAL_INT(calc_and_compare_hash(TEST_1_INP, 16, TEST_1_EXP), 0); |
||||
TEST_ASSERT_EQUAL_INT(calc_and_compare_hash(TEST_2_INP, 40, TEST_2_EXP), 0); |
||||
TEST_ASSERT_EQUAL_INT(calc_and_compare_hash(TEST_3_INP, 64, TEST_3_EXP), 0); |
||||
} |
||||
|
||||
static void test_hashes_cmac_keysize(void) |
||||
{ |
||||
cmac_context_t ctx; |
||||
|
||||
TEST_ASSERT_EQUAL_INT(cmac_init(&ctx, CMAC_KEY, 15), CIPHER_ERR_INVALID_KEY_SIZE); |
||||
TEST_ASSERT_EQUAL_INT(cmac_init(&ctx, CMAC_KEY, 16), CIPHER_INIT_SUCCESS); |
||||
} |
||||
|
||||
Test *tests_hashes_cmac_tests(void) |
||||
{ |
||||
EMB_UNIT_TESTFIXTURES(fixtures) { |
||||
new_TestFixture(test_hashes_cmac), |
||||
new_TestFixture(test_hashes_cmac_keysize), |
||||
}; |
||||
|
||||
EMB_UNIT_TESTCALLER(test_hashes_cmac, NULL, NULL, fixtures); |
||||
|
||||
return (Test *)&test_hashes_cmac; |
||||
} |
Loading…
Reference in new issue