Skip to content

Commit

Permalink
hw/misc: implement ESP32-C3 HMAC
Browse files Browse the repository at this point in the history
Added an internal HMAC implementation using the existing internal SHA APIs
  • Loading branch information
Harshal5 authored and igrr committed Dec 6, 2023
1 parent 6afa33b commit 41d1b9a
Show file tree
Hide file tree
Showing 6 changed files with 494 additions and 1 deletion.
90 changes: 90 additions & 0 deletions crypto/hmac256-internal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* HMAC-SHA-224/256/384/512 implementation
* Last update: 06/15/2005
* Issue date: 06/15/2005
*
* Copyright (C) 2005 Olivier Gay <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project 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 PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <string.h>

#include "hmac256_i.h"


void hmac_sha256_init(struct hmac_sha256_ctx *ctx, const uint8_t *key,
uint32_t key_size)
{
uint32_t fill = SHA256_BLOCK_SIZE - key_size;

uint8_t block_ipad[SHA256_BLOCK_SIZE];
uint8_t block_opad[SHA256_BLOCK_SIZE];

memset(block_ipad + key_size, 0x36, fill);
memset(block_opad + key_size, 0x5c, fill);

for (int i = 0; i < (int) key_size; i++) {
block_ipad[i] = key[i] ^ 0x36;
block_opad[i] = key[i] ^ 0x5c;
}

sha256_init(&ctx->ctx_inside);
sha256_compress(&ctx->ctx_inside, block_ipad);

sha256_init(&ctx->ctx_outside);
sha256_compress(&ctx->ctx_outside, block_opad);
}

void hmac_sha256_update(struct hmac_sha256_ctx *ctx, uint8_t *message)
{
sha256_compress(&ctx->ctx_inside, message);
}


static inline void write32_be(uint32_t n, uint8_t out[4])
{
*(uint32_t *)(out) = __builtin_bswap32(n);
}


void hmac_sha256_final(struct hmac_sha256_ctx *ctx, uint8_t *mac,
uint32_t mac_size)
{
uint8_t block[SHA256_BLOCK_SIZE] = {0};
for(int i = 0 ; i < 8; i++) {
write32_be(ctx->ctx_inside.state[i], block + i * 4);
}
// As the "ctx_inside" state will be the input of the SHA operation over "ctx_outside"
// we need to pad the "ctx_inside" state because `sha256_compress` expects a padded input
uint64_t bit_len = __builtin_bswap64(SHA256_DIGEST_SIZE * 8 + 512);
block[SHA256_DIGEST_SIZE] = 0x80;
memset(block + SHA256_DIGEST_SIZE + 1, 0, SHA256_BLOCK_SIZE - SHA256_DIGEST_SIZE - 1);
memcpy(block + SHA256_BLOCK_SIZE - sizeof(bit_len), &bit_len, sizeof(bit_len));

sha256_compress(&ctx->ctx_outside, block);
memcpy(mac, ctx->ctx_outside.state, SHA256_DIGEST_SIZE);
}
52 changes: 52 additions & 0 deletions crypto/hmac256_i.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* HMAC-SHA-224/256/384/512 implementation
* Last update: 06/15/2005
* Issue date: 06/15/2005
*
* Copyright (C) 2005 Olivier Gay <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project 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 PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#ifndef HMAC256_I_H
#define HMAC256_I_H

#include "qemu/osdep.h"
#include "sha256_i.h"

#define SHA256_DIGEST_SIZE 32
#define SHA256_BLOCK_SIZE 64

struct hmac_sha256_ctx {
struct sha256_state ctx_inside;
struct sha256_state ctx_outside;
};

void hmac_sha256_init(struct hmac_sha256_ctx *ctx, const uint8_t *key, unsigned int key_size);
void hmac_sha256_update(struct hmac_sha256_ctx *ctx, uint8_t *message);
void hmac_sha256_final(struct hmac_sha256_ctx *ctx, uint8_t *mac, unsigned int mac_size);

#endif /* HMAC256_I_H */
1 change: 1 addition & 0 deletions crypto/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ util_ss.add(files('sha384-internal.c'))
util_ss.add(files('sha256-internal.c'))
util_ss.add(files('sha224-internal.c'))
util_ss.add(files('sha1-internal.c'))
util_ss.add(files('hmac256-internal.c'))
util_ss.add(files('init.c'))
if gnutls.found()
util_ss.add(gnutls)
Expand Down
216 changes: 216 additions & 0 deletions hw/misc/esp32c3_hmac.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* ESP32-C3 HMAC emulation
*
* Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or
* (at your option) any later version.
*/

#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/misc/esp32c3_hmac.h"
#include "hw/nvram/esp32c3_efuse.h"
#include "qemu/bswap.h"
#include "qemu/error-report.h"

#define HMAC_WARNING 0
#define HMAC_DEBUG 0

static void esp32c3_hmac_start(ESP32C3HmacState *s)
{
uint8_t efuse_key[32];
esp32c3_efuse_get_key(s->efuse, s->efuse_block_num, efuse_key);
hmac_sha256_init(&s->ctx, efuse_key, sizeof(efuse_key));
s->message_write_complete = 0;
}


static void esp32c3_hmac_update(ESP32C3HmacState *s, uint32_t *message)
{
hmac_sha256_update(&s->ctx, (uint8_t*)(message));
}


static void esp32c3_hmac_finish(ESP32C3HmacState *s, uint32_t *result)
{
hmac_sha256_final(&s->ctx, (uint8_t*) result, sizeof(result));
}


static uint64_t esp32c3_hmac_read(void *opaque, hwaddr addr, unsigned int size)
{
ESP32C3HmacState *s = ESP32C3_HMAC(opaque);

uint64_t r = 0;
switch (addr) {
case A_HMAC_DATE_REG:
r = 0x20200618;
break;

case A_HMAC_QUERY_ERROR_REG:
r = esp32c3_efuse_get_key_purpose(s->efuse, s->efuse_block_num) == s->efuse_key_purpose ? 0 : 1;
break;

case A_HMAC_QUERY_BUSY_REG:
r = 0;
break;

case A_HMAC_RD_RESULT_0_REG ... A_HMAC_RD_RESULT_7_REG:
r = be32_to_cpu(s->result[(addr - A_HMAC_RD_RESULT_0_REG) / sizeof(uint32_t)]);
break;

default:
#if HMAC_WARNING
/* Other registers are not supported yet */
warn_report("[HMAC] Unsupported read to %08lx\n", addr);
#endif
break;
}

#if HMAC_DEBUG
info_report("[HMAC] Reading from %08lx (%08lx)\n", addr, r);
#endif

return r;
}


static void esp32c3_hmac_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
ESP32C3HmacClass *class = ESP32C3_HMAC_GET_CLASS(opaque);
ESP32C3HmacState *s = ESP32C3_HMAC(opaque);

switch (addr) {
case A_HMAC_SET_START_REG:
break;

case A_HMAC_SET_PARA_FINISH_REG:
esp32c3_hmac_start(s);
break;

case A_HMAC_SET_MESSAGE_ONE_REG:
class->hmac_update(s, s->message);
if(s->message_write_complete) {
class->hmac_finish(s, s->result);
}
break;

case A_HMAC_SET_MESSAGE_ING_REG:
break;

case A_HMAC_SET_RESULT_FINISH_REG:
memset(s->result, 0, sizeof(s->result));
break;

case A_HMAC_SET_INVALIDATE_JTAG_REG:
break;

case A_HMAC_SET_INVALIDATE_DS_REG:
break;

case A_HMAC_SET_PARA_PURPOSE_REG:
s->efuse_key_purpose = FIELD_EX32(value, HMAC_SET_PARA_PURPOSE_REG, HMAC_PURPOSE_SET);
break;

case A_HMAC_SET_PARA_KEY_REG:
s->efuse_block_num = EFUSE_BLOCK_KEY0 + FIELD_EX32(value, HMAC_SET_PARA_KEY_REG, HMAC_KEY_SET);
break;

case A_HMAC_WR_MESSAGE_0_REG ... A_HMAC_WR_MESSAGE_15_REG:
s->message[(addr - A_HMAC_WR_MESSAGE_0_REG) / sizeof(uint32_t)] = value;
break;

case A_HMAC_SET_MESSAGE_PAD_REG:
s->message_write_complete = 1;
break;

case A_HMAC_ONE_BLOCK_REG:
s->message_write_complete = 1;
esp32c3_hmac_finish(s, s->result);
break;

case A_HMAC_SET_MESSAGE_END_REG:
case A_HMAC_SOFT_JTAG_CTRL_REG:
case A_HMAC_WR_JTAG_REG:
default:
#if HMAC_WARNING
/* Other registers are not supported yet */
warn_report("[HMAC] Unsupported write to %08lx (%08lx)\n", addr, value);
#endif
break;
}

#if HMAC_DEBUG
info_report("[HMAC] Writing to %08lx (%08lx)\n", addr, value);
#endif

}


static const MemoryRegionOps esp32c3_hmac_ops = {
.read = esp32c3_hmac_read,
.write = esp32c3_hmac_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};

static void esp32c3_hmac_reset(DeviceState *dev)
{
ESP32C3HmacState *s = ESP32C3_HMAC(dev);
memset(s->message, 0, sizeof(s->message));
memset(s->result, 0, sizeof(s->result));

s->efuse_block_num = 0;
s->efuse_key_purpose = 0;
s->message_write_complete = 0;
}

static void esp32c3_hmac_realize(DeviceState *dev, Error **errp)
{
ESP32C3HmacState *s = ESP32C3_HMAC(dev);

/* Make sure Efuse was set of issue an error */
if (s->efuse == NULL) {
error_report("[HMAC] Efuse controller must be set!");
}
}

static void esp32c3_hmac_init(Object *obj)
{
ESP32C3HmacState *s = ESP32C3_HMAC(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);

memory_region_init_io(&s->iomem, obj, &esp32c3_hmac_ops, s,
TYPE_ESP32C3_HMAC, ESP32C3_HMAC_REGS_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}

static void esp32c3_hmac_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ESP32C3HmacClass* esp32c3_hmac = ESP32C3_HMAC_CLASS(klass);

dc->realize = esp32c3_hmac_realize;
dc->reset = esp32c3_hmac_reset;

esp32c3_hmac->hmac_update = esp32c3_hmac_update;
esp32c3_hmac->hmac_finish = esp32c3_hmac_finish;
}

static const TypeInfo esp32c3_hmac_info = {
.name = TYPE_ESP32C3_HMAC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ESP32C3HmacState),
.instance_init = esp32c3_hmac_init,
.class_init = esp32c3_hmac_class_init,
.class_size = sizeof(ESP32C3HmacClass)
};

static void esp32c3_hmac_register_types(void)
{
type_register_static(&esp32c3_hmac_info);
}

type_init(esp32c3_hmac_register_types)
3 changes: 2 additions & 1 deletion hw/misc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ system_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files(
'esp32c3_cache.c',
'esp32c3_sha.c',
'esp32c3_jtag.c',
'esp32c3_rtc_cntl.c'
'esp32c3_rtc_cntl.c',
'esp32c3_hmac.c'
))

if gcrypt.found()
Expand Down
Loading

0 comments on commit 41d1b9a

Please sign in to comment.