diff options
Diffstat (limited to 'aes_keywrap.c')
-rw-r--r-- | aes_keywrap.c | 178 |
1 files changed, 147 insertions, 31 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 @@ -50,7 +50,21 @@ #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; @@ -114,6 +130,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 * words no matter what we do, we can eliminate a few gratuitous @@ -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; + } } } } |