diff options
Diffstat (limited to 'aes_keywrap.c')
-rw-r--r-- | aes_keywrap.c | 176 |
1 files changed, 141 insertions, 35 deletions
diff --git a/aes_keywrap.c b/aes_keywrap.c index 144ad68..b849304 100644 --- a/aes_keywrap.c +++ b/aes_keywrap.c @@ -4,8 +4,9 @@ * Implementation of RFC 5649 over Cryptech AES core. * * Authors: Rob Austein - * Copyright (c) 2015-2017, NORDUnet A/S - * All rights reserved. + * Copyright (c) 2015-2018, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -17,9 +18,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -50,7 +51,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 +77,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 +131,57 @@ 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); + + /* n is the number of 64-bit (8-byte) blocks in the input. + * KEYWRAP_LEN_R_DATA is the number of 4-byte data registers in the core. + */ + if (n == 0 || n > KEYWRAP_LEN_R_DATA * 2) + 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 */ + if ((err = hal_io_write(core, KEYWRAP_ADDR_R_DATA, C + 8, 8 * n)) != 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 to R_DATA */ + if ((err = hal_io_read(core, KEYWRAP_ADDR_R_DATA, C + 8, 8 * n)) != 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 +231,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 +240,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 +277,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 +329,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 +354,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; + } } } } |