Skip to content

Commit

Permalink
[ot] hw/opentitan: ot_hmac: Add HMAC SHA-2 384/512 & key size support
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AlexJones0 committed Dec 12, 2024
1 parent b2ab5f3 commit c430660
Showing 1 changed file with 130 additions and 18 deletions.
148 changes: 130 additions & 18 deletions hw/opentitan/ot_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,16 +399,101 @@ 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:
qemu_log_mask(
LOG_GUEST_ERROR,
"%s: Cannot write back digest when no valid digest size is set. \n",
__func__);
}
}

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:
qemu_log_mask(
LOG_GUEST_ERROR,
"%s: Cannot restore digest when no valid digest size is set. \n",
__func__);
}
}

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:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Cannot get the current hash length when no valid "
"digest size is set. \n",
__func__);
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:
qemu_log_mask(
LOG_GUEST_ERROR,
"%s: Cannot initialise digest when no valid digest size is set. \n",
__func__);
return;
}
if (write_back) {
ot_hmac_writeback_digest_state(s);
}
Expand All @@ -417,17 +502,49 @@ 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;
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:
qemu_log_mask(
LOG_GUEST_ERROR,
"%s: Cannot process the hash when no valid digest size is set. \n",
__func__);
return;
}
if (write_back) {
ot_hmac_writeback_digest_state(s);
}
}

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:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Cannot terminate the hash when no valid digest size "
"is set. \n",
__func__);
return;
}
}

static void ot_hmac_compute_digest(OtHMACState *s)
Expand Down Expand Up @@ -465,9 +582,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);
}
Expand All @@ -483,7 +600,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;
}
Expand Down Expand Up @@ -858,12 +975,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);
Expand Down

0 comments on commit c430660

Please sign in to comment.