aboutsummaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2021-06-06 23:01:11 -0400
committerPaul Selkirk <paul@psgd.org>2021-06-07 15:37:06 -0400
commit8ef2a4e5f54c8623c98c396e378ec093629b849b (patch)
tree8b3d32e4af36dca5bb9b0ef36deb16067542364e /hash.c
parent93887dfe46225b4b7aafb63907ca26cce68c1510 (diff)
Add support for the SHA-3 core.
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c131
1 files changed, 99 insertions, 32 deletions
diff --git a/hash.c b/hash.c
index a496e87..06227af 100644
--- a/hash.c
+++ b/hash.c
@@ -5,7 +5,7 @@
*
* Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
* Copyright (c) 2014-2018, NORDUnet A/S All rights reserved.
- * Copyright: 2020, The Commons Conservancy Cryptech Project
+ * Copyright: 2020-2021, The Commons Conservancy Cryptech Project
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
@@ -18,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
@@ -120,7 +120,7 @@ struct hal_hash_state {
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 */
- core_state[HAL_MAX_HASH_DIGEST_LENGTH]; /* Saved core state */
+ core_state[HAL_MAX_HASH_STATE_LENGTH]; /* Saved core state */
size_t block_used; /* How much of the block we've used */
unsigned block_count; /* Blocks sent */
unsigned flags;
@@ -176,6 +176,10 @@ static const hal_hash_driver_t sha512_driver = {
SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, SHA512_MODE_SHA_512, sw_hash_core_sha512, sizeof(uint64_t)
};
+static const hal_hash_driver_t sha3_driver = {
+ SHA3_LENGTH_LEN, SHA3_ADDR_BLOCK, SHA3_ADDR_DIGEST, 0, NULL, 0
+};
+
/*
* Digest algorithm identifiers: DER encoded full TLV of an
* DigestAlgorithmIdentifier SEQUENCE including OID for the algorithm in
@@ -197,7 +201,11 @@ static const uint8_t
dalgid_sha512[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00 },
dalgid_sha224[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00 },
dalgid_sha512_224[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05, 0x00 },
- dalgid_sha512_256[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00 };
+ dalgid_sha512_256[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00 },
+ dalgid_sha3_224[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, 0x00 },
+ dalgid_sha3_256[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00 },
+ dalgid_sha3_384[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00 },
+ dalgid_sha3_512[] = { 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00 };
/*
* Descriptors. Yes, the {hash,hmac}_state_length fields are a bit
@@ -208,15 +216,15 @@ static const uint8_t
const hal_hash_descriptor_t hal_hash_sha1[1] = {{
HAL_DIGEST_ALGORITHM_SHA1,
- SHA1_BLOCK_LEN, SHA1_DIGEST_LEN,
+ SHA1_BLOCK_LEN, SHA1_DIGEST_LEN, SHA1_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha1, sizeof(dalgid_sha1),
- &sha1_driver, SHA1_NAME, 0
+ &sha1_driver, SHA1_NAME, 1
}};
const hal_hash_descriptor_t hal_hash_sha224[1] = {{
HAL_DIGEST_ALGORITHM_SHA256,
- SHA256_BLOCK_LEN, SHA224_DIGEST_LEN,
+ SHA256_BLOCK_LEN, SHA224_DIGEST_LEN, SHA224_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha224, sizeof(dalgid_sha224),
&sha224_driver, SHA256_NAME, 1
@@ -224,7 +232,7 @@ const hal_hash_descriptor_t hal_hash_sha224[1] = {{
const hal_hash_descriptor_t hal_hash_sha256[1] = {{
HAL_DIGEST_ALGORITHM_SHA256,
- SHA256_BLOCK_LEN, SHA256_DIGEST_LEN,
+ SHA256_BLOCK_LEN, SHA256_DIGEST_LEN, SHA256_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha256, sizeof(dalgid_sha256),
&sha256_driver, SHA256_NAME, 1
@@ -232,7 +240,7 @@ const hal_hash_descriptor_t hal_hash_sha256[1] = {{
const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{
HAL_DIGEST_ALGORITHM_SHA512_224,
- SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN,
+ SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN, SHA512_224_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_224, sizeof(dalgid_sha512_224),
&sha512_224_driver, SHA512_NAME, 1
@@ -240,7 +248,7 @@ const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{
const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{
HAL_DIGEST_ALGORITHM_SHA512_256,
- SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN,
+ SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN, SHA512_256_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_256, sizeof(dalgid_sha512_256),
&sha512_256_driver, SHA512_NAME, 1
@@ -248,7 +256,7 @@ const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{
const hal_hash_descriptor_t hal_hash_sha384[1] = {{
HAL_DIGEST_ALGORITHM_SHA384,
- SHA512_BLOCK_LEN, SHA384_DIGEST_LEN,
+ SHA512_BLOCK_LEN, SHA384_DIGEST_LEN, SHA384_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha384, sizeof(dalgid_sha384),
&sha384_driver, SHA512_NAME, 1
@@ -256,12 +264,58 @@ const hal_hash_descriptor_t hal_hash_sha384[1] = {{
const hal_hash_descriptor_t hal_hash_sha512[1] = {{
HAL_DIGEST_ALGORITHM_SHA512,
- SHA512_BLOCK_LEN, SHA512_DIGEST_LEN,
+ SHA512_BLOCK_LEN, SHA512_DIGEST_LEN, SHA512_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512, sizeof(dalgid_sha512),
&sha512_driver, SHA512_NAME, 1
}};
+const hal_hash_descriptor_t hal_hash_sha3_224[1] = {{
+ HAL_DIGEST_ALGORITHM_SHA3_224,
+ SHA3_224_BLOCK_LEN, SHA3_224_DIGEST_LEN, SHA3_STATE_LEN,
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
+ dalgid_sha3_224, sizeof(dalgid_sha3_224),
+ &sha3_driver, SHA3_NAME, 1
+}};
+
+const hal_hash_descriptor_t hal_hash_sha3_256[1] = {{
+ HAL_DIGEST_ALGORITHM_SHA3_256,
+ SHA3_256_BLOCK_LEN, SHA3_256_DIGEST_LEN, SHA3_STATE_LEN,
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
+ dalgid_sha3_256, sizeof(dalgid_sha3_256),
+ &sha3_driver, SHA3_NAME, 1
+}};
+
+const hal_hash_descriptor_t hal_hash_sha3_384[1] = {{
+ HAL_DIGEST_ALGORITHM_SHA3_384,
+ SHA3_384_BLOCK_LEN, SHA3_384_DIGEST_LEN, SHA3_STATE_LEN,
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
+ dalgid_sha3_384, sizeof(dalgid_sha3_384),
+ &sha3_driver, SHA3_NAME, 1
+}};
+
+const hal_hash_descriptor_t hal_hash_sha3_512[1] = {{
+ HAL_DIGEST_ALGORITHM_SHA3_512,
+ SHA3_512_BLOCK_LEN, SHA3_512_DIGEST_LEN, SHA3_STATE_LEN,
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
+ dalgid_sha3_512, sizeof(dalgid_sha3_512),
+ &sha3_driver, SHA3_NAME, 1
+}};
+
+static inline int is_sha3(hal_hash_state_t *state)
+{
+ switch (state->descriptor->digest_algorithm) {
+ case HAL_DIGEST_ALGORITHM_SHA3_224:
+ case HAL_DIGEST_ALGORITHM_SHA3_256:
+ case HAL_DIGEST_ALGORITHM_SHA3_384:
+ case HAL_DIGEST_ALGORITHM_SHA3_512:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
/*
* Static state blocks. This library is intended for a style of
* embedded programming in which one avoids heap-based allocation
@@ -545,7 +599,6 @@ static hal_error_t hash_write_block(hal_hash_state_t * const state)
#endif
#if ! HAL_ONLY_USE_SOFTWARE_HASH_CORES
- uint8_t ctrl_cmd[4];
hal_error_t err;
if ((err = hal_io_wait_ready(state->core)) != HAL_OK)
@@ -554,23 +607,29 @@ static hal_error_t hash_write_block(hal_hash_state_t * const state)
if (state->descriptor->can_restore_state &&
state->block_count != 0 &&
(err = hash_write_digest(state->core, state->driver, state->core_state,
- state->descriptor->digest_length)) != HAL_OK)
+ state->descriptor->state_length)) != HAL_OK)
return err;
if ((err = hal_io_write(state->core, state->driver->block_addr, state->block,
+ is_sha3(state) ? state->descriptor->state_length :
state->descriptor->block_length)) != HAL_OK)
return err;
- ctrl_cmd[0] = ctrl_cmd[1] = ctrl_cmd[2] = 0;
+ uint8_t ctrl_cmd[4] = {0};
+
+ /* reset the control register */
+ if ((err = hal_io_write(state->core, ADDR_CTRL, ctrl_cmd, sizeof(ctrl_cmd))) != HAL_OK)
+ return err;
+
+ /* write the init or next command */
ctrl_cmd[3] = state->block_count == 0 ? CTRL_INIT : CTRL_NEXT;
ctrl_cmd[3] |= state->driver->ctrl_mode;
-
if ((err = hal_io_write(state->core, ADDR_CTRL, ctrl_cmd, sizeof(ctrl_cmd))) != HAL_OK)
return err;
if (state->descriptor->can_restore_state &&
(err = hash_read_digest(state->core, state->driver, state->core_state,
- state->descriptor->digest_length)) != HAL_OK)
+ state->descriptor->state_length)) != HAL_OK)
return err;
return hal_io_wait_valid(state->core);
@@ -657,7 +716,6 @@ hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaqu
uint8_t *digest_buffer, /* Returned digest */
const size_t digest_buffer_length) /* Length of digest_buffer */
{
- uint64_t bit_length_high, bit_length_low;
hal_error_t err;
uint8_t *p;
size_t n;
@@ -687,12 +745,12 @@ hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaqu
* Add padding, then pull result from the core
*/
- bit_length_low = (state->msg_length_low << 3);
- bit_length_high = (state->msg_length_high << 3) | (state->msg_length_low >> 61);
-
- /* Initial pad byte */
- hal_assert(state->block_used < state->descriptor->block_length);
- state->block[state->block_used++] = 0x80;
+ /* Initial pad byte.
+ * SHA-3 appends an instance ID (01) to the message before padding,
+ * so the effective start of padding is 011. Except that it uses
+ * little-endian bit ordering, so it's xxxxx110. WTF.
+ */
+ state->block[state->block_used++] = is_sha3(state) ? 0x06 : 0x80;
/* If not enough room for bit count, zero and push current block */
if ((n = state->descriptor->block_length - state->block_used) < state->driver->length_length) {
@@ -716,12 +774,21 @@ hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaqu
hal_log(HAL_LOG_DEBUG, "[ Final block, used %lu, n %lu, msg_length %llu ]\n",
(unsigned long) state->block_used, (unsigned long) n, (unsigned long long)state->msg_length_low);
p = state->block + state->descriptor->block_length;
- for (i = 0; (bit_length_low || bit_length_high) && i < state->driver->length_length; i++) {
- *--p = (uint8_t) (bit_length_low & 0xFF);
- bit_length_low >>= 8;
- if (bit_length_high) {
- bit_length_low |= ((bit_length_high & 0xFF) << 56);
- bit_length_high >>= 8;
+ if (is_sha3(state)) {
+ /* SHA-3 ends padding with a single 1 bit, rather than message length. */
+ *--p |= 0x80;
+ }
+ else {
+ uint64_t bit_length_low = (state->msg_length_low << 3);
+ uint64_t bit_length_high = (state->msg_length_high << 3) | (state->msg_length_low >> 61);
+
+ for (i = 0; (bit_length_low || bit_length_high) && i < state->driver->length_length; i++) {
+ *--p = (uint8_t) (bit_length_low & 0xFF);
+ bit_length_low >>= 8;
+ if (bit_length_high) {
+ bit_length_low |= ((bit_length_high & 0xFF) << 56);
+ bit_length_high >>= 8;
+ }
}
}