From e0127e7fe2f6c9f3c138eefc1805c50d3a012871 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 12 Dec 2024 13:45:50 +0000 Subject: [PATCH] [ot] hw/opentitan: ot_hmac: Add HMAC SHA-2 384/512 & key size support This commit introduces full support for using the SHA-2 384 and SHA-2 512 algorithms for hashing alongside the existing SHA-2 256 algorithm, by setting the `digest_size` field in the configuration register. It likewise adds support for using a range of key sizes (128/256/384/512/ 1024), and not just always using a 512 bit key - this is set in the `key_length` field in the configuration register. The existing tomcrypt library is used to support the additional hash functionality, which uses `sha512` functionality for both sha384 and sha512 in its implementation. --- hw/opentitan/ot_hmac.c | 143 +++++++++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 18 deletions(-) diff --git a/hw/opentitan/ot_hmac.c b/hw/opentitan/ot_hmac.c index 0ef05d292054..17d252441525 100644 --- a/hw/opentitan/ot_hmac.c +++ b/hw/opentitan/ot_hmac.c @@ -407,16 +407,97 @@ static void ot_hmac_writeback_digest_state(OtHMACState *s) { /* copy intermediary digest to mock HMAC operation for stop/continue behaviour. */ - /* TODO: add support for SHA2-384 and SHA2-512 */ - for (unsigned i = 0; i < 8u; i++) { - STORE32H(s->ctx->state.sha256.state[i], s->regs->digest + i); + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + for (unsigned idx = 0; idx < 8u; idx++) { + STORE32H(s->ctx->state.sha256.state[idx], s->regs->digest + idx); + } + break; + case HMAC_SHA2_384: + /* Even though SHA384 only uses the first six uint64_t values of + the SHA512 digest, we must store them all for intermediary + computation. */ + case HMAC_SHA2_512: + for (unsigned idx = 0; idx < 8u; idx++) { + STORE64H(s->ctx->state.sha512.state[idx], + s->regs->digest + 2 * idx); + } + break; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when calling start / + continue to begin operation. */ + g_assert_not_reached(); + } +} + +static void ot_hmac_restore_context(OtHMACState *s) +{ + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + s->ctx->state.sha256.curlen = 0; + s->ctx->state.sha256.length = s->regs->msg_length; + for (unsigned idx = 0; idx < 8u; idx++) { + s->ctx->state.sha256.state[idx] = s->regs->digest[idx]; + } + break; + case HMAC_SHA2_384: + /* Even though SHA384 only uses the first six uint64_t values of + the SHA512 digest, we must restore them all for intermediary + computation. */ + case HMAC_SHA2_512: + s->ctx->state.sha512.curlen = 0; + s->ctx->state.sha512.length = s->regs->msg_length; + for (unsigned idx = 0; idx < 8u; idx++) { + s->ctx->state.sha512.state[idx] = + ((uint64_t)s->regs->digest[idx + 1] << 32u) | + s->regs->digest[idx]; + } + break; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when receiving the + continue command to (re-)begin operation. */ + g_assert_not_reached(); + } +} + +static size_t ot_hmac_get_curlen(OtHMACState *s) +{ + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + return s->ctx->state.sha256.curlen; + case HMAC_SHA2_384: + case HMAC_SHA2_512: + return s->ctx->state.sha512.curlen; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when calling start / + continue to begin operation. */ + g_assert_not_reached(); + return 0u; } } static void ot_hmac_sha_init(OtHMACState *s, bool write_back) { - /* TODO: add support for SHA2-384 and SHA2-512 */ - sha256_init(&s->ctx->state); + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + sha256_init(&s->ctx->state); + break; + case HMAC_SHA2_384: + sha384_init(&s->ctx->state); + break; + case HMAC_SHA2_512: + sha512_init(&s->ctx->state); + break; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when calling start / + continue to begin operation. */ + g_assert_not_reached(); + return; + } if (write_back) { ot_hmac_writeback_digest_state(s); } @@ -425,8 +506,24 @@ static void ot_hmac_sha_init(OtHMACState *s, bool write_back) static void ot_hmac_sha_process(OtHMACState *s, const uint8_t *in, size_t inlen, bool write_back) { - /* TODO: add support for SHA2-384 and SHA2-512 */ - sha256_process(&s->ctx->state, in, inlen); + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + sha256_process(&s->ctx->state, in, inlen); + break; + /* NOLINTNEXTLINE */ + case HMAC_SHA2_384: + sha384_process(&s->ctx->state, in, inlen); + break; + case HMAC_SHA2_512: + sha512_process(&s->ctx->state, in, inlen); + break; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when calling start / + continue to begin operation. */ + g_assert_not_reached(); + return; + } if (write_back) { ot_hmac_writeback_digest_state(s); } @@ -434,8 +531,23 @@ static void ot_hmac_sha_process(OtHMACState *s, const uint8_t *in, size_t inlen, static void ot_hmac_sha_done(OtHMACState *s) { - /* TODO: add support for SHA2-384 and SHA2-512 */ - sha256_done(&s->ctx->state, (uint8_t *)s->regs->digest); + switch (ot_hmac_get_digest_size(s->regs->cfg)) { + case HMAC_SHA2_256: + sha256_done(&s->ctx->state, (uint8_t *)s->regs->digest); + return; + case HMAC_SHA2_384: + sha384_done(&s->ctx->state, (uint8_t *)s->regs->digest); + return; + case HMAC_SHA2_512: + sha512_done(&s->ctx->state, (uint8_t *)s->regs->digest); + return; + case HMAC_SHA2_NONE: + default: + /* should never happen: digest size was validated when calling start / + continue to begin operation. */ + g_assert_not_reached(); + return; + } } static void ot_hmac_compute_digest(OtHMACState *s) @@ -473,9 +585,9 @@ static void ot_hmac_process_fifo(OtHMACState *s) bool stop = s->regs->cmd & R_CMD_HASH_STOP_MASK; if (!fifo8_is_empty(&s->input_fifo) && - (!stop || s->ctx->state.sha256.curlen != 0)) { + (!stop || ot_hmac_get_curlen(s) != 0)) { while (!fifo8_is_empty(&s->input_fifo) && - (!stop || s->ctx->state.sha256.curlen != 0)) { + (!stop || ot_hmac_get_curlen(s) != 0)) { uint8_t value = fifo8_pop(&s->input_fifo); ot_hmac_sha_process(s, &value, 1u, false); } @@ -491,7 +603,7 @@ static void ot_hmac_process_fifo(OtHMACState *s) } } - if (stop && s->ctx->state.sha256.curlen == 0) { + if (stop && ot_hmac_get_curlen(s) == 0) { s->regs->intr_state |= INTR_HMAC_DONE_MASK; s->regs->cmd = 0; } @@ -867,12 +979,7 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value, s->regs->cmd = R_CMD_HASH_CONTINUE_MASK; - /* Restore SHA256 context */ - s->ctx->state.sha256.curlen = 0; - s->ctx->state.sha256.length = s->regs->msg_length; - for (unsigned i = 0; i < 8u; i++) { - s->ctx->state.sha256.state[i] = s->regs->digest[i]; - } + ot_hmac_restore_context(s); /* trigger delayed processing of FIFO */ ibex_irq_set(&s->clkmgr, true);