Skip to content

Commit

Permalink
[pentest] Add HMAC SCA tests
Browse files Browse the repository at this point in the history
This commit pulls over the HMAC SCA tests from the pentest branch of
nasahlpa/opentitan that has been used for the penetration testing.

Signed-off-by: Pascal Nasahl <nasahlpa@lowrisc.org>
  • Loading branch information
nasahlpa authored and andreaskurth committed Sep 3, 2024
1 parent f5294e3 commit 372a630
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 0 deletions.
2 changes: 2 additions & 0 deletions sw/device/tests/penetrationtests/firmware/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ FIRMWARE_DEPS_FPGA = [
"//sw/device/tests/penetrationtests/firmware/fi:rng_fi",
"//sw/device/tests/penetrationtests/firmware/fi:rom_fi",
"//sw/device/tests/penetrationtests/firmware/sca:aes_sca",
"//sw/device/tests/penetrationtests/firmware/sca:hmac_sca",
"//sw/device/tests/penetrationtests/firmware/sca:ibex_sca",
"//sw/device/tests/penetrationtests/firmware/sca:kmac_sca",
"//sw/device/tests/penetrationtests/firmware/sca:prng_sca",
Expand Down Expand Up @@ -59,6 +60,7 @@ FIRMWARE_DEPS_FI = [

FIRMWARE_DEPS_SCA = [
"//sw/device/tests/penetrationtests/firmware/sca:aes_sca",
"//sw/device/tests/penetrationtests/firmware/sca:hmac_sca",
"//sw/device/tests/penetrationtests/firmware/sca:ibex_sca",
"//sw/device/tests/penetrationtests/firmware/sca:kmac_sca",
"//sw/device/tests/penetrationtests/firmware/sca:prng_sca",
Expand Down
5 changes: 5 additions & 0 deletions sw/device/tests/penetrationtests/firmware/firmware.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "sw/device/tests/penetrationtests/json/commands.h"
#include "sw/device/tests/penetrationtests/json/crypto_fi_commands.h"
#include "sw/device/tests/penetrationtests/json/extclk_sca_fi_commands.h"
#include "sw/device/tests/penetrationtests/json/hmac_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/ibex_fi_commands.h"
#include "sw/device/tests/penetrationtests/json/ibex_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/kmac_sca_commands.h"
Expand All @@ -35,6 +36,7 @@
#include "fi/rom_fi.h"
#include "lib/extclk_sca_fi.h"
#include "sca/aes_sca.h"
#include "sca/hmac_sca.h"
#include "sca/ibex_sca.h"
#include "sca/kmac_sca.h"
#include "sca/prng_sca.h"
Expand All @@ -57,6 +59,9 @@ status_t process_cmd(ujson_t *uj) {
case kPenetrationtestCommandExtClkScaFi:
RESP_ERR(uj, handle_extclk_sca_fi(uj));
break;
case kPenetrationtestCommandHmacSca:
RESP_ERR(uj, handle_hmac_sca(uj));
break;
case kPenetrationtestCommandIbexFi:
RESP_ERR(uj, handle_ibex_fi(uj));
break;
Expand Down
5 changes: 5 additions & 0 deletions sw/device/tests/penetrationtests/firmware/firmware_sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// Include commands
#include "sw/device/tests/penetrationtests/json/aes_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/commands.h"
#include "sw/device/tests/penetrationtests/json/hmac_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/ibex_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/kmac_sca_commands.h"
#include "sw/device/tests/penetrationtests/json/prng_sca_commands.h"
Expand All @@ -22,6 +23,7 @@
// Include handlers
#include "lib/extclk_sca_fi.h"
#include "sca/aes_sca.h"
#include "sca/hmac_sca.h"
#include "sca/ibex_sca.h"
#include "sca/kmac_sca.h"
#include "sca/prng_sca.h"
Expand All @@ -41,6 +43,9 @@ status_t process_cmd(ujson_t *uj) {
case kPenetrationtestCommandExtClkScaFi:
RESP_ERR(uj, handle_extclk_sca_fi(uj));
break;
case kPenetrationtestCommandHmacSca:
RESP_ERR(uj, handle_hmac_sca(uj));
break;
case kPenetrationtestCommandIbexSca:
RESP_ERR(uj, handle_ibex_sca(uj));
break;
Expand Down
20 changes: 20 additions & 0 deletions sw/device/tests/penetrationtests/firmware/sca/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,26 @@ cc_library(
],
)

cc_library(
name = "hmac_sca",
srcs = ["hmac_sca.c"],
hdrs = ["hmac_sca.h"],
deps = [
"//sw/device/lib/base:memory",
"//sw/device/lib/base:status",
"//sw/device/lib/crypto/impl:keyblob",
"//sw/device/lib/crypto/impl:mac",
"//sw/device/lib/crypto/include:datatypes",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing/test_framework:ujson_ottf",
"//sw/device/lib/ujson",
"//sw/device/sca/lib:prng",
"//sw/device/sca/lib:sca",
"//sw/device/tests/penetrationtests/firmware/lib:sca_lib",
"//sw/device/tests/penetrationtests/json:hmac_sca_commands",
],
)

cc_library(
name = "ibex_sca",
srcs = ["ibex_sca.c"],
Expand Down
227 changes: 227 additions & 0 deletions sw/device/tests/penetrationtests/firmware/sca/hmac_sca.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/tests/penetrationtests/firmware/sca/hmac_sca.h"

#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/crypto/impl/keyblob.h"
#include "sw/device/lib/crypto/include/datatypes.h"
#include "sw/device/lib/crypto/include/mac.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/ottf_test_config.h"
#include "sw/device/lib/testing/test_framework/ujson_ottf.h"
#include "sw/device/lib/ujson/ujson.h"
#include "sw/device/sca/lib/prng.h"
#include "sw/device/sca/lib/sca.h"
#include "sw/device/tests/penetrationtests/firmware/lib/sca_lib.h"
#include "sw/device/tests/penetrationtests/json/hmac_sca_commands.h"

#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"

enum {
/**
* Key length in bytes.
*/
kKeyLength = HMACSCA_CMD_MAX_KEY_BYTES,
/**
* Message length in bytes.
*/
kMessageLength = HMACSCA_CMD_MAX_MESSAGE_BYTES,
/**
* Tag length in bytes.
*/
kTagLength = HMACSCA_CMD_MAX_TAG_BYTES,
/**
* Tag length in words.
*/
kTagLengthWord = kTagLength / sizeof(uint32_t),
/**
* Max number of traces per batch.
*/
kNumBatchOpsMax = 128,
};

static status_t trigger_hmac(uint8_t key_buf[], uint8_t mask_buf[],
uint8_t msg_buf[], uint32_t tag_buf[]) {
// Build the key configuration
otcrypto_key_config_t config = {
.version = kOtcryptoLibVersion1,
.key_mode = kOtcryptoKeyModeHmacSha256,
.key_length = kKeyLength,
.hw_backed = kHardenedBoolFalse,
.security_level = kOtcryptoKeySecurityLevelLow,
};

// Create keyblob.
uint32_t keyblob[keyblob_num_words(config)];

// Create blinded key.
TRY(keyblob_from_key_and_mask((uint32_t *)key_buf, (uint32_t *)mask_buf,
config, keyblob));
otcrypto_blinded_key_t key = {
.config = config,
.keyblob_length = sizeof(keyblob),
.keyblob = keyblob,
};

// Create input message.
otcrypto_const_byte_buf_t input_message = {
.len = kMessageLength,
.data = msg_buf,
};

// Create tag.
otcrypto_word32_buf_t tag = {
.len = kTagLengthWord,
.data = tag_buf,
};

sca_set_trigger_high();
TRY(otcrypto_hmac(&key, input_message, tag));
sca_set_trigger_low();
return OK_STATUS();
}

status_t handle_hmac_sca_init(ujson_t *uj) {
// Setup trigger and enable peripherals needed for the test.
sca_select_trigger_type(kScaTriggerTypeSw);
// Enable the HMAC module and disable unused IP blocks to improve
// SCA measurements.
sca_init(kScaTriggerSourceHmac, kScaPeripheralEntropy | kScaPeripheralIoDiv4 |
kScaPeripheralOtbn | kScaPeripheralCsrng |
kScaPeripheralEdn | kScaPeripheralHmac);

// Disable the instruction cache and dummy instructions for SCA.
sca_configure_cpu();

// Read device ID and return to host.
penetrationtest_device_id_t uj_output;
TRY(sca_read_device_id(uj_output.device_id));
RESP_OK(ujson_serialize_penetrationtest_device_id_t, uj, &uj_output);

return OK_STATUS();
}

status_t handle_hmac_sca_batch_fvsr(ujson_t *uj) {
penetrationtest_hmac_sca_key_t uj_key;
penetrationtest_hmac_sca_num_it_t uj_it;

TRY(ujson_deserialize_penetrationtest_hmac_sca_key_t(uj, &uj_key));
TRY(ujson_deserialize_penetrationtest_hmac_sca_num_it_t(uj, &uj_it));

uint8_t batch_messages[kNumBatchOpsMax][kMessageLength];
uint8_t batch_keys[kNumBatchOpsMax][kKeyLength];
uint8_t batch_masks[kNumBatchOpsMax][kKeyLength];

// First generate all FvsR data sets. When sample_fixed,
// the provided key/masks is used and the message is random. When
// not sample_fixed, a random key/mask and a random message is
// generated.
bool sample_fixed = true;
for (size_t it = 0; it < uj_it.num_iterations; it++) {
if (sample_fixed) {
memcpy(batch_keys[it], uj_key.key, kKeyLength);
memcpy(batch_masks[it], uj_key.mask, kKeyLength);
} else {
prng_rand_bytes(batch_keys[it], kKeyLength);
prng_rand_bytes(batch_masks[it], kKeyLength);
}
prng_rand_bytes(batch_messages[it], kMessageLength);
sample_fixed = batch_messages[it][0] & 0x1;
}

// Invoke HMAC for each data set.
uint32_t tag_buf[kTagLengthWord];
for (size_t it = 0; it < uj_it.num_iterations; it++) {
TRY(trigger_hmac(batch_keys[it], batch_masks[it], batch_messages[it],
tag_buf));
}

// Send the last tag to host via UART.
penetrationtest_hmac_sca_tag_t uj_tag;
memcpy(uj_tag.tag, tag_buf, kTagLength);
RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);

return OK_STATUS();
}

status_t handle_hmac_sca_batch_random(ujson_t *uj) {
penetrationtest_hmac_sca_num_it_t uj_it;

TRY(ujson_deserialize_penetrationtest_hmac_sca_num_it_t(uj, &uj_it));

uint8_t batch_messages[kNumBatchOpsMax][kMessageLength];
uint8_t batch_keys[kNumBatchOpsMax][kKeyLength];
uint8_t batch_masks[kNumBatchOpsMax][kKeyLength];

// Generate random keys and messages.
for (size_t it = 0; it < uj_it.num_iterations; it++) {
prng_rand_bytes(batch_keys[it], kKeyLength);
prng_rand_bytes(batch_masks[it], kKeyLength);
prng_rand_bytes(batch_messages[it], kMessageLength);
}

// Invoke HMAC for each data set.
uint32_t tag_buf[kTagLengthWord];
for (size_t it = 0; it < uj_it.num_iterations; it++) {
TRY(trigger_hmac(batch_keys[it], batch_masks[it], batch_messages[it],
tag_buf));
}

// Send the last tag to host via UART.
penetrationtest_hmac_sca_tag_t uj_tag;
memcpy(uj_tag.tag, tag_buf, kTagLength);
RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);

return OK_STATUS();
}

status_t handle_hmac_sca_single(ujson_t *uj) {
penetrationtest_hmac_sca_key_t uj_key;
penetrationtest_hmac_sca_message_t uj_message;

TRY(ujson_deserialize_penetrationtest_hmac_sca_key_t(uj, &uj_key));
TRY(ujson_deserialize_penetrationtest_hmac_sca_message_t(uj, &uj_message));

// Create buffer to store key, mask, message, and tag.
uint8_t key_buf[kKeyLength];
memcpy(key_buf, uj_key.key, kKeyLength);
uint8_t mask_buf[kKeyLength];
memcpy(mask_buf, uj_key.mask, kKeyLength);
uint8_t msg_buf[kMessageLength];
memcpy(msg_buf, uj_message.message, kMessageLength);
uint32_t tag_buf[kTagLengthWord];

// Trigger HMAC operation.
TRY(trigger_hmac(key_buf, mask_buf, msg_buf, tag_buf));

// Copy tag to uJSON type.
penetrationtest_hmac_sca_tag_t uj_tag;
memcpy(uj_tag.tag, tag_buf, kTagLength);

// Send tag to host via UART.
RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);

return OK_STATUS();
}

status_t handle_hmac_sca(ujson_t *uj) {
hmac_sca_subcommand_t cmd;
TRY(ujson_deserialize_hmac_sca_subcommand_t(uj, &cmd));
switch (cmd) {
case kHmacScaSubcommandInit:
return handle_hmac_sca_init(uj);
case kHmacScaSubcommandBatchFvsr:
return handle_hmac_sca_batch_fvsr(uj);
case kHmacScaSubcommandBatchRandom:
return handle_hmac_sca_batch_random(uj);
case kHmacScaSubcommandSingle:
return handle_hmac_sca_single(uj);
default:
LOG_ERROR("Unrecognized HMAC SCA subcommand: %d", cmd);
return INVALID_ARGUMENT();
}
return OK_STATUS();
}
71 changes: 71 additions & 0 deletions sw/device/tests/penetrationtests/firmware/sca/hmac_sca.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_TESTS_PENETRATIONTESTS_FIRMWARE_SCA_HMAC_SCA_H_
#define OPENTITAN_SW_DEVICE_TESTS_PENETRATIONTESTS_FIRMWARE_SCA_HMAC_SCA_H_

#include "sw/device/lib/base/status.h"
#include "sw/device/lib/ujson/ujson.h"

/**
* Initializes the trigger and configures the device for the HMAC SCA test.
*
*
* @param uj An initialized uJSON context.
* @return OK or error.
*/
status_t handle_hmac_sca_init(ujson_t *uj);

/**
* hmac.sca.batch_fvsr test
*
* This SCA penetration test triggers num_iterations HMAC-SHA256 operations
* using a Fixed vs Random (FvsR) dataset. This dataset is generated on the
* device using the PRNG from the SCA library.
*
* SCA traces are captured during trigger_high & trigger_low.
*
* @param uj An initialized uJSON context.
* @return OK or error.
*/
status_t handle_hmac_sca_batch_fvsr(ujson_t *uj);

/**
* hmac.sca.batch_random test
*
* This SCA penetration test triggers num_iterations HMAC-SHA256 operations
* using a random dataset. This dataset is generated on the device using the
* PRNG from the SCA library.
*
* SCA traces are captured during trigger_high & trigger_low.
*
* @param uj An initialized uJSON context.
* @return OK or error.
*/
status_t handle_hmac_sca_batch_random(ujson_t *uj);

/**
* hmac.sca.single test
*
* This SCA penetration test triggers a single HMAC-SHA256 operation using the
* provided key, mask, and message. The tag is returend to the host.
*
* SCA traces are captured during trigger_high & trigger_low.
*
* @param uj An initialized uJSON context.
* @return OK or error.
*/
status_t handle_hmac_sca_single(ujson_t *uj);

/**
* HMAC SCA command handler.
*
* Command handler for the HMAC SCA command.
*
* @param uj An initialized uJSON context.
* @return OK or error.
*/
status_t handle_hmac_sca(ujson_t *uj);

#endif // OPENTITAN_SW_DEVICE_TESTS_PENETRATIONTESTS_FIRMWARE_SCA_HMAC_SCA_H_
Loading

0 comments on commit 372a630

Please sign in to comment.