diff --git a/.gitmodules b/.gitmodules index a736023248aa81de2230ad5d23950646a9d2850f..a21dc049a14f22cdefc6a9cd09fc38c3a542404c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "lib/micropython/micropython-lib"] path = lib/micropython/micropython-lib url = https://github.com/micropython/micropython-lib.git +[submodule "lib/crypto/tiny-AES-c"] + path = lib/crypto/tiny-AES-c + url = https://github.com/kokke/tiny-AES-c +[submodule "lib/crypto/SHA256"] + path = lib/crypto/SHA256 + url = https://github.com/ilvn/SHA256 diff --git a/bootstrap.sh b/bootstrap.sh index e9de7e9748ad859d65363d6b94aa421662503480..f8fb29bfb7dd948006697347a19ac061986af66f 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,8 @@ set -xe cd "$(dirname "$0")" test -d build/ && rm -r build/ -git submodule update --init ./lib/micropython +# Get external libs (MicroPython, tiny-AES-c, SHA256) +git submodule update --init ./lib meson --cross-file card10-cross.ini build/ "$@" set +x diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 3e1df57875d60c776b0acb4afbdf614ce81728d7..a90ad4b70b91caf486fdcee741ced98943c0958d 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,26 @@ 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. + * + * .. warning:: + * + * The exact behaviour of the TRNG is not well understood. Its + * distribution and other parameters are unknown. Only use this + * function if you really want the unmodified values from the + * hardware TRNG to experiment with it. + * * :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 +1951,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/meson.build b/epicardium/meson.build index 0d10151a0bc31e64daeeca645d8e2ff5bd79fcd1..1966750b038090dfd7a5ca7b35405256efbc9e18 100644 --- a/epicardium/meson.build +++ b/epicardium/meson.build @@ -91,7 +91,7 @@ elf = executable( l0der_sources, ble_sources, version_hdr, - dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble, bhy1], + dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble, bhy1, libcrypto], link_with: [api_dispatcher_lib, freertos], link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib], include_directories: [freertos_includes], 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/meson.build b/epicardium/modules/meson.build index 548d8563ea1e7ac2943843931e1733af5fc07dd2..d77cfc2a2b7f491ad5b179d78ff4fc71fba7951c 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -24,7 +24,7 @@ module_sources = files( 'serial.c', 'sleep.c', 'stream.c', - 'trng.c', + 'rng.c', 'usb.c', 'vibra.c', 'watchdog.c', 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 new file mode 100644 index 0000000000000000000000000000000000000000..3be1d66be3dbddd9fdfde933865e492509874b4c --- /dev/null +++ b/epicardium/modules/rng.c @@ -0,0 +1,97 @@ +#include "epicardium.h" + +#include "modules.h" + +#include "MAX77650-Arduino-Library.h" +#include "tiny-AES-c/aes.h" +#include "SHA256/mark2/sha256.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 aes_ctx; + +int epic_trng_read(uint8_t *dest, size_t size) +{ + if (dest == NULL) + return -EFAULT; + + TRNG_Init(NULL); + TRNG_Read(MXC_TRNG, dest, 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( + &aes_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(&aes_ctx, out, sizeof(out)); + memcpy(dest, out, size); + } + + return 0; +} + +void rng_init(void) +{ + uint8_t key[AES_BLOCKLEN]; + uint8_t iv[AES_BLOCKLEN]; + uint8_t hash[32]; + sha256_context ctx; + int i; + + sha256_init(&ctx); + + /* Seed from TRNG. + * Takes about 10 ms. */ + for (i = 0; i < 256; i++) { + uint8_t entropy[AES_BLOCKLEN]; + epic_trng_read(entropy, AES_BLOCKLEN); + sha256_hash(&ctx, entropy, AES_BLOCKLEN); + } + + // Seed from RTC + uint32_t sec, subsec; + while (RTC_GetTime(&sec, &subsec) == E_BUSY) { + mxc_delay(4000); + } + sha256_hash(&ctx, &sec, sizeof(sec)); + sha256_hash(&ctx, &subsec, sizeof(subsec)); + + // Seed from SysTick + uint32_t systick = SysTick->VAL; + sha256_hash(&ctx, &systick, sizeof(systick)); + + /* Seed from ADC. + * Takes about 50 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); + sha256_hash(&ctx, &adc_data, sizeof(adc_data)); + } + MAX77650_setMUX_SEL(PMIC_AMUX_DISABLED); + + sha256_done(&ctx, hash); + memcpy(key, hash, AES_BLOCKLEN); + memcpy(iv, hash + AES_BLOCKLEN, AES_BLOCKLEN); + AES_init_ctx_iv(&aes_ctx, key, iv); +} diff --git a/epicardium/modules/trng.c b/epicardium/modules/trng.c deleted file mode 100644 index 91e001dcdbc7409c42c403a3d884c37091ffff9e..0000000000000000000000000000000000000000 --- a/epicardium/modules/trng.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "epicardium.h" -#include "trng.h" - -int epic_trng_read(uint8_t *dest, size_t size) -{ - if (dest == NULL) - return -EFAULT; - - TRNG_Init(NULL); - TRNG_Read(MXC_TRNG, dest, size); - - return 0; -} diff --git a/lib/crypto/SHA256 b/lib/crypto/SHA256 new file mode 160000 index 0000000000000000000000000000000000000000..1c9e3886f69f9ca83c1af49968d8e4389035ff44 --- /dev/null +++ b/lib/crypto/SHA256 @@ -0,0 +1 @@ +Subproject commit 1c9e3886f69f9ca83c1af49968d8e4389035ff44 diff --git a/lib/crypto/meson.build b/lib/crypto/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..d5eea1f34f6d95423306a4931ff01fbf709b331a --- /dev/null +++ b/lib/crypto/meson.build @@ -0,0 +1,20 @@ +includes = include_directories( + './', +) + +sources = files( + './tiny-AES-c/aes.c', + './SHA256/mark2/sha256.c', +) + +lib = static_library( + 'crypto', + sources, + include_directories: includes, + c_args: '-w', +) + +libcrypto = declare_dependency( + include_directories: includes, + link_with: lib, +) diff --git a/lib/crypto/tiny-AES-c b/lib/crypto/tiny-AES-c new file mode 160000 index 0000000000000000000000000000000000000000..3f69a5899e58e2e398e8c32ce7b3a954dd593ed4 --- /dev/null +++ b/lib/crypto/tiny-AES-c @@ -0,0 +1 @@ +Subproject commit 3f69a5899e58e2e398e8c32ce7b3a954dd593ed4 diff --git a/lib/meson.build b/lib/meson.build index e43c62dbd5ab9b144d6189318973f4db212cb9eb..a51f0c69fca1d1dbe75ad842ef8ce71491e4a81d 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -10,6 +10,7 @@ subdir('./gfx/') subdir('./FreeRTOS/') subdir('./FreeRTOS-Plus/') subdir('./micropython/') +subdir('./crypto/') subdir('./card10/') subdir('./mx25lba/') diff --git a/pycardium/modules/os.c b/pycardium/modules/os.c index d8e6a105f0061e75afd0fae7bce2a8aa8d9e5b79..ea8b4d0f9a814bdc37853fd873697d3fd2ae1d83 100644 --- a/pycardium/modules/os.c +++ b/pycardium/modules/os.c @@ -188,7 +188,7 @@ static mp_obj_t mp_os_urandom(mp_obj_t size_in) vstr_t vstr; vstr_init_len(&vstr, size); - epic_trng_read((uint8_t *)vstr.buf, size); + epic_csprng_read((uint8_t *)vstr.buf, size); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }