From 255ebc59bf1000af6715217679bc82d5bc4d536b Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Wed, 15 Aug 2018 17:30:14 -0400 Subject: Add support for Joachim's keywrap core. --- aes_keywrap.c | 178 +++++++++++++++++++++++++++++++++++++++++++--------- hal.h | 5 ++ hal_io_fmc.c | 6 +- verilog_constants.h | 26 ++++++++ 4 files changed, 182 insertions(+), 33 deletions(-) diff --git a/aes_keywrap.c b/aes_keywrap.c index 144ad68..77146e6 100644 --- a/aes_keywrap.c +++ b/aes_keywrap.c @@ -4,7 +4,7 @@ * Implementation of RFC 5649 over Cryptech AES core. * * Authors: Rob Austein - * Copyright (c) 2015-2017, NORDUnet A/S + * Copyright (c) 2015-2018, NORDUnet A/S * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,8 +49,22 @@ #include "hal.h" #include "hal_internal.h" +/* + * Enable use of the experimental keywrap core, if present. + */ + +static int use_keywrap_core = 0; + +int hal_aes_use_keywrap_core(int onoff) +{ + use_keywrap_core = (onoff && hal_core_find(KEYWRAP_NAME, NULL) != NULL); + return use_keywrap_core; +} + + /* * How long the ciphertext will be for a given plaintext length. + * This rounds up the length to a multiple of 8, and adds 8 for the IV. */ size_t hal_aes_keywrap_ciphertext_length(const size_t plaintext_length) @@ -62,6 +76,8 @@ size_t hal_aes_keywrap_ciphertext_length(const size_t plaintext_length) /* * Check the KEK, then load it into the AES core. * Note that our AES core only supports 128 and 256 bit keys. + * + * This should work without modification for the experimental keywrap core. */ typedef enum { KEK_encrypting, KEK_decrypting } kek_action_t; @@ -113,6 +129,68 @@ static hal_error_t load_kek(const hal_core_t *core, const uint8_t *K, const size } +/* + * Use the experimental keywrap core to wrap/unwrap n 64-bit blocks of plaintext. + * The wrapped/unwrapped key is returned in the same buffer. + */ + +static hal_error_t do_keywrap_core(const hal_core_t *core, uint8_t * const C, const size_t n) +{ +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + + hal_error_t err; + + hal_assert(core != NULL && C != NULL && n > 0); + + /* The core is currently limited to 4 banks of 512 bytes, which is way too small. */ + if (n == 0 || n > 4 * 64) + return HAL_ERROR_BAD_ARGUMENTS; + + /* write the AIV to A */ + if ((err = hal_io_write(core, KEYWRAP_ADDR_A0, C, 8)) != HAL_OK) + return err; + + /* write the length to RLEN */ + uint32_t nn = htonl(n); + if ((err = hal_io_write(core, KEYWRAP_ADDR_RLEN, (const uint8_t *)&nn, 4)) != HAL_OK) + return err; + + /* write the data to R_DATA, with bank-switching as necessary */ + for (size_t bank = 0; 64 * bank < n; ++bank) { + uint32_t bb = htonl(bank); + if ((err = hal_io_write(core, KEYWRAP_ADDR_R_BANK, (const uint8_t *)&bb, 4)) != HAL_OK) + return err; + /* R_DATA is 128 32-bit registers, so 64 64-bit blocks or 512 bytes. */ + size_t len = min(n - 64 * bank, 64) * 8; + if ((err = hal_io_write(core, KEYWRAP_ADDR_R_DATA0, (C + 512 * bank + 8), len)) != HAL_OK) + return err; + } + + /* start the wrap/unwrap operation, and wait for it to complete */ + if ((err = hal_io_next(core)) != HAL_OK || + (err = hal_io_wait_ready(core)) != HAL_OK) + return err; + + /* read the A registers */ + if ((err = hal_io_read(core, KEYWRAP_ADDR_A0, C, 8)) != HAL_OK) + return err; + + /* read the data from R_DATA, with bank-switching as necessary */ + for (size_t bank = 0; 64 * bank < n; ++bank) { + uint32_t bb = htonl(bank); + if ((err = hal_io_write(core, KEYWRAP_ADDR_R_BANK, (const uint8_t *)&bb, 4)) != HAL_OK) + return err; + size_t len = min(n - 64 * bank, 64) * 8; + if ((err = hal_io_read(core, KEYWRAP_ADDR_R_DATA0, (C + 512 * bank + 8), len)) != HAL_OK) + return err; + } + + return HAL_OK; +} + + /* * Process one block. Since AES Key Wrap always deals with 64-bit * half blocks and since the bus is going to break this up into 32-bit @@ -163,7 +241,7 @@ hal_error_t hal_aes_keywrap(hal_core_t *core, size_t *C_len) { const size_t calculated_C_len = hal_aes_keywrap_ciphertext_length(m); - const int free_core = core == NULL; + const int free_core = (core == NULL); hal_error_t err; size_t n; @@ -172,8 +250,22 @@ hal_error_t hal_aes_keywrap(hal_core_t *core, if (Q == NULL || C == NULL || C_len == NULL || *C_len < calculated_C_len) return HAL_ERROR_BAD_ARGUMENTS; - if (free_core && (err = hal_core_alloc(AES_CORE_NAME, &core, NULL)) != HAL_OK) - return err; + /* If we're passed a core, we should figure out which one it is. + * In practice, core is always NULL, so this is UNTESTED CODE. + */ + if (core) { + const hal_core_info_t *info = hal_core_info(core); + if (memcmp(info->name, KEYWRAP_NAME, 8) == 0) + use_keywrap_core = 1; + else if (memcmp(info->name, AES_CORE_NAME, 8) != 0) + /* I have no idea what this is */ + return HAL_ERROR_BAD_ARGUMENTS; + } + else { + const char *core_name = (use_keywrap_core ? KEYWRAP_NAME : AES_CORE_NAME); + if ((err = hal_core_alloc(core_name, &core, NULL)) != HAL_OK) + return err; + } if ((err = load_kek(core, K, K_len, KEK_encrypting)) != HAL_OK) goto out; @@ -195,21 +287,26 @@ hal_error_t hal_aes_keywrap(hal_core_t *core, n = calculated_C_len/8 - 1; - if (n == 1) { - if ((err = do_block(core, C, C + 8)) != HAL_OK) - goto out; + if (use_keywrap_core) { + err = do_keywrap_core(core, C, n); } - else { - for (size_t j = 0; j <= 5; j++) { - for (size_t i = 1; i <= n; i++) { - uint32_t t = n * j + i; - if ((err = do_block(core, C, C + i * 8)) != HAL_OK) + if (n == 1) { + if ((err = do_block(core, C, C + 8)) != HAL_OK) + goto out; + } + + else { + for (size_t j = 0; j <= 5; j++) { + for (size_t i = 1; i <= n; i++) { + uint32_t t = n * j + i; + if ((err = do_block(core, C, C + i * 8)) != HAL_OK) goto out; - C[7] ^= t & 0xFF; t >>= 8; - C[6] ^= t & 0xFF; t >>= 8; - C[5] ^= t & 0xFF; t >>= 8; - C[4] ^= t & 0xFF; + C[7] ^= t & 0xFF; t >>= 8; + C[6] ^= t & 0xFF; t >>= 8; + C[5] ^= t & 0xFF; t >>= 8; + C[4] ^= t & 0xFF; + } } } } @@ -242,8 +339,22 @@ hal_error_t hal_aes_keyunwrap(hal_core_t *core, if (C == NULL || Q == NULL || C_len % 8 != 0 || C_len < 16 || Q_len == NULL || *Q_len < C_len) return HAL_ERROR_BAD_ARGUMENTS; - if (free_core && (err = hal_core_alloc(AES_CORE_NAME, &core, NULL)) != HAL_OK) - return err; + /* If we're passed a core, we should figure out which one it is. + * In practice, core is always NULL, so this is UNTESTED CODE. + */ + if (core) { + const hal_core_info_t *info = hal_core_info(core); + if (memcmp(info->name, KEYWRAP_NAME, 8) == 0) + use_keywrap_core = 1; + else if (memcmp(info->name, AES_CORE_NAME, 8) != 0) + /* I have no idea what this is */ + return HAL_ERROR_BAD_ARGUMENTS; + } + else { + const char *core_name = (use_keywrap_core ? KEYWRAP_NAME : AES_CORE_NAME); + if ((err = hal_core_alloc(core_name, &core, NULL)) != HAL_OK) + return err; + } if ((err = load_kek(core, K, K_len, KEK_decrypting)) != HAL_OK) goto out; @@ -253,21 +364,26 @@ hal_error_t hal_aes_keyunwrap(hal_core_t *core, if (Q != C) memmove(Q, C, C_len); - if (n == 1) { - if ((err = do_block(core, Q, Q + 8)) != HAL_OK) - goto out; + if (use_keywrap_core) { + err = do_keywrap_core(core, Q, n); } - else { - for (long j = 5; j >= 0; j--) { - for (size_t i = n; i >= 1; i--) { - uint32_t t = n * j + i; - Q[7] ^= t & 0xFF; t >>= 8; - Q[6] ^= t & 0xFF; t >>= 8; - Q[5] ^= t & 0xFF; t >>= 8; - Q[4] ^= t & 0xFF; - if ((err = do_block(core, Q, Q + i * 8)) != HAL_OK) - goto out; + if (n == 1) { + if ((err = do_block(core, Q, Q + 8)) != HAL_OK) + goto out; + } + + else { + for (long j = 5; j >= 0; j--) { + for (size_t i = n; i >= 1; i--) { + uint32_t t = n * j + i; + Q[7] ^= t & 0xFF; t >>= 8; + Q[6] ^= t & 0xFF; t >>= 8; + Q[5] ^= t & 0xFF; t >>= 8; + Q[4] ^= t & 0xFF; + if ((err = do_block(core, Q, Q + i * 8)) != HAL_OK) + goto out; + } } } } diff --git a/hal.h b/hal.h index b544900..9986de7 100644 --- a/hal.h +++ b/hal.h @@ -109,6 +109,9 @@ #define ECDSA384_NAME "ecdsa384" #define ECDSA384_VERSION "0.11" +#define KEYWRAP_NAME "key wrap" +#define KEYWRAP_VERSION "0.70" + /* * C API error codes. Defined in this form so we can keep the tokens * and error strings together. See errorstrings.c. @@ -363,6 +366,8 @@ extern const hal_hash_descriptor_t *hal_hmac_get_descriptor(const hal_hmac_state * AES key wrap functions. */ +extern int hal_aes_use_keywrap_core(int onoff); + extern hal_error_t hal_aes_keywrap(hal_core_t *core, const uint8_t *kek, const size_t kek_length, const uint8_t *plaintext, const size_t plaintext_length, diff --git a/hal_io_fmc.c b/hal_io_fmc.c index 8a32921..07f9352 100644 --- a/hal_io_fmc.c +++ b/hal_io_fmc.c @@ -114,7 +114,8 @@ hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_ for (; len > 0; offset += 4, buf += 4, len -= 4) { uint32_t val; val = htonl(*(uint32_t *)buf); - fmc_write_32(offset, val); + if (fmc_write_32(offset, val) != 0) + return HAL_ERROR_IO_TIMEOUT; } return HAL_OK; @@ -140,7 +141,8 @@ hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf, offset = fmc_offset(offset + hal_core_base(core)); for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) { uint32_t val; - fmc_read_32(offset, &val); + if (fmc_read_32(offset, &val) != 0) + return HAL_ERROR_IO_TIMEOUT; *(uint32_t *)rbuf = ntohl(val); } diff --git a/verilog_constants.h b/verilog_constants.h index 1b00b96..df808c4 100644 --- a/verilog_constants.h +++ b/verilog_constants.h @@ -40,6 +40,7 @@ #ifndef _VERILOG_CONSTANTS_H_ #define _VERILOG_CONSTANTS_H_ + /* * Common to all cores. */ @@ -298,6 +299,31 @@ #define MKMIF_ADDR_EMEM_ADDR (0x10) #define MKMIF_ADDR_EMEM_DATA (0x20) +/* + * AES Keywrap core + */ + +#define KEYWRAP_ADDR_CONFIG (0x0a) +#define KEYWRAP_CONFIG_ENCDEC (1) +#define KEYWRAP_CONFIG_KEYLEN (2) + +#define KEYWRAP_ADDR_RLEN (0x0c) +#define KEYWRAP_ADDR_R_BANK (0x0d) +#define KEYWRAP_ADDR_A0 (0x0e) +#define KEYWRAP_ADDR_A1 (0x0f) + +#define KEYWRAP_ADDR_KEY0 (0x10) +#define KEYWRAP_ADDR_KEY1 (0x11) +#define KEYWRAP_ADDR_KEY2 (0x12) +#define KEYWRAP_ADDR_KEY3 (0x13) +#define KEYWRAP_ADDR_KEY4 (0x14) +#define KEYWRAP_ADDR_KEY5 (0x15) +#define KEYWRAP_ADDR_KEY6 (0x16) +#define KEYWRAP_ADDR_KEY7 (0x17) + +#define KEYWRAP_ADDR_R_DATA0 (0x80) +#define KEYWRAP_ADDR_R_DATA127 (0xff) + #endif /* _VERILOG_CONSTANTS_H_ */ /* -- cgit v1.2.3