blob: fa140e8fd7576de69c06ddffcd9f4f2d78a8040b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/aes.h"
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/sca/aes_serial/sca.h"
#include "sw/device/sca/aes_serial/simple_serial.h"
// This program implements the ChipWhisperer simple serial protocol version 1.1.
// Only set key ('k'), encrypt ('p') and version ('v') commands are implemented.
// Encryption is done in AES-ECB-128 mode.
// See https://wiki.newae.com/SimpleSerial for details.
enum {
kAesKeyLength = 16,
/**
* Number of cycles (at `kClockFreqCpuHz`) that Ibex should sleep to minimize
* noise during AES operations. Caution: This number should be chosen to
* provide enough time. Otherwise, Ibex might wake up while AES is still busy
* and disturb the capture. Currently, we use a start trigger delay of 40
* clock cycles and the scope captures 18 clock cycles at kClockFreqCpuHz (180
* samples). The latter number will likely increase as we improve the security
* hardening.
*/
kIbexAesSleepCycles = 200,
};
static aes_cfg_t aes_cfg;
/**
* Simple serial 'k' (set key) command handler.
*
* This function does not use key shares to simplify side-channel analysis.
* The key must be `kAesKeySize` bytes long.
*
* @param key Key.
* @param key_len Key length.
* @return Result of the operation.
*/
static void aes_serial_set_key(const uint8_t *key, size_t key_len) {
SS_CHECK(key_len == kAesKeyLength);
aes_key_put(key, (uint8_t[kAesKeyLength]){0}, aes_cfg.key_len);
}
/**
* Encrypts a plaintext using the AES peripheral.
*
* This function uses `sca_call_and_sleep()` from the sca library to put Ibex to
* sleep in order to minimize noise during captures. The plaintext must be
* `kAesKeySize` bytes long.
*
* @param plaintext Plaintext.
* @param plaintext_len Length of the plaintext.
* @return Result of the operation.
*/
static void aes_serial_encrypt(const uint8_t *plaintext, size_t plaintext_len) {
aes_data_put_wait(plaintext);
// Start AES operation (this triggers the capture) and go to sleep.
// 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);
}
/**
* Simple serial 'p' (encrypt) command handler.
*
* Encrypts a `kAesKeySize` bytes long plaintext using the AES peripheral and
* sends the ciphertext over UART. This function also handles the trigger
* signal.
*
* @param plaintext Plaintext.
* @param plaintext_len Length of the plaintext.
*/
static void aes_serial_single_encrypt(const uint8_t *plaintext,
size_t plaintext_len) {
SS_CHECK(plaintext_len == kAesKeyLength);
sca_set_trigger_high();
aes_serial_encrypt(plaintext, plaintext_len);
sca_set_trigger_low();
uint8_t ciphertext[kAesKeyLength] = {0};
aes_data_get_wait(ciphertext);
simple_serial_send_packet('r', ciphertext, ARRAYSIZE(ciphertext));
}
/**
* Initializes the AES peripheral.
*/
static void init_aes(void) {
aes_cfg.key_len = kAes128;
aes_cfg.operation = kAesEnc;
aes_cfg.mode = kAesEcb;
aes_cfg.manual_operation = true;
aes_clear();
while (!aes_idle()) {
;
}
aes_init(aes_cfg);
}
/**
* Main function.
*
* Initializes peripherals and processes simple serial packets received over
* UART.
*/
int main(void) {
const dif_uart_t *uart;
sca_init();
sca_get_uart(&uart);
simple_serial_init(uart);
simple_serial_register_handler('k', aes_serial_set_key);
simple_serial_register_handler('p', aes_serial_single_encrypt);
init_aes();
while (true) {
simple_serial_process_packet();
}
}