diff --git a/sw/device/sca/aes_serial.c b/sw/device/sca/aes_serial.c index 4cdf2988fc42e..26c215a267bb9 100644 --- a/sw/device/sca/aes_serial.c +++ b/sw/device/sca/aes_serial.c @@ -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); } /** diff --git a/sw/device/sca/kmac_serial.c b/sw/device/sca/kmac_serial.c index ad774a16bca19..239e12b932fe2 100644 --- a/sw/device/sca/kmac_serial.c +++ b/sw/device/sca/kmac_serial.c @@ -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); } /** diff --git a/sw/device/sca/lib/sca.c b/sw/device/sca/lib/sca.c index fe062b6e9d9fa..290422f9daeb9 100644 --- a/sw/device/sca/lib/sca.c +++ b/sw/device/sca/lib/sca.c @@ -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 @@ -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. diff --git a/sw/device/sca/lib/sca.h b/sw/device/sca/lib/sca.h index 19bfcfc54d1e8..c102b6002fdff 100644 --- a/sw/device/sca/lib/sca.h +++ b/sw/device/sca/lib/sca.h @@ -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. diff --git a/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c b/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c index 1e84dc59d4886..bd26fa4e80fda 100644 --- a/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c +++ b/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c @@ -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(); } diff --git a/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c b/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c index ea255260c4ce7..05f051e60de46 100644 --- a/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c +++ b/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c @@ -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(); } diff --git a/sw/device/sca/sha3_serial.c b/sw/device/sca/sha3_serial.c index da7a5c59af38d..cbeb1836ed286 100644 --- a/sw/device/sca/sha3_serial.c +++ b/sw/device/sca/sha3_serial.c @@ -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); } /** diff --git a/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c b/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c index 223290c47442c..b78ddd2510f94 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c @@ -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, @@ -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; } @@ -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); @@ -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)); @@ -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 @@ -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; @@ -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(); @@ -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)); @@ -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)); @@ -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) != diff --git a/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c b/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c index c65d7a5410dc6..5831cd7bbfe3f 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c @@ -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. @@ -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; diff --git a/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c b/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c index 3a8f3961bb177..2181759442fa4 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c @@ -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; diff --git a/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h index 6067d60903714..a891a68100181 100644 --- a/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h @@ -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