Skip to content

Commit

Permalink
[cryptotest] Add test coverage of HMAC streaming API
Browse files Browse the repository at this point in the history
23335 added a streaming API for HMAC utilizing the HMAC HWIP. Here, we
add support in the cryptotest framework to cover the streaming API,
modeled after how this is done for the existing streaming APIs for
SHA-2.

Signed-off-by: Ryan Torok <[email protected]>
  • Loading branch information
RyanTorok committed Jun 6, 2024
1 parent ca6e918 commit 87e3c1a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 29 deletions.
54 changes: 43 additions & 11 deletions sw/device/tests/crypto/cryptotest/firmware/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/lib/base/math.h"
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/crypto/impl/integrity.h"
Expand All @@ -13,11 +14,7 @@
#include "sw/device/lib/ujson/ujson.h"
#include "sw/device/tests/crypto/cryptotest/json/hmac_commands.h"

const unsigned int kOtcryptoHmacTagBytesSha256 = 32;
const unsigned int kOtcryptoHmacTagBytesSha384 = 48;
const unsigned int kOtcryptoHmacTagBytesSha512 = 64;

const int MaxTagBytes = kOtcryptoHmacTagBytesSha512;
const int MaxTagBytes = kSha512DigestBytes;
const int MaxTagWords = MaxTagBytes / sizeof(uint32_t);

// Random value for masking, as large as the longest test key. This value
Expand Down Expand Up @@ -48,15 +45,15 @@ status_t handle_hmac(ujson_t *uj) {
switch (uj_hash_alg) {
case kCryptotestHmacHashAlgSha256:
key_mode = kOtcryptoKeyModeHmacSha256;
tag_bytes = kOtcryptoHmacTagBytesSha256;
tag_bytes = kSha256DigestBytes;
break;
case kCryptotestHmacHashAlgSha384:
key_mode = kOtcryptoKeyModeHmacSha384;
tag_bytes = kOtcryptoHmacTagBytesSha384;
tag_bytes = kSha384DigestBytes;
break;
case kCryptotestHmacHashAlgSha512:
key_mode = kOtcryptoKeyModeHmacSha512;
tag_bytes = kOtcryptoHmacTagBytesSha512;
tag_bytes = kSha512DigestBytes;
break;
default:
LOG_ERROR("Unsupported HMAC key mode: %d", uj_hash_alg);
Expand Down Expand Up @@ -97,16 +94,51 @@ status_t handle_hmac(ujson_t *uj) {
.len = tag_bytes / sizeof(uint32_t),
.data = tag_buf,
};
// Test oneshot API
otcrypto_status_t status = otcrypto_hmac(&key, input_message, tag);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}
// Copy tag to uJSON type
// Copy oneshot tag to uJSON type
cryptotest_hmac_tag_t uj_tag;
memcpy(uj_tag.tag, tag_buf, tag_bytes);
memcpy(uj_tag.oneshot_tag, tag_buf, tag_bytes);
uj_tag.tag_len = tag_bytes;

// Send tag to host via UART
// Zero out tag_buf to mitigate chance of a false positive in the
// stepwise test
memset(tag_buf, 0, tag_bytes);
// Test streaming API
otcrypto_hmac_context_t ctx;
status = otcrypto_hmac_init(&ctx, &key);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}
// Split up input message into 2 shares for better coverage of
// streaming API
otcrypto_const_byte_buf_t input_message_share1 = {
.len = uj_message.message_len / 2,
.data = msg_buf,
};
otcrypto_const_byte_buf_t input_message_share2 = {
.len = ceil_div(uj_message.message_len, 2),
.data = &msg_buf[uj_message.message_len / 2],
};
status = otcrypto_hmac_update(&ctx, input_message_share1);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}
status = otcrypto_hmac_update(&ctx, input_message_share2);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}
status = otcrypto_hmac_final(&ctx, tag);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}
// Copy streaming tag to uJSON output
memcpy(uj_tag.streaming_tag, tag_buf, tag_bytes);

// Send tags to host via UART
RESP_OK(ujson_serialize_cryptotest_hmac_tag_t, uj, &uj_tag);
return OK_STATUS(0);
}
3 changes: 2 additions & 1 deletion sw/device/tests/crypto/cryptotest/json/hmac_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ UJSON_SERDE_STRUCT(CryptotestHmacMessage, cryptotest_hmac_message_t, HMAC_MESSAG
UJSON_SERDE_STRUCT(CryptotestHmacKey, cryptotest_hmac_key_t, HMAC_KEY);

#define HMAC_TAG(field, string) \
field(tag, uint8_t, HMAC_CMD_MAX_TAG_BYTES) \
field(oneshot_tag, uint8_t, HMAC_CMD_MAX_TAG_BYTES) \
field(streaming_tag, uint8_t, HMAC_CMD_MAX_TAG_BYTES) \
field(tag_len, size_t)
UJSON_SERDE_STRUCT(CryptotestHmacTag, cryptotest_hmac_tag_t, HMAC_TAG);

Expand Down
42 changes: 25 additions & 17 deletions sw/host/tests/crypto/hmac_kat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,32 @@ fn run_hmac_testcase(
.send(&*uart)?;

let hmac_tag = CryptotestHmacTag::recv(&*uart, opts.timeout, false)?;
let success = if test_case.tag.len() > hmac_tag.tag_len {
// If we got a shorter tag back then the test asks for, we can't accept the tag, even if
// the beginning bytes match.
false
} else {
// Some of the NIST test cases only specify the beginning bytes of the expected tag, so we
// only check up to what the test specifies.
test_case.tag[..] == hmac_tag.tag[..test_case.tag.len()]
};
if test_case.result != success {
log::info!(
"FAILED test #{}: expected = {}, actual = {}",
test_case.test_case_id,
test_case.result,
success
);
let mut failed = false;
for (mode, actual_tag) in [
("oneshot", hmac_tag.oneshot_tag),
("streaming", hmac_tag.streaming_tag),
] {
let success = if test_case.tag.len() > hmac_tag.tag_len {
// If we got a shorter tag back then the test asks for, we can't accept the tag, even if
// the beginning bytes match.
false
} else {
// Some of the NIST test cases only specify the beginning bytes of the expected tag, so we
// only check up to what the test specifies.
test_case.tag[..] == actual_tag[..test_case.tag.len()]
};
if test_case.result != success {
log::info!(
"FAILED test #{} in {} mode: expected = {}, actual = {}",
test_case.test_case_id,
mode,
test_case.result,
success
);
failed = true;
}
}
if success != test_case.result {
if failed {
*fail_counter += 1;
}
Ok(())
Expand Down

0 comments on commit 87e3c1a

Please sign in to comment.