CC3XX: Add DRBGs (CTR, HMAC, HASH)
Verified through some of the vectors available in the DRBGVS set.
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: Ib1c864f6c866e0c06fce29d6c8abfec1b39bc0ac
diff --git a/platform/ext/accelerator/cc312/cc312-rom/CMakeLists.txt b/platform/ext/accelerator/cc312/cc312-rom/CMakeLists.txt
index 16a273c..e789524 100644
--- a/platform/ext/accelerator/cc312/cc312-rom/CMakeLists.txt
+++ b/platform/ext/accelerator/cc312/cc312-rom/CMakeLists.txt
@@ -22,6 +22,11 @@
./cc3xx_kdf.c
./cc3xx_pka.c
./cc3xx_poly1305.c
+ ./cc3xx_hmac.c
+ ./cc3xx_drbg_ctr.c
+ ./cc3xx_drbg_hash.c
+ ./cc3xx_drbg_hmac.c
+ ./cc3xx_drbg.c
)
target_include_directories(cc312_rom
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.c b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.c
new file mode 100644
index 0000000..59399b2
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+#include "cc3xx_drbg.h"
+#include "cc3xx_config.h"
+
+cc3xx_err_t cc3xx_drbg_init(
+ cc3xx_drbg_id_t id,
+ struct cc3xx_drbg_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len)
+{
+ assert(id < CC3XX_DRBG_MAX);
+
+ state->id = id;
+
+ switch(id) {
+#ifdef CC3XX_CONFIG_DRBG_CTR_ENABLE
+ case CC3XX_DRBG_CTR:
+ return cc3xx_drbg_ctr_init(
+ &state->ctr,
+ entropy, entropy_len,
+ nonce, nonce_len,
+ personalization, personalization_len);
+#endif /* CC3XX_CONFIG_DRBG_CTR_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HMAC_ENABLE
+ case CC3XX_DRBG_HMAC:
+ return cc3xx_drbg_hmac_instantiate(
+ &state->hmac,
+ entropy, entropy_len,
+ nonce, nonce_len,
+ personalization, personalization_len);
+#endif /* CC3XX_CONFIG_DRBG_HMAC_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HASH_ENABLE
+ case CC3XX_DRBG_HASH:
+ return cc3xx_drbg_hash_init(
+ &state->hash,
+ entropy, entropy_len,
+ nonce, nonce_len,
+ personalization, personalization_len);
+#endif /* CC3XX_CONFIG_DRBG_HASH_ENABLE */
+ default:
+ return CC3XX_ERR_DRBG_INVALID_ID;
+ }
+}
+
+cc3xx_err_t cc3xx_drbg_generate(
+ struct cc3xx_drbg_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ switch(state->id) {
+#ifdef CC3XX_CONFIG_DRBG_CTR_ENABLE
+ case CC3XX_DRBG_CTR:
+ return cc3xx_drbg_ctr_generate(
+ &state->ctr, len_bits, returned_bits, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_CTR_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HMAC_ENABLE
+ case CC3XX_DRBG_HMAC:
+ return cc3xx_drbg_hmac_generate(
+ &state->hmac, len_bits, returned_bits, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_HMAC_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HASH_ENABLE
+ case CC3XX_DRBG_HASH:
+ return cc3xx_drbg_hash_generate(
+ &state->hash, len_bits, returned_bits, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_HASH_ENABLE */
+ default:
+ return CC3XX_ERR_DRBG_INVALID_ID;
+ }
+}
+
+cc3xx_err_t cc3xx_drbg_reseed(
+ struct cc3xx_drbg_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ switch(state->id) {
+#ifdef CC3XX_CONFIG_DRBG_CTR_ENABLE
+ case CC3XX_DRBG_CTR:
+ return cc3xx_drbg_ctr_reseed(
+ &state->ctr, entropy, entropy_len, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_CTR_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HMAC_ENABLE
+ case CC3XX_DRBG_HMAC:
+ return cc3xx_drbg_hmac_reseed(
+ &state->hmac, entropy, entropy_len, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_HMAC_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HASH_ENABLE
+ case CC3XX_DRBG_HASH:
+ return cc3xx_drbg_hash_reseed(
+ &state->hash, entropy, entropy_len, additional_input, additional_input_len);
+#endif /* CC3XX_CONFIG_DRBG_HASH_ENABLE */
+ default:
+ return CC3XX_ERR_DRBG_INVALID_ID;
+ }
+}
+
+cc3xx_err_t cc3xx_drbg_uninit(struct cc3xx_drbg_state_t *state)
+{
+ switch(state->id) {
+#ifdef CC3XX_CONFIG_DRBG_CTR_ENABLE
+ case CC3XX_DRBG_CTR:
+ return cc3xx_drbg_ctr_uninit(&state->ctr);
+#endif /* CC3XX_CONFIG_DRBG_CTR_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HMAC_ENABLE
+ case CC3XX_DRBG_HMAC:
+ return cc3xx_drbg_hmac_uninit(&state->hmac);
+#endif /* CC3XX_CONFIG_DRBG_HMAC_ENABLE */
+#ifdef CC3XX_CONFIG_DRBG_HASH_ENABLE
+ case CC3XX_DRBG_HASH:
+ return cc3xx_drbg_hash_uninit(&state->hash);
+#endif /* CC3XX_CONFIG_DRBG_HASH_ENABLE */
+ default:
+ return CC3XX_ERR_DRBG_INVALID_ID;
+ }
+}
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.h
new file mode 100644
index 0000000..1852906
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CC3XX_DRBG_H__
+#define __CC3XX_DRBG_H__
+
+/**
+ * @file Contains a generic interface towards a DRBG mechanism that
+ * can be chosen at runtime during the instantiation phase of
+ * the DRBG, i.e. when calling cc3xx_drbg_init()
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "cc3xx_error.h"
+#include "cc3xx_config.h"
+
+#include "cc3xx_drbg_ctr.h"
+#include "cc3xx_drbg_hash.h"
+#include "cc3xx_drbg_hmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief This enum defines which DRBG mechanism to use. Allowed
+ * values are CC3XX_DRBG_CTR, CC3XX_DRBG_HASH, CC3XX_DRBG_HMAC
+ */
+typedef enum {
+ CC3XX_DRBG_CTR = 0,
+ CC3XX_DRBG_HMAC,
+ CC3XX_DRBG_HASH,
+ CC3XX_DRBG_MAX = CC3XX_DRBG_HASH + 1,
+} cc3xx_drbg_id_t;
+
+/**
+ * @brief Generic context for a DRBG generator
+ *
+ */
+struct cc3xx_drbg_state_t {
+ cc3xx_drbg_id_t id;
+ union {
+ struct cc3xx_drbg_ctr_state_t ctr;
+ struct cc3xx_drbg_hmac_state_t hmac;
+ struct cc3xx_drbg_hash_state_t hash;
+ };
+};
+
+/**
+ * @brief Instantiate the DRBG
+ *
+ * @param id The ID of the DRBG to instantiate, of type \ref cc3xx_drbg_id_t
+ * @param state A pointer to a state structure
+ * @param entropy Buffer containing the entropy for the instantiation
+ * @param entropy_len Size in bytes of the entropy buffer \param entropy
+ * @param nonce Buffer containing the nonce
+ * @param nonce_len Size in bytes of the nonce buffer \param nonce
+ * @param personalization Buffer containing the personalization string
+ * @param personalization_len Size in bytes of the personalization buffer \param personalization
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_init(
+ cc3xx_drbg_id_t id,
+ struct cc3xx_drbg_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len);
+
+/**
+ * @brief Generates random bits from the DRBG instance
+ *
+ * @param state Pointer to an instantiated DRBG generator
+ * @param len_bits Size in bits to be generated. Must be byte aligned for simplicity
+ * @param returned_bits Pointer holding the returned random bit string
+ * @param additional_input Pointer to the additional input to be used
+ * @param additional_input_len Size in bytes of the additional input to be used
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_generate(
+ struct cc3xx_drbg_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Reseeds the DRBG
+ *
+ * @param state A pointer to a state structure
+ * @param entropy Entropy to be used for reseeding
+ * @param entropy_len Size in bytes of the entropy pointed by \param entropy
+ * @param additional_input Optional pointer containing additional input for reseeding
+ * @param additional_input_len Size in bytes of the buffer pointed by \param additional_input
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_reseed(
+ struct cc3xx_drbg_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Un-initializes the state structure associated to the underlying DRBG
+ *
+ * @param state Pointer to the structure
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_uninit(struct cc3xx_drbg_state_t *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CC3XX_DRBG_H__ */
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.c b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.c
new file mode 100644
index 0000000..eda5f46
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include "cc3xx_pka.h"
+#include "cc3xx_endian_helpers.h"
+#include "cc3xx_drbg_ctr.h"
+#include "cc3xx_rng.h"
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+#include "cc3xx_stdlib.h"
+#endif
+
+static void long_inc_int(uint32_t *acc, size_t acc_size, bool is_increment)
+{
+ cc3xx_pka_reg_id_t r0;
+ assert(acc_size == CC3XX_DRBG_CTR_BLOCKLEN);
+
+ /* Accumulation happen only on 128 bit accumulators */
+ cc3xx_pka_init(CC3XX_DRBG_CTR_BLOCKLEN);
+
+ /* Allocate a register among those not in use, given configured size */
+ r0 = cc3xx_pka_allocate_reg();
+
+ /* Initialize the accumulator register with the current value of acc */
+ cc3xx_pka_write_reg(r0, (const uint32_t *)acc, CC3XX_DRBG_CTR_BLOCKLEN);
+
+ /* Perform the actual operation */
+ cc3xx_pka_add_si(r0, is_increment ? 1 : -1, r0);
+
+ /* Read back the accumulator register */
+ cc3xx_pka_read_reg(r0, acc, CC3XX_DRBG_CTR_BLOCKLEN);
+
+ /* Uninit the engine */
+ cc3xx_pka_uninit();
+}
+
+static inline void long_inc(uint32_t *acc, size_t acc_size)
+{
+ long_inc_int(acc, acc_size, true);
+}
+
+static inline void long_dec(uint32_t *acc, size_t acc_size)
+{
+ long_inc_int(acc, acc_size, false);
+}
+
+/**
+ * @brief Produces seedlen bits of data through the underlying block
+ * cipher (AES) set in CTR mode, and uses the produced data to update
+ * the values of (Key, V) to be used as a state
+ *
+ * @param state A pointer to a state structure
+ * @param data provided data for the update process
+ * @param data_len Length of the update operation
+ *
+ * @return cc3xx_err_t
+ */
+static cc3xx_err_t cc3xx_drbg_ctr_update(
+ struct cc3xx_drbg_ctr_state_t *state,
+ const uint8_t *data, const size_t data_len)
+{
+ cc3xx_err_t err;
+
+ assert(data_len <= CC3XX_DRBG_CTR_SEEDLEN);
+
+ long_inc((uint32_t *)state->block_v, sizeof(state->block_v));
+
+ err = cc3xx_aes_init(CC3XX_AES_DIRECTION_ENCRYPT,
+ CC3XX_AES_MODE_CTR,
+ CC3XX_AES_KEY_ID_USER_KEY,
+ (const uint32_t *)state->key_k, sizeof(state->key_k),
+ (const uint32_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ cc3xx_aes_set_output_buffer((uint8_t *)state->key_k, CC3XX_DRBG_CTR_SEEDLEN);
+
+ err = cc3xx_aes_update(data, data_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ /* allow for the update() to happen on less than 256 bit of data */
+ if (data_len < CC3XX_DRBG_CTR_SEEDLEN) {
+ uint8_t all_zeros[CC3XX_DRBG_CTR_SEEDLEN - data_len];
+ memset(all_zeros, 0, sizeof(all_zeros));
+ err = cc3xx_aes_update(all_zeros, sizeof(all_zeros));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ err = cc3xx_aes_finish(NULL);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_ctr_init(
+ struct cc3xx_drbg_ctr_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len)
+{
+ cc3xx_err_t err;
+ uint32_t personalized_entropy[CC3XX_DRBG_CTR_SEEDLEN_WORDS];
+ uint8_t *seed_material = (uint8_t *)entropy;
+ size_t idx;
+
+ /* The entropy must be equal to 256 bit. The spec allows for a lower
+ * amout of entropy to be passed during instantiation, then using a
+ * derivation function at this point to reach 256 bit. But this implementation
+ * focuses on lower complexity hence the derivation function is not used
+ */
+ assert(entropy_len == CC3XX_DRBG_CTR_SEEDLEN);
+
+ /* This implementation does not use a derivation function, hence the nonce
+ * is not used during the instantiation procedure
+ */
+ (void)nonce;
+ (void)nonce_len;
+
+ if (personalization != NULL) {
+
+ /* If present and less than 256 bit, it's equivalent to be zero padded */
+ assert(personalization_len <= CC3XX_DRBG_CTR_SEEDLEN);
+
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+ cc3xx_dpa_hardened_word_copy(personalized_entropy,
+ (uint32_t *)entropy,
+ CC3XX_DRBG_CTR_SEEDLEN_WORDS);
+#else
+ memcpy(personalized_entropy, entropy, CC3XX_DRBG_CTR_SEEDLEN);
+#endif
+ for (idx = 0; idx < personalization_len; idx++) {
+ ((uint8_t *)personalized_entropy)[idx] ^= personalization[idx];
+ }
+ seed_material = (uint8_t *)personalized_entropy;
+ }
+
+ memset(state, 0, sizeof(struct cc3xx_drbg_ctr_state_t));
+
+ err = cc3xx_drbg_ctr_update(state, seed_material, CC3XX_DRBG_CTR_SEEDLEN);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ state->reseed_counter = 1;
+
+out:
+ if (personalization != NULL) {
+ /* Make sure the seed material on the stack gets overwritten with random values */
+ cc3xx_secure_erase_buffer(personalized_entropy, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
+ }
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_ctr_generate(
+ struct cc3xx_drbg_ctr_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+ const uint8_t all_zeros[CC3XX_DRBG_CTR_SEEDLEN] = {0};
+ const uint8_t *p_additional_input = all_zeros;
+ size_t produced_bits = 0;
+ size_t num_whole_blocks = (len_bits/8)/CC3XX_DRBG_CTR_SEEDLEN;
+ struct cc3xx_aes_state_t aes_state;
+ size_t idx;
+
+ if (state->reseed_counter == UINT32_MAX) {
+ /* When we reach 2^32 invocations we must reseed */
+ return CC3XX_ERR_DRBG_RESEED_REQUIRED;
+ }
+
+ /* The implementation constraints the output length to be byte aligned to
+ * reduce complexity
+ */
+ assert(len_bits != 0);
+ assert((len_bits % 8) == 0);
+
+ if (additional_input != NULL) {
+
+ assert(additional_input_len <= CC3XX_DRBG_CTR_SEEDLEN);
+
+ err = cc3xx_drbg_ctr_update(state, additional_input, additional_input_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ p_additional_input = additional_input;
+ }
+
+ long_inc((uint32_t *)state->block_v, sizeof(state->block_v));
+
+ err = cc3xx_aes_init(CC3XX_AES_DIRECTION_ENCRYPT,
+ CC3XX_AES_MODE_CTR,
+ CC3XX_AES_KEY_ID_USER_KEY,
+ (const uint32_t *)state->key_k, sizeof(state->key_k),
+ (const uint32_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ cc3xx_aes_set_output_buffer(returned_bits, len_bits/8); /* length is in bytes */
+
+ for (idx = 0; idx < num_whole_blocks; idx++) {
+ err = cc3xx_aes_update(all_zeros, sizeof(all_zeros));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ produced_bits += (CC3XX_DRBG_CTR_SEEDLEN * 8);
+ }
+
+ /* Deal with a partial block */
+ if ((len_bits - produced_bits) != 0) {
+ /* Produce the last block */
+ err = cc3xx_aes_update(all_zeros, (len_bits - produced_bits)/8); /* in bytes */
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ /* We need to get the value of the counter back from the AES subsystem
+ * as it's required in update()
+ */
+ cc3xx_aes_get_state(&aes_state);
+
+ err = cc3xx_aes_finish(NULL);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+ cc3xx_dpa_hardened_word_copy((uint32_t *)state->block_v,
+ aes_state.ctr,
+ CC3XX_DRBG_CTR_BLOCKLEN_WORDS);
+#else
+ memcpy(state->block_v, aes_state.ctr, sizeof(state->block_v));
+#endif
+ long_dec((uint32_t *)state->block_v, sizeof(state->block_v));
+
+ /* Update for back tracking resistance */
+ err = cc3xx_drbg_ctr_update(state, p_additional_input, CC3XX_DRBG_CTR_SEEDLEN);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ state->reseed_counter++;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_ctr_reseed(
+ struct cc3xx_drbg_ctr_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+ uint32_t personalized_entropy[CC3XX_DRBG_CTR_SEEDLEN_WORDS];
+ uint8_t *seed_material = (uint8_t *)entropy;
+ size_t idx;
+
+ assert(entropy_len == CC3XX_DRBG_CTR_SEEDLEN);
+
+ if (additional_input != NULL) {
+ assert(additional_input_len <= CC3XX_DRBG_CTR_SEEDLEN);
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+ cc3xx_dpa_hardened_word_copy(personalized_entropy,
+ (uint32_t *)entropy,
+ CC3XX_DRBG_CTR_SEEDLEN_WORDS);
+#else
+ memcpy(personalized_entropy, entropy, entropy_len);
+#endif
+ for (idx = 0; idx < additional_input_len; idx++) {
+ ((uint8_t *)personalized_entropy)[idx] ^= additional_input[idx];
+ }
+ seed_material = (uint8_t *)personalized_entropy;
+ }
+
+ err = cc3xx_drbg_ctr_update(state, seed_material, entropy_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ state->reseed_counter = 1;
+
+out:
+ if (additional_input != NULL) {
+ /* Make sure the seed material on the stack gets overwritten with random values */
+ cc3xx_secure_erase_buffer(personalized_entropy, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
+ }
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_ctr_uninit(struct cc3xx_drbg_ctr_state_t *state)
+{
+ /* Secure erase only the sensitive material*/
+ cc3xx_secure_erase_buffer((uint32_t *)state, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
+
+ memset(state, 0, sizeof(struct cc3xx_drbg_ctr_state_t));
+
+ return CC3XX_ERR_SUCCESS;
+}
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.h
new file mode 100644
index 0000000..f17fa91
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_ctr.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CC3XX_DRBG_CTR_H__
+#define __CC3XX_DRBG_CTR_H__
+
+#include "cc3xx_error.h"
+#include "cc3xx_aes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief CTR mode uses AES only as underlying block cipher
+ *
+ */
+#define CC3XX_DRBG_CTR_BLOCKLEN (AES_BLOCK_SIZE)
+
+/**
+ * @brief CTR mode uses AES-128 only as underlying block cipher
+ *
+ */
+#define CC3XX_DRBG_CTR_KEYLEN (16)
+
+/**
+ * @brief AES-128 key length in words, as used by the CTR_DRBG module
+ *
+ */
+#define CC3XX_DRBG_CTR_KEYLEN_WORDS ((CC3XX_DRBG_CTR_KEYLEN)/(4))
+
+/**
+ * @brief CTR mode uses AES only as underlying block cipher, and this
+ * define provides the value of the AES block length in words
+ *
+ */
+#define CC3XX_DRBG_CTR_BLOCKLEN_WORDS ((CC3XX_DRBG_CTR_BLOCKLEN)/(4))
+
+/**
+ * @brief CTR_DRBG defines SEEDLEN as BLOCKLEN + KEYLEN
+ *
+ */
+#define CC3XX_DRBG_CTR_SEEDLEN (CC3XX_DRBG_CTR_BLOCKLEN + CC3XX_DRBG_CTR_KEYLEN)
+
+/**
+ * @brief CTR_DRBG defines SEEDLEN as BLOCKLEN + KEYLEN (This is in words)
+ *
+ */
+#define CC3XX_DRBG_CTR_SEEDLEN_WORDS (CC3XX_DRBG_CTR_BLOCKLEN_WORDS + CC3XX_DRBG_CTR_KEYLEN_WORDS)
+
+/**
+ * @brief Contains the state of the CTR_DRBG
+ *
+ */
+struct cc3xx_drbg_ctr_state_t {
+ uint32_t key_k[CC3XX_DRBG_CTR_KEYLEN_WORDS];
+ uint32_t block_v[CC3XX_DRBG_CTR_BLOCKLEN_WORDS];
+ uint32_t reseed_counter;
+};
+
+/**
+ * @brief Instantiate the CTR_DRBG
+ *
+ * @param state A pointer to a state structure
+ * @param entropy Buffer containing the entropy for the instantiation
+ * @param entropy_len Size in bytes of the entropy buffer \param entropy
+ * @param nonce Buffer containing the nonce
+ * @param nonce_len Size in bytes of the nonce buffer \param nonce
+ * @param personalization Buffer containing the personalization string
+ * @param personalization_len Size in bytes of the personalization buffer \param personalization
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_ctr_init(
+ struct cc3xx_drbg_ctr_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len);
+
+/**
+ * @brief Generates random bits from the CTR_DRBG instance
+ *
+ * @param state Pointer to an instantiated CTR_DRBG generator
+ * @param len_bits Size in bits to be generated. Must be byte aligned for simplicity
+ * @param returned_bits Pointer where the random bits will be written to
+ * @param additional_input Pointer to the additional input to be used
+ * @param additional_input_len Size in bytes of the additional input to be used
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_ctr_generate(
+ struct cc3xx_drbg_ctr_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Reseeds the CTR_DRBG
+ *
+ * @param state A pointer to a state structure
+ * @param entropy Entropy to be used for reseeding
+ * @param entropy_len Size in bytes of the entropy pointed by \param entropy
+ * @param additional_input Optional pointer containing additional input for reseeding
+ * @param additional_input_len Size in bytes of the buffer pointed by \param additional_input
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_ctr_reseed(
+ struct cc3xx_drbg_ctr_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Un-initializes the state structure associated to the CTR_DRBG
+ *
+ * @param state Pointer to the state structure
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_ctr_uninit(
+ struct cc3xx_drbg_ctr_state_t *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CC3XX_DRBG_CTR_H__ */
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.c b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.c
new file mode 100644
index 0000000..2005cd3
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include "cc3xx_hash.h"
+#include "cc3xx_drbg_hash.h"
+#include "cc3xx_endian_helpers.h"
+#include "cc3xx_pka.h"
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+#include "cc3xx_stdlib.h"
+#endif
+
+/**
+ * @brief Ceiling of a / b
+ */
+#define CEIL(a, b) ((a) + (b) - 1)/(b)
+
+/** \note Throughout the file sizeof(state_v) and sizeof(constant_c) are
+ * decreased by 1 byte because they have been defined with 1 byte
+ * more in the \ref struct cc3xx_drbg_hash_state_t to be 4 bytes
+ * aligned
+ */
+
+static void long_acc(uint8_t *acc, const uint8_t *val, size_t acc_size, size_t val_size)
+{
+ /* Need to convert BE -> LE -> BE again if PKA is configured for LE */
+ cc3xx_pka_reg_id_t r0, r1;
+ assert(acc_size == CC3XX_DRBG_HASH_SEEDLEN);
+
+ /* Accumulation happen only on 440 bit accumulators */
+ cc3xx_pka_init(CC3XX_DRBG_HASH_SEEDLEN);
+
+ /* Allocate a register among those not in use, given configured size */
+ r0 = cc3xx_pka_allocate_reg();
+
+ /* Initialize the accumulator register with the current value of acc */
+ cc3xx_pka_write_reg(r0, (const uint32_t *)acc, CC3XX_DRBG_HASH_SEEDLEN);
+
+ /* Request another register for the value to accumulate */
+ r1 = cc3xx_pka_allocate_reg();
+
+ /* Write the value to accumulate into the register */
+ cc3xx_pka_write_reg(r1, (const uint32_t *)val, val_size);
+
+ /* Perform the actual operation */
+ cc3xx_pka_add(r0, r1, r0);
+
+ /* Read back the accumulator register */
+ cc3xx_pka_read_reg(r0, (uint32_t *)acc, CC3XX_DRBG_HASH_SEEDLEN);
+
+ /* Uninit the engine */
+ cc3xx_pka_uninit();
+}
+
+/* Hardcode support for SHA-256 based HMAC only */
+static const cc3xx_hash_alg_t alg = CC3XX_HASH_ALG_SHA256;
+
+/**
+ * @brief Hash derivation function as specified by NIST SP 800-90 Section 10.3.1
+ *
+ * @param hash_inputs_num Total number of the hash_inputs being passed to the update function
+ * @param hash_inputs An array of three buffer pointers that can be used in the derivation process
+ * @param hash_inputs_len An array of three size_t values that contain the size of each buffer passed
+ * @param out Buffer containing the output of the derivation function
+ * @param out_len_bits Size in bits of the buffer containing the result of the derivation operation
+ * @return cc3xx_err_t
+ */
+static cc3xx_err_t hash_df(
+ size_t hash_inputs_num,
+ const uint8_t **hash_inputs,
+ const size_t *hash_inputs_len,
+ uint8_t *out,
+ size_t out_len_bits)
+{
+ /* The number of full SHA-256 hashes output (256 bit) that we need to cover the requested
+ * output of out_len_bits = 440 bit, i.e. the CC3XX_DRBG_HASH_SEEDLEN
+ */
+ const size_t num_hash = 2;
+ cc3xx_err_t err;
+ uint8_t counter_out_len_bits[5] = {0x01, 0x00, 0x00, 0x01, 0xB8}; /* 0x01 || out_len_bits */
+ size_t idx;
+ size_t hash_input_idx;
+ uint32_t temp[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
+
+ /* Number of bits to return must be fixed to 440 for the implementation, i.e. 0x1B8 */
+ assert(out_len_bits == CC3XX_DRBG_HASH_SEEDLEN * 8);
+
+ for (idx = 0; idx < num_hash; idx++) {
+
+ err = cc3xx_hash_init(alg);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ err = cc3xx_hash_update(counter_out_len_bits, sizeof(counter_out_len_bits));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ for (hash_input_idx = 0; hash_input_idx < hash_inputs_num && hash_inputs_len[hash_input_idx] != 0; hash_input_idx++) {
+ err = cc3xx_hash_update(hash_inputs[hash_input_idx], hash_inputs_len[hash_input_idx]);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ cc3xx_hash_finish((idx != num_hash - 1) ? (uint32_t *)out : temp, SHA256_OUTPUT_SIZE);
+
+ if (idx != num_hash - 1) {
+ out += SHA256_OUTPUT_SIZE;
+ }
+ counter_out_len_bits[0]++;
+ }
+
+ memcpy(out, temp, CC3XX_DRBG_HASH_SEEDLEN - SHA256_OUTPUT_SIZE);
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hash_init(
+ struct cc3xx_drbg_hash_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len)
+{
+ cc3xx_err_t err;
+ uint8_t byte0 = 0x0;
+ const uint8_t *data[3] = {entropy, nonce, personalization};
+ size_t data_len[3] = {entropy_len, nonce_len, personalization_len};
+
+ err = hash_df(3, data, data_len, state->value_v, CC3XX_DRBG_HASH_SEEDLEN * 8);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ data[0] = &byte0;
+ data[1] = state->value_v;
+ data_len[0] = sizeof(byte0);
+ data_len[1] = sizeof(state->value_v) - 1;
+
+ err = hash_df(2, data, data_len, state->constant_c, CC3XX_DRBG_HASH_SEEDLEN * 8);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ state->reseed_counter = 1;
+
+ return err;
+}
+
+/**
+ * @brief Hash based generation process as specified by NIST SP 800-90 Section 10.1.1.4
+ *
+ * @param block_v block_v containing the seed to be used by the hashgen process
+ * @param out_len_bits Number of bits requested to be generated, byte aligned
+ * @param returned_bits Buffer containing the bits generated using the hash based process
+ * @return cc3xx_err_t
+ */
+static cc3xx_err_t hash_gen_process(uint8_t *block_v, size_t out_len_bits, uint8_t *returned_bits)
+{
+ cc3xx_err_t err;
+ size_t idx;
+ size_t gen_num_m = CEIL(out_len_bits, SHA256_OUTPUT_SIZE * 8); /* Number of hash generations */
+ uint32_t data[(CC3XX_DRBG_HASH_SEEDLEN + 1) / sizeof(uint32_t)];
+ uint32_t partial_last_block[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
+#ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
+ size_t num_words_to_copy = sizeof(data) / sizeof(uint32_t);
+ cc3xx_dpa_hardened_word_copy((uint32_t *)data, (uint32_t *)block_v, num_words_to_copy);
+#else
+ memcpy(data, block_v, CC3XX_DRBG_HASH_SEEDLEN);
+#endif
+
+ for (idx = 0; idx < gen_num_m; idx++) {
+ const uint8_t byte1 = 0x1;
+ uint32_t *p_output_buf = NULL;
+
+ err = cc3xx_hash_init(alg);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ err = cc3xx_hash_update((uint8_t *)data, CC3XX_DRBG_HASH_SEEDLEN);
+ if (err!= CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ if (idx != gen_num_m - 1) {
+ p_output_buf = (uint32_t *)returned_bits;
+ } else {
+ /* We need to discriminate the case where the last generation is for a whole
+ * block or a partial block
+ */
+ if (out_len_bits % (SHA256_OUTPUT_SIZE * 8)) {
+ p_output_buf = partial_last_block;
+ } else {
+ p_output_buf = (uint32_t *)returned_bits;
+ }
+ }
+
+ cc3xx_hash_finish(p_output_buf, SHA256_OUTPUT_SIZE);
+
+ long_acc((uint8_t *)data, &byte1, CC3XX_DRBG_HASH_SEEDLEN, sizeof(byte1));
+
+ returned_bits += SHA256_OUTPUT_SIZE;
+ }
+
+ returned_bits -= SHA256_OUTPUT_SIZE;
+
+ if (out_len_bits % (SHA256_OUTPUT_SIZE * 8)) {
+ memcpy(returned_bits, partial_last_block, out_len_bits % (SHA256_OUTPUT_SIZE * 8));
+ }
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hash_generate(
+ struct cc3xx_drbg_hash_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+ const uint8_t byte3 = 0x03;
+ uint8_t reseed_counter[4];
+ uint32_t hash_output_buffer[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
+ /* The reseed counter must be treated as a BE number, so use a local
+ * buffer to format it as a big endian number for the long addition
+ */
+ uint32_t *p_reseed_counter = (uint32_t *) reseed_counter;
+
+ if (state->reseed_counter == UINT32_MAX) {
+ /* When we reach 2^32 invocations we must reseed */
+ return CC3XX_ERR_DRBG_RESEED_REQUIRED;
+ }
+
+ /* The implementation constraints the output length to be byte aligned to
+ * reduce complexity
+ */
+ assert(len_bits != 0);
+ assert((len_bits % 8) == 0);
+
+ if (additional_input_len && additional_input != NULL) {
+ const uint8_t byte2 = 0x02;
+
+ err = cc3xx_hash_init(alg);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hash_update(&byte2, sizeof(byte2));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hash_update(state->value_v, sizeof(state->value_v) - 1);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hash_update(additional_input, additional_input_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ cc3xx_hash_finish(hash_output_buffer, SHA256_OUTPUT_SIZE);
+ long_acc(state->value_v, (uint8_t *)hash_output_buffer,
+ sizeof(state->value_v) - 1, sizeof(hash_output_buffer));
+ }
+
+ err = hash_gen_process(state->value_v, len_bits, returned_bits);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ err = cc3xx_hash_init(alg);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hash_update(&byte3, sizeof(byte3));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hash_update(state->value_v, sizeof(state->value_v) - 1);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ cc3xx_hash_finish(hash_output_buffer, SHA256_OUTPUT_SIZE);
+
+ /* V = V + H + C + reseed_counter */
+ long_acc(state->value_v, (uint8_t *)hash_output_buffer,
+ sizeof(state->value_v) - 1, sizeof(hash_output_buffer));
+ long_acc(state->value_v, state->constant_c,
+ sizeof(state->value_v) - 1, sizeof(state->constant_c) - 1);
+
+ *p_reseed_counter = bswap_32(state->reseed_counter);
+ long_acc(state->value_v, reseed_counter,
+ sizeof(state->value_v) - 1, sizeof(reseed_counter));
+
+ state->reseed_counter++;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hash_reseed(
+ struct cc3xx_drbg_hash_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+ const uint8_t byte0 = 0x0;
+ /* temporary buffer for (byte1 || V). Note that hash_df does not work in-place */
+ uint8_t temp[1 + sizeof(state->value_v) - 1] = {0x01};
+ const uint8_t *data[3] = {temp, entropy, additional_input};
+ size_t data_len[3] = {sizeof(temp), entropy_len, additional_input_len};
+
+ /* temp concatenates 0x01 || V */
+ memcpy(&temp[1], state->value_v, sizeof(state->value_v) - 1);
+
+ err = hash_df(3, data, data_len, state->value_v, CC3XX_DRBG_HASH_SEEDLEN * 8);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ data[0] = &byte0;
+ data[1] = state->value_v;
+ data_len[0] = sizeof(byte0);
+ data_len[1] = sizeof(state->value_v) - 1;
+
+ err = hash_df(2, data, data_len, state->constant_c, CC3XX_DRBG_HASH_SEEDLEN * 8);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ state->reseed_counter = 1;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hash_uninit(struct cc3xx_drbg_hash_state_t *state)
+{
+ cc3xx_secure_erase_buffer((uint32_t *)state, sizeof(struct cc3xx_drbg_hash_state_t)/4);
+ return CC3XX_ERR_SUCCESS;
+}
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.h
new file mode 100644
index 0000000..5aac40f
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hash.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CC3XX_DRBG_HASH_H__
+#define __CC3XX_DRBG_HASH_H__
+
+#include <stdint.h>
+#include "cc3xx_error.h"
+
+#include "cc3xx_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The value of seedlen is fixed by the spec to 440 bits. This
+ * defines is used to convert it to bytes
+ */
+#define CC3XX_DRBG_HASH_SEEDLEN (440/8)
+
+/**
+ * @brief Contains the state of the HASH_DRBG
+ *
+ */
+struct cc3xx_drbg_hash_state_t {
+ uint8_t value_v[CC3XX_DRBG_HASH_SEEDLEN + 1]; /* +1 for word alignment */
+ uint8_t constant_c[CC3XX_DRBG_HASH_SEEDLEN + 1];
+ uint32_t reseed_counter;
+};
+
+/**
+ * @brief Instantiate the HASH_DRBG generator
+ *
+ * @param state Pointer to a \ref cc3xx_drbg_hash_state_t context
+ * @param entropy Pointer to the collected entropy
+ * @param entropy_len Size in bytes of the entropy
+ * @param nonce Pointer to the nonce to be used
+ * @param nonce_len Size in bytes of the nonce
+ * @param personalization Pointer to the personalisation string to be used
+ * @param personalization_len Size in bytes of the personalisation string
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hash_init(
+ struct cc3xx_drbg_hash_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len);
+
+/**
+ * @brief Generates random bits from the HASH_DRBG instance
+ *
+ * @param state Pointer to an instantiated HASH_DRBG generator
+ * @param len_bits Size in bits to be generated. Must be byte aligned for simplicity
+ * @param returned_bits Pointer holding the returned random bit string
+ * @param additional_input Pointer to the additional input to be used
+ * @param additional_input_len Size in bytes of the additional input to be used
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hash_generate(
+ struct cc3xx_drbg_hash_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Reseeds the HASH_DRBG instance
+ *
+ * @param state Pointer to an instantiated HASH_DRBG generator to reseed
+ * @param entropy Pointer to the additional entropy to use for reseeding
+ * @param entropy_len Size in bytes of the additional entropy
+ * @param additional_input Pointer to the additional input to use for reseeding
+ * @param additional_input_len Size in bytes of the additional input buffer
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hash_reseed(
+ struct cc3xx_drbg_hash_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Un-initializes the state structure associated to the HASH_DRBG
+ *
+ * @param state Pointer to the structure
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hash_uninit(struct cc3xx_drbg_hash_state_t *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CC3XX_DRBG_HASH_H__ */
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.c b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.c
new file mode 100644
index 0000000..83ae108
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include "cc3xx_stdlib.h"
+#include "cc3xx_hmac.h"
+#include "cc3xx_drbg_hmac.h"
+
+#define BITS_TO_BYTES(x) (((x) + 7)/8)
+#define BYTES_TO_BITS(x) ((x)*8)
+
+/**
+ * @brief Update the state (K,V)
+ *
+ * @param hmac_inputs_num Number of inputs for the update operation, it can be zero
+ * @param state A pointer to a state structure
+ * @param hmac_inputs Inputs for the update operation, passed as an array of hmac_inputs_num pointers
+ * @param hmac_inputs_len Lengths for the update operation, passed as an array of hmac_inputs_num values
+ * @return cc3xx_err_t
+ */
+static cc3xx_err_t cc3xx_drbg_hmac_update(
+ size_t hmac_inputs_num,
+ struct cc3xx_drbg_hmac_state_t *state,
+ const uint8_t **hmac_inputs, const size_t *hmac_inputs_len)
+{
+ const uint8_t byte0 = 0x00; const uint8_t byte1 = 0x01;
+ cc3xx_err_t err;
+ size_t idx;
+
+ /* 1. K = HMAC(K, V || 0x00 || provided_data) */
+ err = cc3xx_hmac_set_key(&state->h, (const uint8_t *)state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, (const uint8_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, &byte0, sizeof(byte0));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ /* provided_data can be given into up to 3 chunks, starting from 0 index */
+ for (idx = 0; idx < hmac_inputs_num && hmac_inputs_len[idx] != 0; idx++) {
+ err = cc3xx_hmac_update(&state->h, hmac_inputs[idx], hmac_inputs_len[idx]);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ err = cc3xx_hmac_finish(&state->h, state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ /* 2. V = HMAC(K, V) */
+ err = cc3xx_hmac_set_key(&state->h, (const uint8_t *)state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, (const uint8_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_finish(&state->h, state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ /* 3. If no provided_data has been passed, just return here */
+ if (hmac_inputs_num == 0) {
+ return err;
+ }
+
+ /* 4. K = HMAC(K, V || 0x01 || provided_data) */
+ err = cc3xx_hmac_set_key(&state->h, (const uint8_t *)state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, (const uint8_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, &byte1, sizeof(byte1));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ for (idx = 0; idx < hmac_inputs_num && hmac_inputs_len[idx] != 0; idx++) {
+ err = cc3xx_hmac_update(&state->h, hmac_inputs[idx], hmac_inputs_len[idx]);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ err = cc3xx_hmac_finish(&state->h, state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ /* 5. V = HMAC(K, V) */
+ err = cc3xx_hmac_set_key(&state->h, (const uint8_t *)state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, (const uint8_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_finish(&state->h, state->block_v, sizeof(state->block_v));
+
+ /* return updated (K, V) state */
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hmac_instantiate(
+ struct cc3xx_drbg_hmac_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len)
+{
+ cc3xx_err_t err;
+
+ /* Initialize the state */
+ memset(state->block_v, 0x01, sizeof(state->block_v));
+ memset(state->key_k, 0x00, sizeof(state->key_k));
+
+ /* Prepare the seed material to be passed to update() */
+ const uint8_t *seed[3] = {entropy, nonce, personalization};
+ const size_t seed_len[3] = {entropy_len, nonce_len, personalization_len};
+
+ err = cc3xx_drbg_hmac_update(3, state, seed, seed_len);
+
+ state->reseed_counter = 1;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hmac_generate(
+ struct cc3xx_drbg_hmac_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+ size_t generated_bits = 0;
+ const uint8_t *data[3] = {NULL};
+ size_t data_len[3] = {0};
+ size_t idx;
+ size_t last_hmac_update_num = 0;
+
+ if (state->reseed_counter == UINT32_MAX) {
+ /* When we reach 2^32 invocations we must reseed */
+ return CC3XX_ERR_DRBG_RESEED_REQUIRED;
+ }
+
+ if (additional_input_len && additional_input != NULL) {
+ data[0] = additional_input;
+ data_len[0] = additional_input_len;
+ err = cc3xx_drbg_hmac_update(1, state, data, data_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ /* While len(temp) < requested_number_of_bits, as per spec */
+ while (generated_bits < len_bits) {
+ uint32_t temp[CC3XX_DRBG_HMAC_OUTLEN/4];
+ size_t bytes_to_copy;
+ /* V = HMAC(K, V) */
+ err = cc3xx_hmac_set_key(&state->h, (const uint8_t *)state->key_k, sizeof(state->key_k));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_update(&state->h, (const uint8_t *)state->block_v, sizeof(state->block_v));
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ err = cc3xx_hmac_finish(&state->h, temp, CC3XX_DRBG_HMAC_OUTLEN);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ bytes_to_copy = len_bits - generated_bits < BYTES_TO_BITS(CC3XX_DRBG_HMAC_OUTLEN) ?
+ BITS_TO_BYTES(len_bits - generated_bits) : CC3XX_DRBG_HMAC_OUTLEN;
+ memcpy(&returned_bits[BITS_TO_BYTES(generated_bits)], temp, bytes_to_copy);
+
+ generated_bits += BYTES_TO_BITS(CC3XX_DRBG_HMAC_OUTLEN);
+
+ memcpy(state->block_v, temp, CC3XX_DRBG_HMAC_OUTLEN);
+ }
+
+ /* We need to mask the last byte in case len_bits % 8 is different than 0 */
+ if (len_bits % 8) {
+ uint8_t mask = 0UL;
+ for (idx = 0; idx < len_bits % 8; idx++) {
+ mask |= 1UL << (8 - idx - 1);
+ }
+
+ returned_bits[BITS_TO_BYTES(len_bits) - 1] &= mask;
+ }
+
+ /* The update is done with no additional_input to update() */
+ if (additional_input != NULL && additional_input_len != 0) {
+ data[0] = additional_input;
+ data_len[0] = additional_input_len;
+ last_hmac_update_num = 1;
+ }
+
+ err = cc3xx_drbg_hmac_update(last_hmac_update_num, state, data, data_len);
+
+ state->reseed_counter++;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hmac_reseed(
+ struct cc3xx_drbg_hmac_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len)
+{
+ cc3xx_err_t err;
+
+ /* The update is done with no personalization string update() */
+ const uint8_t *data[3] = {entropy, additional_input, NULL};
+ const size_t data_len[3] = {entropy_len, additional_input_len, 0};
+
+ err = cc3xx_drbg_hmac_update(2, state, data, data_len);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ state->reseed_counter = 1;
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_drbg_hmac_uninit(struct cc3xx_drbg_hmac_state_t *state)
+{
+ cc3xx_secure_erase_buffer((uint32_t *)state, sizeof(struct cc3xx_drbg_hmac_state_t)/4);
+ return CC3XX_ERR_SUCCESS;
+}
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.h
new file mode 100644
index 0000000..c368f33
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_drbg_hmac.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CC3XX_DRBG_HMAC_H__
+#define __CC3XX_DRBG_HMAC_H__
+
+#include <stdint.h>
+#include "cc3xx_error.h"
+
+#include "cc3xx_hmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The assumption is that it will be a multiple of 4. It depends on the
+ * underlying hash function being used, which for the cc3xx driver is
+ * retricted to SHA-256
+ */
+#define CC3XX_DRBG_HMAC_OUTLEN SHA256_OUTPUT_SIZE
+
+/**
+ * @brief Contains the state of the HMAC_DRBG
+ *
+ */
+struct cc3xx_drbg_hmac_state_t {
+ struct cc3xx_hmac_state_t h;
+ uint32_t block_v[CC3XX_DRBG_HMAC_OUTLEN / sizeof(uint32_t)];
+ uint32_t key_k[CC3XX_DRBG_HMAC_OUTLEN / sizeof(uint32_t)];
+ uint32_t reseed_counter;
+};
+
+/**
+ * @brief Instantiate the HMAC_DRBG
+ *
+ * @param state A pointer to a state structure
+ * @param entropy Buffer containing the entropy for the instantiation
+ * @param entropy_len Size in bytes of the entropy buffer \param entropy
+ * @param nonce Buffer containing the nonce
+ * @param nonce_len Size in bytes of the nonce buffer \param nonce
+ * @param personalization Buffer containing the personalization string
+ * @param personalization_len Size in bytes of the personalization buffer \param personalization
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hmac_instantiate(
+ struct cc3xx_drbg_hmac_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *personalization, size_t personalization_len);
+
+/**
+ * @brief Generate up to len bytes of data
+ *
+ * @param state A pointer to a state structure
+ * @param len_bits Size in bits to be generated. Note that this does not need to be byte aligned.
+ * @param returned_bits Buffer to hold returned bits, must be of size ceil(len_bits/8) bytes
+ * @param additional_input Optional pointer containing the additional input to be added
+ * @param additional_input_len Size in bytes of the additional input \param additional_input
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hmac_generate(
+ struct cc3xx_drbg_hmac_state_t *state,
+ size_t len_bits, uint8_t *returned_bits,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Reseeds the HMAC_DRBG
+ *
+ * @param state A pointer to a state structure
+ * @param entropy Entropy to be used for reseeding
+ * @param entropy_len Size in bytes of the entropy pointed by \param entropy
+ * @param additional_input Optional pointer containing additional input for reseeding
+ * @param additional_input_len Size in bytes of the buffer pointed by \param additional_input
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hmac_reseed(
+ struct cc3xx_drbg_hmac_state_t *state,
+ const uint8_t *entropy, size_t entropy_len,
+ const uint8_t *additional_input, size_t additional_input_len);
+
+/**
+ * @brief Un-initializes the state structure associated to the HMAC_DRBG
+ *
+ * @param state Pointer to the structure
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_drbg_hmac_uninit(struct cc3xx_drbg_hmac_state_t *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CC3XX_DRBG_HMAC_H__ */
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_error.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_error.h
index 312085f..9811748 100644
--- a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_error.h
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_error.h
@@ -34,6 +34,9 @@
CC3XX_ERR_GCM_VARIABLE_IV_NOT_IMPLEMENTED,
CC3XX_ERR_CHACHA_IV_SIZE_INCORRECT,
CC3XX_ERR_DFA_VIOLATION,
+ CC3XX_ERR_DRBG_RESEED_REQUIRED,
+ CC3XX_ERR_DRBG_INVALID_ID,
+ CC3XX_ERR_MAX_VALUE = UINT32_MAX
};
#ifdef __cplusplus
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hash.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hash.h
index 1db4517..0e9709b 100644
--- a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hash.h
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hash.h
@@ -37,7 +37,7 @@
/**
* \brief Initialize a hash operation.
-
+ *
* \param[in] alg Which hash algorithm should be initialized.
*
* \return CC3XX_ERR_SUCCESS on success, another
@@ -47,7 +47,7 @@
/**
* \brief Input data into a hash operation.
-
+ *
* \param[in] buf A pointer to the data to be input.
* \param[in] length The size of the data to be input.
*
@@ -59,8 +59,8 @@
/**
* \brief Get the current state of the hash operation.
* Allows for restartable hash operations.
-
- * \param[out] state The cc3xx_hash_state_t to write the state into.
+ *
+ * \param[out] state The cc3xx_hash_state_t to write the state into.
*/
void cc3xx_hash_get_state(struct cc3xx_hash_state_t *state);
@@ -68,27 +68,27 @@
* \brief Set the current state of the hash operation.
* Allows for restartable hash operations.
*
- * \note This funtion initializes the hardware, there is
- * no need to seperately call cc3xx_hash_init.
-
- * \param[in] state The cc3xx_hash_state_t to read the state from.
+ * \note This function initializes the hardware, there is
+ * no need to separately call cc3xx_hash_init.
+ *
+ * \param[in] state The cc3xx_hash_state_t to read the state from.
*/
void cc3xx_hash_set_state(const struct cc3xx_hash_state_t *state);
/**
* \brief Finish a hash operation, and output the hash.
*
- * \param[out] res The result of the hash operation.
- * \param[in] length The size of the result buffer. Must match the
- * hash output size. Checked by assert only.
+ * \param[out] res The result of the hash operation.
+ * \param[in] length The size of the result buffer. Must match the
+ * hash output size. Checked by assert only.
*/
void cc3xx_hash_finish(uint32_t *res, size_t length);
/**
- * \brief Uninitialize the hash engine.
+ * \brief Uninitialize the hash engine.
*
- * \note The hash engine is not implicitly uninitialized
- * on an error.
+ * \note The hash engine is not implicitly uninitialized
+ * on an error.
*
*/
void cc3xx_hash_uninit(void);
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.c b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.c
new file mode 100644
index 0000000..07841eb
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include "cc3xx_hash.h"
+#include "cc3xx_hmac.h"
+
+#define SHA256_BLOCK_SIZE (64)
+
+/* Hardcode support for SHA-256 based HMAC only */
+static const cc3xx_hash_alg_t alg = CC3XX_HASH_ALG_SHA256;
+
+cc3xx_err_t cc3xx_hmac_set_key(
+ struct cc3xx_hmac_state_t *state,
+ const uint8_t *key,
+ size_t key_size)
+{
+ const uint8_t ipad = 0x36;
+ cc3xx_err_t err;
+ size_t idx;
+ /* In case the key is higher than B, it must be hashed first */
+ uint32_t hash_key_output[SHA256_BLOCK_SIZE / sizeof(uint32_t)];
+ const uint8_t *p_key = key;
+ size_t key_length = key_size;
+
+ if ((err = cc3xx_hash_init(alg)) != CC3XX_ERR_SUCCESS)
+ goto out;
+
+ if (key_size > CC3XX_HMAC_BLOCK_SIZE) {
+ /* hash the key to L bytes */
+ err = cc3xx_hash_update(key, key_size);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+ p_key = (const uint8_t *)hash_key_output;
+ key_length = SHA256_OUTPUT_SIZE;
+ }
+
+ cc3xx_hash_finish(hash_key_output, sizeof(hash_key_output));
+
+ /* K ^ ipad */
+ for (idx = 0; idx < key_length; idx++) {
+ state->key[idx] = p_key[idx] ^ ipad;
+ }
+
+ memset(&state->key[key_length], ipad, CC3XX_HMAC_BLOCK_SIZE - key_length);
+
+ /* H(K ^ ipad) */
+ if ((err = cc3xx_hash_init(alg)) != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ err = cc3xx_hash_update(state->key, CC3XX_HMAC_BLOCK_SIZE);
+
+out:
+ if (err == CC3XX_ERR_SUCCESS) {
+ cc3xx_hash_get_state(&state->hash);
+ }
+ cc3xx_hash_uninit();
+ return err;
+}
+
+cc3xx_err_t cc3xx_hmac_update(
+ struct cc3xx_hmac_state_t *state,
+ const uint8_t *data,
+ size_t data_length)
+{
+ cc3xx_err_t err;
+
+ cc3xx_hash_set_state(&state->hash);
+
+ /* H(K ^ ipad | data)*/
+ err = cc3xx_hash_update(data, data_length);
+
+ if (err == CC3XX_ERR_SUCCESS) {
+ cc3xx_hash_get_state(&state->hash);
+ }
+ cc3xx_hash_uninit();
+ return err;
+}
+
+cc3xx_err_t cc3xx_hmac_finish(
+ struct cc3xx_hmac_state_t *state,
+ uint32_t *tag,
+ size_t tag_size)
+{
+ uint32_t scratch[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
+ const uint8_t ixopad = 0x36 ^ 0x5c; /* ipad ^ opad */
+ cc3xx_err_t err;
+ size_t idx;
+
+ assert(tag_size >= SHA256_OUTPUT_SIZE);
+
+ cc3xx_hash_set_state(&state->hash);
+
+ /* Produce H(K ^ ipad | data) */
+ cc3xx_hash_finish(scratch, sizeof(scratch));
+
+ /* K ^ opad */
+ for (idx = 0; idx < CC3XX_HMAC_BLOCK_SIZE; idx++) {
+ state->key[idx] ^= ixopad;
+ }
+
+ /* H( K ^ opad | H(K ^ ipad | data)) */
+ err = cc3xx_hash_init(alg);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ err = cc3xx_hash_update(state->key, CC3XX_HMAC_BLOCK_SIZE);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ err = cc3xx_hash_update((const uint8_t *)scratch, sizeof(scratch));
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto out;
+ }
+
+ cc3xx_hash_finish(tag, tag_size);
+
+out:
+ if (err == CC3XX_ERR_SUCCESS) {
+ cc3xx_hash_get_state(&state->hash);
+ }
+ cc3xx_hash_uninit();
+ return err;
+}
diff --git a/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.h b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.h
new file mode 100644
index 0000000..5866e8b
--- /dev/null
+++ b/platform/ext/accelerator/cc312/cc312-rom/cc3xx_hmac.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CC3XX_HMAC_H__
+#define __CC3XX_HMAC_H__
+
+#include <stdint.h>
+#include "cc3xx_error.h"
+#include "cc3xx_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The size in Bytes, i.e. B, associated to the HMAC block size
+ *
+ */
+#define CC3XX_HMAC_BLOCK_SIZE (64)
+
+/**
+ * @brief Contains the state of the HMAC operation
+ *
+ */
+struct cc3xx_hmac_state_t {
+ uint8_t key[CC3XX_HMAC_BLOCK_SIZE];
+ struct cc3xx_hash_state_t hash; /* Allows to restart low-level hash */
+} __attribute__((aligned(4)));
+
+/**
+ * @brief Sets the key for the HMAC operation on the state
+ *
+ * @param state A pointer to a state structure
+ * @param key Buffer containing the key
+ * @param key_size Size in bytes of the buffer \param key
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_hmac_set_key(
+ struct cc3xx_hmac_state_t *state,
+ const uint8_t *key,
+ size_t key_size);
+
+/**
+ * @brief Update the HMAC operation with a new chunk of data to authenticate
+ *
+ * @param state A pointer to a state structure
+ * @param data Buffer containing the data to use for the update
+ * @param data_length Size in bytes of the buffer \param data
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_hmac_update(
+ struct cc3xx_hmac_state_t *state,
+ const uint8_t *data,
+ size_t data_length);
+
+/**
+ * @brief Finalize the HMAC operation by producing the authentication tag
+ *
+ * @param state A pointer to a state structure
+ * @param tag Output buffer
+ * @param tag_size Size in bytes of the buffer \param tag
+ * @return cc3xx_err_t
+ */
+cc3xx_err_t cc3xx_hmac_finish(
+ struct cc3xx_hmac_state_t *state,
+ uint32_t *tag,
+ size_t tag_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CC3XX_HMAC_H__ */
diff --git a/platform/ext/target/arm/rss/common/cc312/cc3xx_config.h b/platform/ext/target/arm/rss/common/cc312/cc3xx_config.h
index 9e1f038..5eb74e9 100644
--- a/platform/ext/target/arm/rss/common/cc312/cc3xx_config.h
+++ b/platform/ext/target/arm/rss/common/cc312/cc3xx_config.h
@@ -73,6 +73,13 @@
/* Whether RNG is enabled */
#define CC3XX_CONFIG_RNG_ENABLE
+/* Whether the CTR_DRBG is enabled through the generic interface */
+#define CC3XX_CONFIG_DRBG_CTR_ENABLE
+/* Whether the HMAC_DRBG is enabled through the generic interface */
+#define CC3XX_CONFIG_DRBG_HMAC_ENABLE
+/* Whether the HASH_DRBG is enabled through the generic interface */
+#define CC3XX_CONFIG_DRBG_HASH_ENABLE
+
/* Whether an external TRNG should be used in place of the standard CC3XX TRNG */
#ifdef RSS_OTP_TRNG
#define CC3XX_CONFIG_RNG_EXTERNAL_TRNG