diff options
-rw-r--r-- | hal.h | 4 | ||||
-rw-r--r-- | hash.c | 182 |
2 files changed, 146 insertions, 40 deletions
@@ -511,6 +511,7 @@ typedef struct { const uint8_t * const digest_algorithm_id; size_t digest_algorithm_id_length; const void *driver; + unsigned can_restore_state : 1; } hal_hash_descriptor_t; /* @@ -560,6 +561,9 @@ extern hal_error_t hal_hmac_update(const hal_hmac_state_t state, extern hal_error_t hal_hmac_finalize(const hal_hmac_state_t state, uint8_t *hmac, const size_t length); +extern void hal_hash_cleanup(hal_hash_state_t *state); + +extern void hal_hmac_cleanup(hal_hmac_state_t *state); /* * AES key wrap functions. @@ -76,7 +76,8 @@ typedef struct { } driver_t; /* - * Hash state. + * Hash state. For now we assume that the only core state we need to + * save and restore is the current digest value. */ typedef struct { @@ -84,11 +85,15 @@ typedef struct { const driver_t *driver; uint64_t msg_length_high; /* Total data hashed in this message */ uint64_t msg_length_low; /* (128 bits in SHA-512 cases) */ - uint8_t block[HAL_MAX_HASH_BLOCK_LENGTH]; /* Block we're accumulating */ + uint8_t block[HAL_MAX_HASH_BLOCK_LENGTH], /* Block we're accumulating */ + core_state[HAL_MAX_HASH_DIGEST_LENGTH]; /* Saved core state */ size_t block_used; /* How much of the block we've used */ unsigned block_count; /* Blocks sent */ + unsigned flags; } internal_hash_state_t; +#define STATE_FLAG_STATE_ALLOCATED 0x1 /* State buffer dynamically allocated */ + /* * HMAC state. Right now this just holds the key block and a hash * context; if and when we figure out how PCLSR the hash cores, we @@ -185,42 +190,42 @@ const hal_hash_descriptor_t hal_hash_sha1[1] = {{ SHA1_BLOCK_LEN, SHA1_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha1, sizeof(dalgid_sha1), - &sha1_driver + &sha1_driver, 0 }}; const hal_hash_descriptor_t hal_hash_sha256[1] = {{ SHA256_BLOCK_LEN, SHA256_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha256, sizeof(dalgid_sha256), - &sha256_driver + &sha256_driver, 1 }}; const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{ SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha512_224, sizeof(dalgid_sha512_224), - &sha512_224_driver + &sha512_224_driver, 0 }}; const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{ SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha512_256, sizeof(dalgid_sha512_256), - &sha512_256_driver + &sha512_256_driver, 0 }}; const hal_hash_descriptor_t hal_hash_sha384[1] = {{ SHA512_BLOCK_LEN, SHA384_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha384, sizeof(dalgid_sha384), - &sha384_driver + &sha384_driver, 0 }}; const hal_hash_descriptor_t hal_hash_sha512[1] = {{ SHA512_BLOCK_LEN, SHA512_DIGEST_LEN, sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t), dalgid_sha512, sizeof(dalgid_sha512), - &sha512_driver + &sha512_driver, 0 }}; /* @@ -274,13 +279,21 @@ hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor, const driver_t * const driver = check_driver(descriptor); internal_hash_state_t *state = state_buffer; - if (driver == NULL || state == NULL || opaque_state == NULL || - state_length < descriptor->hash_state_length) + if (driver == NULL || opaque_state == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (state_buffer != NULL && state_length < descriptor->hash_state_length) return HAL_ERROR_BAD_ARGUMENTS; + if (state_buffer == NULL && (state = malloc(descriptor->hash_state_length)) == NULL) + return HAL_ERROR_ALLOCATION_FAILURE; + memset(state, 0, sizeof(*state)); state->descriptor = descriptor; state->driver = driver; + + if (state_buffer == NULL) + state->flags |= STATE_FLAG_STATE_ALLOCATED; opaque_state->state = state; @@ -288,10 +301,66 @@ hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor, } /* + * Clean up hash state. No-op unless memory was dynamically allocated. + */ + +void hal_hash_cleanup(hal_hash_state_t *opaque_state) +{ + if (opaque_state == NULL) + return; + + internal_hash_state_t *state = opaque_state->state; + + if (state == NULL || (state->flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return; + + memset(state, 0, state->descriptor->hash_state_length); + free(state); + opaque_state->state = NULL; +} + +/* + * Read hash result from core. At least for now, this also serves to + * read current hash state from core. + */ + +static hal_error_t hash_read_digest(const driver_t * const driver, + uint8_t *digest, + const size_t digest_length) +{ + hal_error_t err; + + assert(digest != NULL && digest_length % 4 == 0); + + if ((err = hal_io_wait_valid(driver->status_addr)) != HAL_OK) + return err; + + return hal_io_read(driver->digest_addr, digest, digest_length); +} + +/* + * Write hash state back to core. + */ + +static hal_error_t hash_write_digest(const driver_t * const driver, + const uint8_t * const digest, + const size_t digest_length) +{ + hal_error_t err; + + assert(digest != NULL && digest_length % 4 == 0); + + if ((err = hal_io_wait_ready(driver->status_addr)) != HAL_OK) + return err; + + return hal_io_write(driver->digest_addr, digest, digest_length); +} + +/* * Send one block to a core. */ -static hal_error_t hash_write_block(const internal_hash_state_t * const state) +static hal_error_t hash_write_block(internal_hash_state_t *state) { uint8_t ctrl_cmd[4]; hal_error_t err; @@ -299,43 +368,38 @@ static hal_error_t hash_write_block(const internal_hash_state_t * const state) assert(state != NULL && state->descriptor != NULL && state->driver != NULL); assert(state->descriptor->block_length % 4 == 0); + assert(state->descriptor->digest_length <= sizeof(state->core_state) || + !state->descriptor->can_restore_state); + if (debug) fprintf(stderr, "[ %s ]\n", state->block_count == 0 ? "init" : "next"); - if ((err = hal_io_write(state->driver->block_addr, state->block, state->descriptor->block_length)) != HAL_OK) + if ((err = hal_io_wait_ready(state->driver->status_addr)) != HAL_OK) + return err; + + if (state->descriptor->can_restore_state && + state->block_count != 0 && + (err = hash_write_digest(state->driver, state->core_state, + state->descriptor->digest_length)) != HAL_OK) + return err; + + if ((err = hal_io_write(state->driver->block_addr, state->block, + state->descriptor->block_length)) != HAL_OK) return err; ctrl_cmd[0] = ctrl_cmd[1] = ctrl_cmd[2] = 0; ctrl_cmd[3] = state->block_count == 0 ? CTRL_INIT : CTRL_NEXT; ctrl_cmd[3] |= state->driver->ctrl_mode; - /* - * Not sure why we're waiting for ready here, but it's what the old - * (read: tested) code did, so keep that behavior for now. - */ - if ((err = hal_io_write(state->driver->ctrl_addr, ctrl_cmd, sizeof(ctrl_cmd))) != HAL_OK) return err; - return hal_io_wait_valid(state->driver->status_addr); -} - -/* - * Read hash result from core. - */ - -static hal_error_t hash_read_digest(const driver_t * const driver, - uint8_t *digest, - const size_t digest_length) -{ - hal_error_t err; - - assert(digest != NULL && digest_length % 4 == 0); - - if ((err = hal_io_wait_valid(driver->status_addr)) != HAL_OK) + if (state->descriptor->can_restore_state && + (err = hash_read_digest(state->driver, state->core_state, + state->descriptor->digest_length)) != HAL_OK) return err; - return hal_io_read(driver->digest_addr, digest, digest_length); + return hal_io_wait_valid(state->driver->status_addr); } /* @@ -485,15 +549,21 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor, { const driver_t * const driver = check_driver(descriptor); internal_hmac_state_t *state = state_buffer; - internal_hash_state_t *h = &state->hash_state; hal_hash_state_t oh; hal_error_t err; int i; - if (descriptor == NULL || driver == NULL || state == NULL || opaque_state == NULL || - state_length < descriptor->hmac_state_length) + if (driver == NULL || opaque_state == NULL) return HAL_ERROR_BAD_ARGUMENTS; + if (state_buffer != NULL && state_length < descriptor->hmac_state_length) + return HAL_ERROR_BAD_ARGUMENTS; + + if (state_buffer == NULL && (state = malloc(descriptor->hmac_state_length)) == NULL) + return HAL_ERROR_ALLOCATION_FAILURE; + + internal_hash_state_t *h = &state->hash_state; + assert(descriptor->block_length <= sizeof(state->keybuf)); #if 0 @@ -507,7 +577,10 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor, #endif if ((err = hal_hash_initialize(descriptor, &oh, h, sizeof(*h))) != HAL_OK) - return err; + goto fail; + + if (state_buffer == NULL) + h->flags |= STATE_FLAG_STATE_ALLOCATED; /* * If the supplied HMAC key is longer than the hash block length, we @@ -523,7 +596,7 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor, else if ((err = hal_hash_update(oh, key, key_length)) != HAL_OK || (err = hal_hash_finalize(oh, state->keybuf, sizeof(state->keybuf))) != HAL_OK || (err = hal_hash_initialize(descriptor, &oh, h, sizeof(*h))) != HAL_OK) - return err; + goto fail; /* * XOR the key with the IPAD value, then start the inner hash. @@ -533,7 +606,7 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor, state->keybuf[i] ^= HMAC_IPAD; if ((err = hal_hash_update(oh, state->keybuf, descriptor->block_length)) != HAL_OK) - return err; + goto fail; /* * Prepare the key for the final hash. Since we just XORed key with @@ -554,6 +627,35 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor, opaque_state->state = state; return HAL_OK; + + fail: + if (state_buffer == NULL) + free(state); + return err; +} + +/* + * Clean up HMAC state. No-op unless memory was dynamically allocated. + */ + +void hal_hmac_cleanup(hal_hmac_state_t *opaque_state) +{ + if (opaque_state == NULL) + return; + + internal_hmac_state_t *state = opaque_state->state; + + if (state == NULL) + return; + + internal_hash_state_t *h = &state->hash_state; + + if ((h->flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return; + + memset(state, 0, h->descriptor->hmac_state_length); + free(state); + opaque_state->state = NULL; } /* |