Skip to content

Commit

Permalink
[pentest] Cherry-pick Add support for AES SCA measurements on chip
Browse files Browse the repository at this point in the history
This PR manually cherry-picks "Add support for AES SCA measurements on
chip" lowRISC#21741 from earlgrey_es_sival to master  as the
automatic cherry-pick failed due to a merge conflict.

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa authored and vogelpi committed Apr 1, 2024
1 parent 919341e commit 9f23640
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 29 deletions.
2 changes: 1 addition & 1 deletion sw/device/sca/aes_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ static void aes_encrypt(const uint8_t *plaintext, size_t plaintext_len) {
// Using the SecAesStartTriggerDelay hardware parameter, the AES unit is
// configured to start operation 40 cycles after receiving the start trigger.
// This allows Ibex to go to sleep in order to not disturb the capture.
sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles);
sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, false);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion sw/device/sca/kmac_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ static void sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
// configured to start operation 40 cycles after receiving the START and PROC
// commands. This allows Ibex to go to sleep in order to not disturb the
// capture.
sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles);
sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles, false);
}

/**
Expand Down
11 changes: 10 additions & 1 deletion sw/device/sca/lib/sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ void sca_set_trigger_low(void) {
OT_DISCARD(dif_gpio_write(&gpio, trigger_bit_index, false));
}

void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles) {
void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles,
bool sw_trigger) {
// Disable the IO_DIV4_PERI clock to reduce noise during the actual capture.
// This also disables the UART(s) and GPIO modules required for
// communication with the scope. Therefore, it has to be re-enabled after
Expand All @@ -328,8 +329,16 @@ void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles) {
OT_DISCARD(dif_rv_timer_counter_set_enabled(&timer, kRvTimerHart,
kDifToggleEnabled));

if (sw_trigger) {
sca_set_trigger_high();
}

callee();

if (sw_trigger) {
sca_set_trigger_low();
}

wait_for_interrupt();

// Re-enable IO_DIV4_PERI clock to resume communication with the scope.
Expand Down
4 changes: 3 additions & 1 deletion sw/device/sca/lib/sca.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ typedef void (*sca_callee)(void);
*
* @param callee Function to call before putting Ibex to sleep.
* @param sleep_cycles Number of cycles to sleep.
* @param sw_trigger Raise trigger before calling the target function.
*/
void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles);
void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles,
bool sw_trigger);

/**
* Seeds the software LFSR usable e.g. for key masking.
Expand Down
2 changes: 1 addition & 1 deletion sw/device/sca/otbn_vertical/ecc256_keygen_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ static void p256_run_keygen(uint32_t mode, const uint32_t *share0,

// Execute program.
sca_set_trigger_high();
sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles);
sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false);
SS_CHECK_STATUS_OK(otbn_busy_wait_for_done());
sca_set_trigger_low();
}
Expand Down
2 changes: 1 addition & 1 deletion sw/device/sca/otbn_vertical/ecc256_modinv_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static void p256_run_modinv(uint32_t *k0, uint32_t *k1) {

// Execute program.
sca_set_trigger_high();
sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles);
sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false);
otbn_busy_wait_for_done();
sca_set_trigger_low();
}
Expand Down
4 changes: 1 addition & 3 deletions sw/device/sca/sha3_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,7 @@ static void sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
// configured to start operation 40 cycles after receiving the START and PROC
// commands. This allows Ibex to go to sleep in order to not disturb the
// capture.
sca_set_trigger_high();
sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles);
sca_set_trigger_low();
sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles, true);
}

/**
Expand Down
61 changes: 50 additions & 11 deletions sw/device/tests/crypto/cryptotest/firmware/aes_sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

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

/**
* Enable FPGA mode.
*/
static bool fpga_mode = false;

enum {
kAesKeyLengthMax = 32,
kAesKeyLength = 16,
Expand Down Expand Up @@ -238,7 +243,15 @@ static aes_sca_error_t aes_encrypt(const uint8_t *plaintext,
}

// Start AES operation (this triggers the capture) and go to sleep.
sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles);
if (fpga_mode) {
// On the FPGA, the AES block automatically sets and unsets the trigger.
sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, false);
} else {
// On the chip, we need to manually set and unset the trigger. This is done
// in this function to have the trigger as close as possible to the AES
// operation.
sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, true);
}
return aesScaOk;
}

Expand Down Expand Up @@ -302,11 +315,15 @@ status_t handle_aes_sca_single_encrypt(ujson_t *uj) {
block_ctr = 1;
}

sca_set_trigger_high();
if (fpga_mode) {
sca_set_trigger_high();
}
if (aes_encrypt(uj_data.text, uj_data.text_length) != aesScaOk) {
return ABORTED();
}
sca_set_trigger_low();
if (fpga_mode) {
sca_set_trigger_low();
}

TRY(aes_send_ciphertext(false, uj));
return OK_STATUS(0);
Expand Down Expand Up @@ -391,14 +408,18 @@ status_t handle_aes_sca_batch_encrypt(ujson_t *uj) {
block_ctr = num_encryptions;
}

sca_set_trigger_high();
if (fpga_mode) {
sca_set_trigger_high();
}
for (uint32_t i = 0; i < num_encryptions; ++i) {
if (aes_encrypt(plaintext_random, kAesTextLength) != aesScaOk) {
return ABORTED();
}
aes_serial_advance_random();
}
sca_set_trigger_low();
if (fpga_mode) {
sca_set_trigger_low();
}

TRY(aes_send_ciphertext(true, uj));

Expand Down Expand Up @@ -451,7 +472,9 @@ status_t handle_aes_sca_batch_alternative_encrypt(ujson_t *uj) {
// Set trigger high outside of loop
// On FPGA, the trigger is AND-ed with AES !IDLE and creates a LO-HI-LO per
// AES operation
sca_set_trigger_high();
if (fpga_mode) {
sca_set_trigger_high();
}
dif_aes_data_t ciphertext;
for (uint32_t i = 0; i < num_encryptions; ++i) {
// Encrypt
Expand All @@ -472,7 +495,9 @@ status_t handle_aes_sca_batch_alternative_encrypt(ujson_t *uj) {
// Use ciphertext as next plaintext (incl. next call to this function)
memcpy(batch_plaintext, ciphertext.data, kAesTextLength);
}
sca_set_trigger_low();
if (fpga_mode) {
sca_set_trigger_low();
}

// send last ciphertext
cryptotest_aes_sca_ciphertext_t uj_output;
Expand Down Expand Up @@ -642,7 +667,9 @@ status_t handle_aes_sca_fvsr_key_batch_encrypt(ujson_t *uj) {
return OUT_OF_RANGE();
}

sca_set_trigger_high();
if (fpga_mode) {
sca_set_trigger_high();
}
for (uint32_t i = 0; i < num_encryptions; ++i) {
if (aes_key_mask_and_config(batch_keys[i], kAesKeyLength) != aesScaOk) {
return ABORTED();
Expand All @@ -651,7 +678,9 @@ status_t handle_aes_sca_fvsr_key_batch_encrypt(ujson_t *uj) {
return ABORTED();
}
}
sca_set_trigger_low();
if (fpga_mode) {
sca_set_trigger_low();
}

TRY(aes_send_ciphertext(false, uj));

Expand Down Expand Up @@ -709,12 +738,16 @@ status_t handle_aes_sca_fvsr_data_batch_encrypt(ujson_t *uj) {
sample_fixed = sca_next_lfsr(1, kScaLfsrOrder) & 0x1;
}

sca_set_trigger_high();
if (fpga_mode) {
sca_set_trigger_high();
}
for (uint32_t i = 0; i < num_encryptions; ++i) {
aes_key_mask_and_config(batch_keys[i], kAesKeyLength);
aes_encrypt(batch_plaintexts[i], kAesTextLength);
}
sca_set_trigger_low();
if (fpga_mode) {
sca_set_trigger_low();
}

TRY(aes_send_ciphertext(false, uj));

Expand Down Expand Up @@ -843,6 +876,12 @@ status_t handle_aes_sca_fvsr_key_start_batch_generate(ujson_t *uj) {
* @param uj The received uJSON data.
*/
status_t handle_aes_sca_init(ujson_t *uj) {
// Read mode. FPGA or discrete.
cryptotest_aes_sca_fpga_mode_t uj_data;
TRY(ujson_deserialize_cryptotest_aes_sca_fpga_mode_t(uj, &uj_data));
if (uj_data.fpga_mode == 0x01) {
fpga_mode = true;
}
sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4 | kScaPeripheralAes);

if (dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes) !=
Expand Down
8 changes: 5 additions & 3 deletions sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,8 @@ static kmac_sca_error_t sha3_ujson_absorb(const uint8_t *msg, size_t msg_len) {
if (fpga_mode == false) {
// Start command. On the chip, we need to first issue a START command
// before writing to the message FIFO.
sca_call_and_sleep(kmac_start_cmd, kIbexLoadHashPrefixKeySleepCycles);
sca_call_and_sleep(kmac_start_cmd, kIbexLoadHashPrefixKeySleepCycles,
false);
}

// Write data to message FIFO.
Expand All @@ -556,11 +557,12 @@ static kmac_sca_error_t sha3_ujson_absorb(const uint8_t *msg, size_t msg_len) {
// configured to start operation 320 cycles after receiving the START and
// PROC commands. This allows Ibex to go to sleep in order to not disturb
// the capture.
sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles);
sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles, false);
} else {
// On the chip, issue a PROCESS command to start operation and put Ibex
// into sleep.
sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles);
sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles,
false);
}

return kmacScaOk;
Expand Down
8 changes: 2 additions & 6 deletions sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,11 @@ sha3_sca_error_t sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
// configured to start operation 320 cycles after receiving the START and
// PROC commands. This allows Ibex to go to sleep in order to not disturb
// the capture.
sca_set_trigger_high();
sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles);
sca_set_trigger_low();
sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles, true);
} else {
// On the chip, issue a PROCESS command to start operation and put Ibex
// into sleep.
sca_set_trigger_high();
sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles);
sca_set_trigger_low();
sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles, true);
}

return sha3ScaOk;
Expand Down
4 changes: 4 additions & 0 deletions sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ UJSON_SERDE_STRUCT(CryptotestAesScaLfsr, cryptotest_aes_sca_lfsr_t, AES_SCA_LFSR
field(ciphertext, uint8_t, AESSCA_CMD_MAX_MSG_BYTES) \
field(ciphertext_length, uint32_t)
UJSON_SERDE_STRUCT(CryptotestAesScaCiphertext, cryptotest_aes_sca_ciphertext_t, AES_SCA_CIPHERTEXT);

#define AES_SCA_FPGA_MODE(field, string) \
field(fpga_mode, uint8_t)
UJSON_SERDE_STRUCT(CryptotestAesScaFpgaMode, cryptotest_aes_sca_fpga_mode_t, AES_SCA_FPGA_MODE);
// clang-format on

#ifdef __cplusplus
Expand Down

0 comments on commit 9f23640

Please sign in to comment.