summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/build.mk5
-rw-r--r--board/cr50/dcrypto/aes_cmac.c239
-rw-r--r--board/cr50/dcrypto/dcrypto.h9
3 files changed, 135 insertions, 118 deletions
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index f644a2c892..3f1c40f9c6 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -24,7 +24,7 @@ ifeq ($(BOARD_MK_INCLUDED_ONCE),)
# command line.
ENV_VARS := CR50_DEV CRYPTO_TEST H1_RED_BOARD U2F_TEST RND_TEST DRBG_TEST\
ECDSA_TEST DCRYPTO_TEST P256_BIN_TEST SHA1_TEST SHA256_TEST\
- HMAC_SHA256_TEST
+ HMAC_SHA256_TEST CMAC_TEST
ifneq ($(CRYPTO_TEST),)
CPPFLAGS += -DCRYPTO_TEST_SETUP
@@ -114,6 +114,9 @@ fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/dcrypto_p256.o
fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/compare.o
fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/dcrypto_runtime.o
ifneq ($(CRYPTO_TEST),)
+ifneq ($(CMAC_TEST),)
+fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/aes_cmac.o
+endif
fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/gcm.o
fips-${CONFIG_DCRYPTO_BOARD} += dcrypto/hkdf.o
endif
diff --git a/board/cr50/dcrypto/aes_cmac.c b/board/cr50/dcrypto/aes_cmac.c
index a921bc589b..d80d3c872e 100644
--- a/board/cr50/dcrypto/aes_cmac.c
+++ b/board/cr50/dcrypto/aes_cmac.c
@@ -4,38 +4,25 @@
*/
/* AES-CMAC-128 implementation according to NIST SP 800-38B, RFC4493 */
-#include "console.h"
-#include "dcrypto.h"
+#include "internal.h"
#define BSIZE 16 /* 16 bytes per 128-bit block */
-/* Given a 128-bit number in 32-bit chunks, shift to the left by one */
-static void shiftl_1(const uint8_t *in, uint8_t *out)
-{
- int i;
- uint8_t carry = 0;
-
- for (i = 15; i >= 0; i--) {
- out[i] = in[i] << 1;
- out[i] |= carry;
- carry = (in[i] & 0x80) ? 1 : 0;
- }
-}
static void xor128(const uint32_t in1[4], const uint32_t in2[4],
uint32_t out[4])
{
- int i;
+ size_t i;
for (i = 0; i < 4; i++)
out[i] = in1[i] ^ in2[i];
}
-static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i,
+static void get_and_xor(const uint8_t *arr, const size_t nBytes, size_t i,
const uint8_t *xor_term, uint8_t *out)
{
- int j;
- int k;
+ size_t j;
+ size_t k;
for (j = 0; j < 16; j++) {
k = i*16 + j; /* index in arr */
@@ -49,44 +36,66 @@ static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i,
}
}
+static const uint32_t zero[4] = {0, 0, 0, 0};
+
/* Wrapper for initializing and calling AES-128 */
-static int aes128(const uint8_t *K, const uint32_t in[4], uint32_t out[4])
+static enum dcrypto_result aes128(const uint8_t *K, const uint32_t in[4],
+ uint32_t out[4])
{
const uint32_t zero[4] = {0, 0, 0, 0};
if (DCRYPTO_aes_init((const uint8_t *)K, 128, (const uint8_t *)zero,
CIPHER_MODE_ECB, ENCRYPT_MODE) != DCRYPTO_OK)
- return 0;
+ return DCRYPTO_FAIL;
if (DCRYPTO_aes_block((const uint8_t *)in, (uint8_t *)out) !=
DCRYPTO_OK)
- return 0;
- return 1;
+ return DCRYPTO_FAIL;
+ return DCRYPTO_OK;
}
-static int gen_subkey(const uint8_t *K, uint32_t k1[4], uint32_t k2[4])
+static void compute_subkey(uint32_t out_words[4], const uint32_t in_words[4])
{
- uint32_t L[4];
- uint32_t tmp[4];
- const uint32_t *xor_term;
- static const uint32_t zero[4] = {0, 0, 0, 0};
- static const uint32_t Rb[4] = {0, 0, 0, 0x87000000};
+ const uint32_t msb = (in_words[0] >> 7) & 1;
- if (!aes128(K, zero, L))
- return 0;
+ /**
+ * Shift left by 1 bit without branches. The counter is big-endian,
+ * while process it on little-endian arch.
+ */
+ for (size_t index = 0; index < 3; ++index) {
+ /* bit 7 in each byte will become a bit zero in next byte. */
+ out_words[index] = (in_words[index] & 0x80808080) >> 15;
+ /* shift bits left and clear overflows, then combine. */
+ out_words[index] |= (in_words[index] << 1) & 0xfefefefe;
+ /**
+ * and add highest bit of next word which will be in lowest
+ * byte of next word.
+ */
+ out_words[index] |= ((in_words[index + 1] & 0x80) << 17);
+ }
+ out_words[3] = (in_words[3] & 0x80808080) >> 15;
+ out_words[3] |= (in_words[3] << 1) & 0xfefefefe;
+ out_words[3] ^= ((0 - msb) & 0x87) << 24;
+}
+
+static enum dcrypto_result gen_subkey(const uint8_t *K, uint32_t k1[4],
+ uint32_t k2[4])
+{
+ uint32_t L[4];
+ enum dcrypto_result result;
- xor_term = (L[0] & 0x00000080) ? Rb : zero;
- shiftl_1((const uint8_t *)L, (uint8_t *)tmp);
- xor128(tmp, xor_term, k1);
+ result = aes128(K, zero, L);
+ if (result != DCRYPTO_OK)
+ return result;
- xor_term = (k1[0] & 0x00000080) ? Rb : zero;
- shiftl_1((const uint8_t *) k1, (uint8_t *) tmp);
- xor128(tmp, xor_term, k2);
+ compute_subkey(k1, L);
+ compute_subkey(k2, k1);
- return 1;
+ /* result should be DCRYPTO_OK at this point. */
+ return result;
}
-int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
- uint32_t T[4])
+enum dcrypto_result DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M,
+ size_t len, uint32_t T[4])
{
uint32_t n;
int i;
@@ -96,10 +105,12 @@ int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
uint32_t M_last[4];
uint32_t Y[4];
uint32_t X[4] = {0, 0, 0, 0};
+ enum dcrypto_result result;
/* Generate the subkeys K1 and K2 */
- if (!gen_subkey(K, k1, k2))
- return 0;
+ result = gen_subkey(K, k1, k2);
+ if (result != DCRYPTO_OK)
+ return result;
/* Set n and flag.
* flag = 1 if the last block has a full 128 bits; 0 otherwise
@@ -115,14 +126,15 @@ int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
}
/* M_last = padded(last 128-bit block of M) ^ (flag ? k1 : k2) */
- get_and_xor(M, len, n-1, (uint8_t *) (flag ? k1 : k2),
- (uint8_t *) M_last);
+ get_and_xor(M, len, n - 1, (uint8_t *)(flag ? k1 : k2),
+ (uint8_t *)M_last);
- for (i = 0; i < n - 1; i++) {
+ for (i = 0; i < (int)n - 1; i++) {
/* Y = padded(nth 128-bit block of M) ^ (flag ? k1 : k2) */
get_and_xor(M, len, i, (uint8_t *)X, (uint8_t *)Y);
- if (!aes128(K, Y, X))
- return 0;
+ result = aes128(K, Y, X);
+ if (result != DCRYPTO_OK)
+ return result;
}
/* TODO: This block is separate from the main loop in the RFC. However,
@@ -130,29 +142,31 @@ int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
* for one more step, which might be a nicer way to write it.
*/
xor128(X, M_last, Y);
- if (!aes128(K, Y, T))
- return 0;
- return 1;
+ return aes128(K, Y, T);
}
-int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len,
- const uint32_t T[4])
+enum dcrypto_result DCRYPTO_aes_cmac_verify(const uint8_t *key,
+ const uint8_t *M, size_t len,
+ const uint32_t T[4])
{
- int i;
+ size_t i;
uint32_t T2[4];
- int match = 1;
+ uint32_t match = 0;
- if (!DCRYPTO_aes_cmac(key, M, len, T2))
- return -EC_ERROR_UNKNOWN;
+ if (DCRYPTO_aes_cmac(key, M, len, T2) != DCRYPTO_OK)
+ return DCRYPTO_FAIL;
- for (i = 0; i < 4; i++) {
- if (T[i] != T2[i])
- match = 0;
- }
- return match;
+ for (i = 0; i < 4; i++)
+ match |= T[i] ^ T2[i];
+
+ always_memset(T2, 0, sizeof(T2));
+
+ return dcrypto_ok_if_zero(match);
}
#ifdef CRYPTO_TEST_SETUP
+#include "console.h"
+
static int check_answer(const uint32_t expected[4], uint32_t actual[4])
{
int i;
@@ -174,20 +188,27 @@ static int check_answer(const uint32_t expected[4], uint32_t actual[4])
return success;
}
+/* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c
+ * k1: fbeed618 35713366 7c85e08f 7236a8de
+ * k2: f7ddac30 6ae266cc f90bc11e e46d513b
+ */
+static const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
+static const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c,
+ 0xdea83672};
+static const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9,
+ 0x3b516de4};
+
static int command_test_aes_block(int argc, char **argv)
{
uint32_t actual[4];
- const uint32_t zero[4] = {0, 0, 0, 0};
- const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
- const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a, 0x47f0423e,
- 0x6f541bb9};
+ static const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a,
+ 0x47f0423e, 0x6f541bb9};
- aes128((const uint8_t *) K, zero, actual);
+ aes128((const uint8_t *)K, zero, actual);
check_answer(expected, actual);
return 0;
}
-
DECLARE_SAFE_CONSOLE_COMMAND(test_aesbk, command_test_aes_block, NULL,
"Test AES block in AES-CMAC subkey generation");
@@ -195,17 +216,8 @@ static int command_test_subkey_gen(int argc, char **argv)
{
uint32_t k1[4];
uint32_t k2[4];
- /* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c
- * k1: fbeed618 35713366 7c85e08f 7236a8de
- * k2: f7ddac30 6ae266cc f90bc11e e46d513b
- */
- const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
- const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c,
- 0xdea83672};
- const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9,
- 0x3b516de4};
- gen_subkey((const uint8_t *) K, k1, k2);
+ gen_subkey((const uint8_t *)K, k1, k2);
ccprintf("Checking K1: ");
check_answer(k1e, k1);
@@ -227,30 +239,41 @@ struct cmac_test_param {
/* N.B. The order of bytes in each 32-bit block is reversed from the form in
* which they are written in the RFC.
+ * Make sure it is placed in .rodata, not .data
*/
-const struct cmac_test_param rfctests[4] = {
+static const uint8_t M0[0] = {};
+static const uint32_t M1[] = {0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373};
+static const uint32_t M2[] = {0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
+ 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
+ 0x461cc830, 0x11e45ca3};
+static const uint32_t M3[] = {0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
+ 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
+ 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a,
+ 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6};
+
+static const struct cmac_test_param rfctests[4] = {
/* --------------------------------------------------
* Example 1: len = 0
* M <empty string>
* AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746
* --------------------------------------------------
*/
- { .len = 0,
- .M = (uint8_t *) "",
- .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b},
- },
+ {
+ .len = 0,
+ .M = (uint8_t *)M0,
+ .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b},
+ },
/* --------------------------------------------------
* Example 2: len = 16
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
* AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c
* --------------------------------------------------
*/
- { .len = 16,
- .M = (uint8_t *) (uint32_t[]) {
- 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373
- },
- .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0},
- },
+ {
+ .len = sizeof(M1),
+ .M = (uint8_t *)M1,
+ .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0},
+ },
/* --------------------------------------------------
* Example 3: len = 40
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
@@ -259,14 +282,11 @@ const struct cmac_test_param rfctests[4] = {
* AES-CMAC dfa66747 de9ae630 30ca3261 1497c827
* --------------------------------------------------
*/
- { .len = 40,
- .M = (uint8_t *) (uint32_t[]) {
- 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
- 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
- 0x461cc830, 0x11e45ca3
- },
- .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714},
- },
+ {
+ .len = sizeof(M2),
+ .M = (uint8_t *)M2,
+ .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714},
+ },
/* --------------------------------------------------
* Example 4: len = 64
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
@@ -276,15 +296,11 @@ const struct cmac_test_param rfctests[4] = {
* AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe
* --------------------------------------------------
*/
- { .len = 64,
- .M = (uint8_t *) (uint32_t[]) {
- 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
- 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
- 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a,
- 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6
- },
- .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679},
- },
+ {
+ .len = sizeof(M3),
+ .M = (uint8_t *)M3,
+ .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679},
+ },
};
static int command_test_aes_cmac(int argc, char **argv)
@@ -293,7 +309,6 @@ static int command_test_aes_cmac(int argc, char **argv)
uint32_t T[4];
int testN;
struct cmac_test_param param;
- const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
for (i = 1; i < argc; i++) {
testN = strtoi(argv[i], NULL, 10);
@@ -302,6 +317,7 @@ static int command_test_aes_cmac(int argc, char **argv)
ccprintf("Testing RFC Example #%d (%d-byte message)...", testN,
param.len);
+ memset(T, 0, sizeof(T));
DCRYPTO_aes_cmac((const uint8_t *)K, param.M, param.len, T);
check_answer(param.Te, T);
}
@@ -317,24 +333,21 @@ static int command_test_verify(int argc, char **argv)
{
int i;
int testN;
- int result;
+ enum dcrypto_result result;
struct cmac_test_param param;
- const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09};
for (i = 1; i < argc; i++) {
testN = strtoi(argv[i], NULL, 10);
- param = rfctests[testN-1];
+ param = rfctests[testN - 1];
ccprintf("Testing RFC Example #%d (%d-byte message)...", testN,
param.len);
result = DCRYPTO_aes_cmac_verify((const uint8_t *)K, param.M,
- param.len, param.Te);
- if (result == 1)
+ param.len, param.Te);
+ if (result == DCRYPTO_OK)
ccprintf("SUCCESS\n");
- else if (result == 0)
- ccprintf("FAILURE: verify returned INVALID\n");
- else if (result == -EC_ERROR_UNKNOWN)
+ else
ccprintf("FAILURE: verify returned ERROR\n");
}
diff --git a/board/cr50/dcrypto/dcrypto.h b/board/cr50/dcrypto/dcrypto.h
index c162b1c66c..0a8c05a536 100644
--- a/board/cr50/dcrypto/dcrypto.h
+++ b/board/cr50/dcrypto/dcrypto.h
@@ -689,14 +689,15 @@ void DCRYPTO_gcm_finish(struct GCM_CTX *ctx);
* Writes 128-bit tag to T; returns 0 if an error is encountered and 1
* otherwise.
*/
-int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
- uint32_t T[4]);
+enum dcrypto_result DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M,
+ size_t len, uint32_t T[4]);
/* key: 128-bit key, M: message, len: number of bytes in M,
* T: tag to be verified
* Returns 1 if the tag is correct and 0 otherwise.
*/
-int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len,
- const uint32_t T[4]);
+enum dcrypto_result DCRYPTO_aes_cmac_verify(const uint8_t *key,
+ const uint8_t *M, size_t len,
+ const uint32_t T[4]);
/*
* BIGNUM utility methods.