Skip to content

Commit

Permalink
[cryptolib, kmac] Add sideload support to KMAC driver
Browse files Browse the repository at this point in the history
Extend KMAC driver so that it supports sideloading
the key from Keymgr.

Signed-off-by: Fatih Balli <[email protected]>
  • Loading branch information
ballifatih authored and milesdai committed Feb 23, 2024
1 parent a7976ef commit baed49a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 30 deletions.
80 changes: 66 additions & 14 deletions sw/device/lib/crypto/drivers/kmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,25 @@ static status_t kmac_set_prefix_regs(const unsigned char *func_name,
* capacity). For instance, if we want to run SHA-3 with 224-bit digest size,
* then `operation_type` = kSHA3_224.
*
* `hw_backed` must be either `kHardenedBoolFalse` or `kHardenedBoolTrue`. For
* other values, this function returns an error.
* For KMAC operations, if `hw_backed = kHardenedBoolTrue` the sideloaded key
* coming from Keymgr is used. If `hw_backed = kHardenedBoolFalse`, the key
* configured by SW is used.
*
* For non-KMAC operations, the value of `hw_backed` can be either of
* `kHardenedBoolFalse` or `kHardenedBoolTrue`. It is recommended to set it to
* `kHardenedBoolFalse` for consistency.
*
* @param operation The chosen operation, see kmac_operation_t struct.
* @param security_str Security strength for KMAC (128 or 256).
* @param hw_backed Whether the key comes from the sideload port.
* @return Error code.
*/
OT_WARN_UNUSED_RESULT
static status_t kmac_init(kmac_operation_t operation,
kmac_security_str_t security_str) {
kmac_security_str_t security_str,
hardened_bool_t hw_backed) {
HARDENED_TRY(wait_status_bit(KMAC_STATUS_SHA3_IDLE_BIT, 1));

// If the operation is KMAC, ensure that the entropy complex has been
Expand All @@ -485,7 +497,13 @@ static status_t kmac_init(kmac_operation_t operation,
// These bits should be set to 1 only if needed by the rest of the code
// in this function.
cfg_reg = bitfield_bit32_write(cfg_reg, KMAC_CFG_SHADOWED_KMAC_EN_BIT, 0);
cfg_reg = bitfield_bit32_write(cfg_reg, KMAC_CFG_SHADOWED_SIDELOAD_BIT, 0);
if (hw_backed == kHardenedBoolTrue) {
cfg_reg = bitfield_bit32_write(cfg_reg, KMAC_CFG_SHADOWED_SIDELOAD_BIT, 1);
} else if (hw_backed == kHardenedBoolFalse) {
cfg_reg = bitfield_bit32_write(cfg_reg, KMAC_CFG_SHADOWED_SIDELOAD_BIT, 0);
} else {
return OTCRYPTO_BAD_ARGS;
};

// operation bit fields: Bit 0: `kmac_en`, Bit 1-2: `mode`
cfg_reg = bitfield_bit32_write(cfg_reg, KMAC_CFG_SHADOWED_KMAC_EN_BIT,
Expand Down Expand Up @@ -712,7 +730,8 @@ static status_t kmac_process_msg_blocks(kmac_operation_t operation,

status_t kmac_sha3_224(const uint8_t *message, size_t message_len,
uint32_t *digest) {
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength224));
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength224,
/*hw_backed=*/kHardenedBoolFalse));

size_t digest_len_words = 224 / 32;
return kmac_process_msg_blocks(kKmacOperationSHA3, message, message_len,
Expand All @@ -721,7 +740,8 @@ status_t kmac_sha3_224(const uint8_t *message, size_t message_len,

status_t kmac_sha3_256(const uint8_t *message, size_t message_len,
uint32_t *digest) {
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength256));
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength256,
/*hw_backed=*/kHardenedBoolFalse));

size_t digest_len_words = 256 / 32;
return kmac_process_msg_blocks(kKmacOperationSHA3, message, message_len,
Expand All @@ -730,7 +750,8 @@ status_t kmac_sha3_256(const uint8_t *message, size_t message_len,

status_t kmac_sha3_384(const uint8_t *message, size_t message_len,
uint32_t *digest) {
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength384));
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength384,
/*hw_backed=*/kHardenedBoolFalse));

size_t digest_len_words = 384 / 32;
return kmac_process_msg_blocks(kKmacOperationSHA3, message, message_len,
Expand All @@ -739,7 +760,8 @@ status_t kmac_sha3_384(const uint8_t *message, size_t message_len,

status_t kmac_sha3_512(const uint8_t *message, size_t message_len,
uint32_t *digest) {
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength512));
HARDENED_TRY(kmac_init(kKmacOperationSHA3, kKmacSecurityStrength512,
/*hw_backed=*/kHardenedBoolFalse));

size_t digest_len_words = 512 / 32;
return kmac_process_msg_blocks(kKmacOperationSHA3, message, message_len,
Expand All @@ -748,15 +770,17 @@ status_t kmac_sha3_512(const uint8_t *message, size_t message_len,

status_t kmac_shake_128(const uint8_t *message, size_t message_len,
uint32_t *digest, size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationSHAKE, kKmacSecurityStrength128));
HARDENED_TRY(kmac_init(kKmacOperationSHAKE, kKmacSecurityStrength128,
/*hw_backed=*/kHardenedBoolFalse));

return kmac_process_msg_blocks(kKmacOperationSHAKE, message, message_len,
digest, digest_len);
}

status_t kmac_shake_256(const uint8_t *message, size_t message_len,
uint32_t *digest, size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationSHAKE, kKmacSecurityStrength256));
HARDENED_TRY(kmac_init(kKmacOperationSHAKE, kKmacSecurityStrength256,
/*hw_backed=*/kHardenedBoolFalse));

return kmac_process_msg_blocks(kKmacOperationSHAKE, message, message_len,
digest, digest_len);
Expand All @@ -766,7 +790,8 @@ status_t kmac_cshake_128(const uint8_t *message, size_t message_len,
const unsigned char *func_name, size_t func_name_len,
const unsigned char *cust_str, size_t cust_str_len,
uint32_t *digest, size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationCSHAKE, kKmacSecurityStrength128));
HARDENED_TRY(kmac_init(kKmacOperationCSHAKE, kKmacSecurityStrength128,
/*hw_backed=*/kHardenedBoolFalse));

HARDENED_TRY(kmac_write_prefix_block(kKmacOperationCSHAKE, func_name,
func_name_len, cust_str, cust_str_len));
Expand All @@ -779,7 +804,8 @@ status_t kmac_cshake_256(const uint8_t *message, size_t message_len,
const unsigned char *func_name, size_t func_name_len,
const unsigned char *cust_str, size_t cust_str_len,
uint32_t *digest, size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationCSHAKE, kKmacSecurityStrength256));
HARDENED_TRY(kmac_init(kKmacOperationCSHAKE, kKmacSecurityStrength256,
/*hw_backed=*/kHardenedBoolFalse));

HARDENED_TRY(kmac_write_prefix_block(kKmacOperationCSHAKE, func_name,
func_name_len, cust_str, cust_str_len));
Expand All @@ -792,9 +818,22 @@ status_t kmac_kmac_128(kmac_blinded_key_t *key, const uint8_t *message,
size_t message_len, const unsigned char *cust_str,
size_t cust_str_len, uint32_t *digest,
size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationKMAC, kKmacSecurityStrength128));
HARDENED_TRY(
kmac_init(kKmacOperationKMAC, kKmacSecurityStrength128, key->hw_backed));

HARDENED_TRY(kmac_write_key_block(key));
if (key->hw_backed == kHardenedBoolTrue) {
if (key->share0 != NULL || key->share1 != NULL ||
key->len != kKmacSideloadKeyLength / 8) {
return OTCRYPTO_BAD_ARGS;
}
} else if (key->hw_backed == kHardenedBoolFalse) {
if (key->share0 == NULL || key->share1 == NULL) {
return OTCRYPTO_BAD_ARGS;
}
HARDENED_TRY(kmac_write_key_block(key));
} else {
return OTCRYPTO_BAD_ARGS;
}

HARDENED_TRY(kmac_write_prefix_block(kKmacOperationKMAC, /*func_name=*/NULL,
/*func_name_len=*/0, cust_str,
Expand All @@ -808,9 +847,22 @@ status_t kmac_kmac_256(kmac_blinded_key_t *key, const uint8_t *message,
size_t message_len, const unsigned char *cust_str,
size_t cust_str_len, uint32_t *digest,
size_t digest_len) {
HARDENED_TRY(kmac_init(kKmacOperationKMAC, kKmacSecurityStrength256));
HARDENED_TRY(
kmac_init(kKmacOperationKMAC, kKmacSecurityStrength256, key->hw_backed));

HARDENED_TRY(kmac_write_key_block(key));
if (key->hw_backed == kHardenedBoolTrue) {
if (key->share0 != NULL || key->share1 != NULL ||
key->len != kKmacSideloadKeyLength / 8) {
return OTCRYPTO_BAD_ARGS;
}
} else if (key->hw_backed == kHardenedBoolFalse) {
if (key->share0 == NULL || key->share1 == NULL) {
return OTCRYPTO_BAD_ARGS;
}
HARDENED_TRY(kmac_write_key_block(key));
} else {
return OTCRYPTO_BAD_ARGS;
}

HARDENED_TRY(kmac_write_prefix_block(kKmacOperationKMAC, /*func_name=*/NULL,
/*func_name_len=*/0, cust_str,
Expand Down
32 changes: 26 additions & 6 deletions sw/device/lib/crypto/drivers/kmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ enum {
kKmacPrefixMaxSize = 36,
// The max size of customization string for KMAC.
kKmacCustStrMaxSize = 32,
// The size of the sideload key. This parameter is not exposed by KMAC or
// Keymgr hjson files from HW, so we need to hardcode it for the moment.
kKmacSideloadKeyLength = 256,
};

/**
Expand All @@ -33,6 +36,9 @@ typedef struct kmac_blinded_key {
uint32_t *share1;
// The length of single share (in bytes)
size_t len;
// Whether the key should be provided by keymgr through sideload port.
// If `hw_backed` is true, `share0/1` pointers and `len` are ignored.
hardened_bool_t hw_backed;
} kmac_blinded_key_t;

/**
Expand Down Expand Up @@ -208,10 +214,17 @@ status_t kmac_cshake_256(const uint8_t *message, size_t message_len,
/**
* Compute KMAC-128 in one-shot.
*
* The caller must ensure that `digest_len` words are allocated at the location
* pointed to by `digest`.
* This function also supports sideloading the key from the Keymgr through a
* peripheral port inaccessible to SW. In order to sideload the key, the caller
* needs to set `key->hw_backed` to `kHardenedBoolTrue`. When sideloading,
* `key->length` must correspond to the sideload key size
* `kKmacSideloadKeyLength / 8` and `share` pointers must be set to NULL.
*
* `cust_str_len` cannot exceed `kKmacCustStrMaxSize`.
* With SW-provided keys, `key->hw_backed` must be `kHardenedBoolFalse`, `share`
* pointers must be correctly configured and `len` must match the key length.
*
* The caller must ensure that `digest_len` words are allocated at the location
* pointed to by `digest`. `cust_str_len` must not exceed `kKmacCustStrMaxSize`.
*
* @param message The input message.
* @param message_len The input message length in bytes.
Expand All @@ -230,10 +243,17 @@ status_t kmac_kmac_128(kmac_blinded_key_t *key, const uint8_t *message,
/**
* Compute KMAC-256 in one-shot.
*
* The caller must ensure that `digest_len` words are allocated at the location
* pointed to by `digest`.
* This function also supports sideloading the key from the Keymgr through a
* peripheral port inaccessible to SW. In order to sideload the key, the caller
* needs to set `key->hw_backed` to `kHardenedBoolTrue`. When sideloading,
* `key->length` must correspond to the sideload key size
* `kKmacSideloadKeyLength / 8` and `share` pointers must be set to NULL.
*
* `cust_str_len` cannot exceed `kKmacCustStrMaxSize`.
* With SW-provided keys, `key->hw_backed` must be `kHardenedBoolFalse`, `share`
* pointers must be correctly configured and `len` must match the key length.
*
* The caller must ensure that `digest_len` words are allocated at the location
* pointed to by `digest`. `cust_str_len` must not exceed `kKmacCustStrMaxSize`.
*
* @param message The input message.
* @param message_len The input message length in bytes.
Expand Down
42 changes: 33 additions & 9 deletions sw/device/lib/crypto/impl/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ otcrypto_status_t otcrypto_kmac(const otcrypto_blinded_key_t *key,
return OTCRYPTO_BAD_ARGS;
}

// Ensure that the output will fit in the tag buffer.
if (required_output_len > tag.len * sizeof(uint32_t) ||
tag.len > SIZE_MAX / sizeof(uint32_t)) {
// Ensure that tag buffer length and `required_output_len` match each other.
if (required_output_len != tag.len * sizeof(uint32_t) ||
required_output_len == 0) {
return OTCRYPTO_BAD_ARGS;
}

Expand All @@ -68,15 +68,33 @@ otcrypto_status_t otcrypto_kmac(const otcrypto_blinded_key_t *key,
return OTCRYPTO_BAD_ARGS;
}

// TODO (#16410, #15590): Add sideload support.
kmac_blinded_key_t kmac_key = {
.share0 = NULL,
.share1 = NULL,
.hw_backed = key->config.hw_backed,
.len = key_len,
};

if (key->config.hw_backed == kHardenedBoolTrue) {
return OTCRYPTO_NOT_IMPLEMENTED;
if (key_len != kKmacSideloadKeyLength / 8 ||
key->keyblob_length != 8 * sizeof(uint32_t)) {
return OTCRYPTO_BAD_ARGS;
}
// Configure keymgr with diversification input and then generate the
// sideload key.
keymgr_diversification_t diversification;
HARDENED_TRY(keyblob_to_keymgr_diversification(key, &diversification));
HARDENED_TRY(keymgr_generate_key_kmac(diversification));
} else if (key->config.hw_backed == kHardenedBoolFalse) {
// Check `key_len` matches `keyblob_length`.
if (key->keyblob_length != 2 * key->config.key_length) {
return OTCRYPTO_BAD_ARGS;
}
HARDENED_TRY(keyblob_to_shares(key, &kmac_key.share0, &kmac_key.share1));
} else {
return OTCRYPTO_BAD_ARGS;
}

kmac_blinded_key_t kmac_key;
HARDENED_TRY(keyblob_to_shares(key, &kmac_key.share0, &kmac_key.share1));
kmac_key.len = key_len;

switch (kmac_mode) {
case kOtcryptoKmacModeKmac128:
// Check `key_mode` matches `mac_mode`
Expand All @@ -101,6 +119,12 @@ otcrypto_status_t otcrypto_kmac(const otcrypto_blinded_key_t *key,
return OTCRYPTO_BAD_ARGS;
}

if (key->config.hw_backed == kHardenedBoolTrue) {
HARDENED_TRY(keymgr_sideload_clear_kmac());
} else if (key->config.hw_backed != kHardenedBoolFalse) {
return OTCRYPTO_BAD_ARGS;
}

return OTCRYPTO_OK;
}

Expand Down
2 changes: 1 addition & 1 deletion sw/device/lib/crypto/include/mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ otcrypto_status_t otcrypto_hmac(const otcrypto_blinded_key_t *key,
* This function computes the KMAC on the `input_message` using the `key` and
* returns a `tag` of `required_output_len`. The customization string is passed
* through `customization_string` parameter. If no customization is desired it
* can be empty.
* can be be left empty (by settings its `data` to NULL and `length` to 0).
*
* The caller should set the `key_length` field of `key.config` to the number
* of bytes in the key. Only the following key sizes (in bytes) are supported:
Expand Down

0 comments on commit baed49a

Please sign in to comment.