diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 2ad19134960d6ec35e110266ea0abab3754b255a..6139ae688ba4eec4b1a75af57ad1fd54f59a5dfe 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -119,6 +119,7 @@ typedef _Bool bool; #define API_GPIO_READ_PIN 0xA3 #define API_TRNG_READ 0xB0 +#define API_CSPRNG_READ 0XB1 #define API_PERSONAL_STATE_SET 0xc0 #define API_PERSONAL_STATE_GET 0xc1 @@ -1921,13 +1922,19 @@ API(API_RTC_SCHEDULE_ALARM, int epic_rtc_schedule_alarm(uint32_t timestamp)); API_ISR(EPIC_INT_RTC_ALARM, epic_isr_rtc_alarm); /** - * TRNG + * RNG * ==== */ /** * Read random bytes from the TRNG. * + * Be aware that this function returns raw unprocessed bytes from + * the TRNG. They might be biased or have other kinds of imperfections. + * + * Use :c:func:`epic_csprng_read` for cryptographically safe random + * numbers instead. + * * :param uint8_t * dest: Destination buffer * :param size: Number of bytes to read. * :return: `0` on success or a negative value if an error occured. Possible @@ -1937,6 +1944,20 @@ API_ISR(EPIC_INT_RTC_ALARM, epic_isr_rtc_alarm); */ API(API_TRNG_READ, int epic_trng_read(uint8_t *dest, size_t size)); +/** + * Read random bytes from the CSPRNG. + * + * The random bytes returned are safe to be used for cryptography. + * + * :param uint8_t * dest: Destination buffer + * :param size: Number of bytes to read. + * :return: `0` on success or a negative value if an error occured. Possible + * errors: + * + * - ``-EFAULT``: Invalid destination address. + */ +API(API_CSPRNG_READ, int epic_csprng_read(uint8_t *dest, size_t size)); + /** * MAX30001 * ======== diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c index a9241525bdd68619baaa728c7b1e37c964e3c054..055ae486b391ca0b46b6737689141e1ea175014b 100644 --- a/epicardium/modules/hardware.c +++ b/epicardium/modules/hardware.c @@ -18,7 +18,6 @@ #include "i2c.h" #include "rtc.h" #include "spi.h" -#include "trng.h" #include "wdt.h" /* @@ -83,6 +82,11 @@ int hardware_early_init(void) E_BUSY) ; + /* + * RNG + */ + rng_init(); + /* If we don't have a valid time yet, set it to 2019-01-01 */ if (RTC_GetSecond() < 1546300800L) { epic_rtc_set_milliseconds(1546300800UL * 1000); diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h index c26a1ce6cf7a2480eb982d8b80ab1215d4c06278..14184bd9ca96b367ebcf57a7d8b7739a407df817 100644 --- a/epicardium/modules/modules.h +++ b/epicardium/modules/modules.h @@ -136,4 +136,8 @@ extern gpio_cfg_t gpio_configs[]; /* ---------- Sleep -------------------------------------------------------- */ void sleep_deepsleep(void); + + +void rng_init(void); + #endif /* MODULES_H */ diff --git a/epicardium/modules/rng.c b/epicardium/modules/rng.c index 91e001dcdbc7409c42c403a3d884c37091ffff9e..0357f10697889798f9bd9c731611f46a7f1bcc7c 100644 --- a/epicardium/modules/rng.c +++ b/epicardium/modules/rng.c @@ -1,6 +1,20 @@ #include "epicardium.h" + +#include "modules.h" + +#include "MAX77650-Arduino-Library.h" +#include "tiny-AES-c/aes.h" + +#include "mxc_sys.h" +#include "adc.h" +#include "mxc_delay.h" +#include "rtc.h" #include "trng.h" +#include <string.h> + +static struct AES_ctx ctx; + int epic_trng_read(uint8_t *dest, size_t size) { if (dest == NULL) @@ -11,3 +25,81 @@ int epic_trng_read(uint8_t *dest, size_t size) return 0; } + +int epic_csprng_read(uint8_t *dest, size_t size) +{ + if (size >= AES_BLOCKLEN) { + int block_count = size / AES_BLOCKLEN; + AES_CTR_xcrypt_buffer(&ctx, dest, block_count * AES_BLOCKLEN); + size -= block_count * AES_BLOCKLEN; + dest += block_count * AES_BLOCKLEN; + } + + if (size > 0) { + uint8_t out[AES_BLOCKLEN]; + AES_CTR_xcrypt_buffer(&ctx, out, sizeof(out)); + memcpy(dest, out, size); + } + + return 0; +} + +static void xor + (uint8_t * a, uint8_t *b, size_t size) { + while (size--) { + *a = *a ^ *b; + a++; + b++; + } + } + + static void seed(uint8_t *entropy, size_t size) +{ + uint8_t key_new[AES_BLOCKLEN]; + uint8_t iv[AES_BLOCKLEN] = { 0 }; + epic_csprng_read(key_new, AES_BLOCKLEN); + xor(key_new, entropy, size); + AES_init_ctx_iv(&ctx, key_new, iv); +} + +void rng_init(void) +{ + uint8_t key[AES_BLOCKLEN] = { 0 }; + uint8_t iv[AES_BLOCKLEN] = { 0 }; + int i; + + AES_init_ctx_iv(&ctx, key, iv); + + /* Seed from TRNG. + * Takes about 30 ms. */ + for (i = 0; i < 256; i++) { + uint8_t entropy[AES_BLOCKLEN]; + epic_trng_read(entropy, AES_BLOCKLEN); + seed(entropy, AES_BLOCKLEN); + } + + // Seed from RTC + uint32_t sec, subsec; + while (RTC_GetTime(&sec, &subsec) == E_BUSY) { + mxc_delay(4000); + } + seed((uint8_t *)&sec, sizeof(sec)); + seed((uint8_t *)&subsec, sizeof(subsec)); + + // Seed from SysTick + uint32_t systick = SysTick->VAL; + seed((uint8_t *)&systick, sizeof(systick)); + + /* Seed from ADC. + * Takes about 80 ms */ + ADC_Init(0x9, NULL); + GPIO_Config(&gpio_cfg_adc0); + MAX77650_setMUX_SEL(PMIC_AMUX_BATT_U); + for (i = 0; i < 256; i++) { + uint16_t adc_data; + ADC_StartConvert(ADC_CH_0, 0, 0); + ADC_GetData(&adc_data); + seed((uint8_t *)&adc_data, sizeof(adc_data)); + } + MAX77650_setMUX_SEL(PMIC_AMUX_DISABLED); +}