From 5ca312e6f7848c3830b7c9b98f024f0c184007c4 Mon Sep 17 00:00:00 2001 From: trigaux Date: Wed, 28 May 2025 17:13:26 -0400 Subject: [PATCH 1/6] Make ui use cmake. --- .gitmodules | 3 + firmware/ui/.mxproject | 15 +- firmware/ui/CMakeLists.txt | 96 + firmware/ui/CMakePresets.json | 60 + firmware/ui/Makefile | 257 +- firmware/ui/STM32F405XX_FLASH.ld | 227 + firmware/ui/cmake/gcc-arm-none-eabi.cmake | 45 + firmware/ui/cmake/stm32cubemx/CMakeLists.txt | 100 + firmware/ui/dependencies/sframe | 1 + firmware/ui/inc/app_main.hh | 4 +- firmware/ui/inc/gsl/gsl-lite.hpp | 4156 ------------------ firmware/ui/inc/sframe/map.h | 111 - firmware/ui/inc/sframe/sframe.h | 205 - firmware/ui/inc/sframe/vector.h | 142 - firmware/ui/src/sframe/crypto.cc | 97 - firmware/ui/src/sframe/crypto.h | 51 - firmware/ui/src/sframe/crypto_stm32.cc | 273 -- firmware/ui/src/sframe/header.cc | 203 - firmware/ui/src/sframe/header.h | 34 - firmware/ui/src/sframe/sframe.cc | 358 -- firmware/ui/ui.ioc | 11 +- 21 files changed, 544 insertions(+), 5905 deletions(-) create mode 100644 firmware/ui/CMakeLists.txt create mode 100644 firmware/ui/CMakePresets.json create mode 100644 firmware/ui/STM32F405XX_FLASH.ld create mode 100644 firmware/ui/cmake/gcc-arm-none-eabi.cmake create mode 100644 firmware/ui/cmake/stm32cubemx/CMakeLists.txt create mode 160000 firmware/ui/dependencies/sframe delete mode 100644 firmware/ui/inc/gsl/gsl-lite.hpp delete mode 100644 firmware/ui/inc/sframe/map.h delete mode 100644 firmware/ui/inc/sframe/sframe.h delete mode 100644 firmware/ui/inc/sframe/vector.h delete mode 100644 firmware/ui/src/sframe/crypto.cc delete mode 100644 firmware/ui/src/sframe/crypto.h delete mode 100644 firmware/ui/src/sframe/crypto_stm32.cc delete mode 100644 firmware/ui/src/sframe/header.cc delete mode 100644 firmware/ui/src/sframe/header.h delete mode 100644 firmware/ui/src/sframe/sframe.cc diff --git a/.gitmodules b/.gitmodules index ebd11ef5..2a81cc99 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "firmware/net/components/nlohmann_json/lib"] path = firmware/net/components/nlohmann_json/lib url = git@github.com:nlohmann/json.git +[submodule "firmware/ui/dependencies/sframe"] + path = firmware/ui/dependencies/sframe + url = https://github.com/GhostofCookie/sframe.git diff --git a/firmware/ui/.mxproject b/firmware/ui/.mxproject index a0d3afd8..133c0079 100644 --- a/firmware/ui/.mxproject +++ b/firmware/ui/.mxproject @@ -1,24 +1,11 @@ [PreviousLibFiles] -LibFiles=Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_system.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_utils.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dmamux.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_usart.h;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_system.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_utils.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dmamux.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_usart.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f405xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Drivers/CMSIS/Include/mpu_armv7.h;Drivers/CMSIS/Include/core_cm35p.h;Drivers/CMSIS/Include/cmsis_armclang_ltm.h;Drivers/CMSIS/Include/pac_armv81.h;Drivers/CMSIS/Include/tz_context.h;Drivers/CMSIS/Include/cmsis_armclang.h;Drivers/CMSIS/Include/cachel1_armv7.h;Drivers/CMSIS/Include/core_cm1.h;Drivers/CMSIS/Include/mpu_armv8.h;Drivers/CMSIS/Include/core_cm7.h;Drivers/CMSIS/Include/cmsis_iccarm.h;Drivers/CMSIS/Include/core_sc000.h;Drivers/CMSIS/Include/cmsis_armcc.h;Drivers/CMSIS/Include/pmu_armv8.h;Drivers/CMSIS/Include/core_cm23.h;Drivers/CMSIS/Include/core_armv81mml.h;Drivers/CMSIS/Include/core_cm3.h;Drivers/CMSIS/Include/cmsis_gcc.h;Drivers/CMSIS/Include/core_sc300.h;Drivers/CMSIS/Include/core_starmc1.h;Drivers/CMSIS/Include/core_cm4.h;Drivers/CMSIS/Include/core_armv8mml.h;Drivers/CMSIS/Include/cmsis_compiler.h;Drivers/CMSIS/Include/core_cm0.h;Drivers/CMSIS/Include/core_cm55.h;Drivers/CMSIS/Include/core_cm33.h;Drivers/CMSIS/Include/core_armv8mbl.h;Drivers/CMSIS/Include/core_cm0plus.h;Drivers/CMSIS/Include/core_cm85.h;Drivers/CMSIS/Include/cmsis_version.h; - -[PreviousUsedIarFiles] -SourceFiles=../Core/Src/main.c;../Core/Src/stm32f4xx_it.c;../Core/Src/stm32f4xx_hal_msp.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;../Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;../Core/Src/system_stm32f4xx.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;../Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;../Core/Src/system_stm32f4xx.c;;; -HeaderPath=../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Core/Inc; -CDefines=USE_HAL_DRIVER;STM32F405xx;USE_HAL_DRIVER;USE_HAL_DRIVER; - -[PreviousUsedMakefileFiles] -SourceFiles=Core/Src/main.c;Core/Src/stm32f4xx_it.c;Core/Src/stm32f4xx_hal_msp.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Core/Src/system_stm32f4xx.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Core/Src/system_stm32f4xx.c;;; -HeaderPath=Drivers/STM32F4xx_HAL_Driver/Inc;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;Drivers/CMSIS/Device/ST/STM32F4xx/Include;Drivers/CMSIS/Include;Core/Inc; -CDefines=USE_HAL_DRIVER;STM32F405xx;USE_HAL_DRIVER;USE_HAL_DRIVER; +LibFiles=Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_system.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_utils.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dmamux.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_usart.h;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rcc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_system.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_utils.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_gpio.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dma.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_dmamux.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_pwr.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_cortex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_exti.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_crc.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2s_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rng.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_spi.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_tim.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_usart.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f405xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Drivers/CMSIS/Include/core_cm85.h;Drivers/CMSIS/Include/cachel1_armv7.h;Drivers/CMSIS/Include/pac_armv81.h;Drivers/CMSIS/Include/core_cm7.h;Drivers/CMSIS/Include/tz_context.h;Drivers/CMSIS/Include/core_cm3.h;Drivers/CMSIS/Include/cmsis_compiler.h;Drivers/CMSIS/Include/cmsis_armclang.h;Drivers/CMSIS/Include/core_cm35p.h;Drivers/CMSIS/Include/mpu_armv7.h;Drivers/CMSIS/Include/cmsis_armcc.h;Drivers/CMSIS/Include/core_cm4.h;Drivers/CMSIS/Include/core_cm0.h;Drivers/CMSIS/Include/cmsis_iccarm.h;Drivers/CMSIS/Include/core_armv81mml.h;Drivers/CMSIS/Include/core_armv8mml.h;Drivers/CMSIS/Include/core_sc000.h;Drivers/CMSIS/Include/core_cm55.h;Drivers/CMSIS/Include/core_cm1.h;Drivers/CMSIS/Include/mpu_armv8.h;Drivers/CMSIS/Include/core_sc300.h;Drivers/CMSIS/Include/cmsis_gcc.h;Drivers/CMSIS/Include/cmsis_version.h;Drivers/CMSIS/Include/pmu_armv8.h;Drivers/CMSIS/Include/core_cm23.h;Drivers/CMSIS/Include/core_cm33.h;Drivers/CMSIS/Include/core_cm0plus.h;Drivers/CMSIS/Include/core_armv8mbl.h;Drivers/CMSIS/Include/core_starmc1.h;Drivers/CMSIS/Include/cmsis_armclang_ltm.h; [PreviousUsedCMakes] SourceFiles=Core/Src/main.c;Core/Src/stm32f4xx_it.c;Core/Src/stm32f4xx_hal_msp.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Core/Src/system_stm32f4xx.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c;Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c;Core/Src/system_stm32f4xx.c;;; HeaderPath=Drivers/STM32F4xx_HAL_Driver/Inc;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;Drivers/CMSIS/Device/ST/STM32F4xx/Include;Drivers/CMSIS/Include;Core/Inc; CDefines=USE_HAL_DRIVER;STM32F405xx;USE_HAL_DRIVER;USE_HAL_DRIVER; -[] -SourceFiles=;; - [PreviousGenFiles] AdvancedFolderStructure=true HeaderFileListSize=3 diff --git a/firmware/ui/CMakeLists.txt b/firmware/ui/CMakeLists.txt new file mode 100644 index 00000000..3b5ee695 --- /dev/null +++ b/firmware/ui/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.22) +set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake") + +add_compile_options( + -mthumb + -fexceptions +) + +# +# This file is generated only once, +# and is not re-generated if converter is called multiple times. +# +# User is free to modify the file as much as necessary +# + +# Setup compiler settings +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) + +set(CRYPTO "STM32_CM4" CACHE STRING "") +set(NO_ALLOC ON CACHE BOOL "") +add_subdirectory(dependencies/sframe) + + +# Define the build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# Set the project name +set(CMAKE_PROJECT_NAME ui) + +# Include toolchain file +include("cmake/gcc-arm-none-eabi.cmake") + +# Enable compile command to ease indexing with e.g. clangd +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) + +# Core project settings +project(${CMAKE_PROJECT_NAME}) +message("Build type: " ${CMAKE_BUILD_TYPE}) + +# Enable CMake support for ASM and C languages +enable_language(C ASM) + +# Create an executable object type +add_executable(${CMAKE_PROJECT_NAME}) + +# Add STM32CubeMX generated sources +add_subdirectory(cmake/stm32cubemx) + +# Link directories setup +target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE + # Add user defined library search paths +) + +file(GLOB_RECURSE CXX_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc") +file(GLOB_RECURSE SHARED_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../shared/*.cc") +target_sources(${CMAKE_PROJECT_NAME} PRIVATE + ${CXX_SOURCES} + ${SHARED_SOURCES} +) + +# Add include paths +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Core/Inc + ${CMAKE_CURRENT_SOURCE_DIR}/inc + ${CMAKE_CURRENT_SOURCE_DIR}/inc/fonts + ${CMAKE_CURRENT_SOURCE_DIR}/../shared_inc + ${CMAKE_CURRENT_SOURCE_DIR}/../shared/ +) + +# Add project symbols (macros) +target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE +) + +# Add linked libraries +target_link_libraries(${CMAKE_PROJECT_NAME} + stm32cubemx + + sframe +) + +set(BIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin") +set(HEX_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.hex") + +add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.elf ${BIN_FILE} + COMMAND ${CMAKE_OBJCOPY} -O ihex ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.elf ${HEX_FILE} + COMMENT "Generating .bin and .hex files" +) diff --git a/firmware/ui/CMakePresets.json b/firmware/ui/CMakePresets.json new file mode 100644 index 00000000..1ed4e19d --- /dev/null +++ b/firmware/ui/CMakePresets.json @@ -0,0 +1,60 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake", + "cacheVariables": { + } + }, + { + "name": "Debug", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "RelWithDebInfo", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "Release", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "MinSizeRel", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "MinSizeRel" + } + } + ], + "buildPresets": [ + { + "name": "Debug", + "configurePreset": "Debug" + }, + { + "name": "RelWithDebInfo", + "configurePreset": "RelWithDebInfo" + }, + { + "name": "Release", + "configurePreset": "Release" + }, + { + "name": "MinSizeRel", + "configurePreset": "MinSizeRel" + } + ] +} \ No newline at end of file diff --git a/firmware/ui/Makefile b/firmware/ui/Makefile index eb798592..bad92cf0 100644 --- a/firmware/ui/Makefile +++ b/firmware/ui/Makefile @@ -33,9 +33,6 @@ OPT = -Os ####################################### # Build path BUILD_DIR = ./build -STM32_CRYPTO_DIR= -STM32_CRYPTO_INCLUDE_DIR=${STM32_CRYPTO_DIR}/include -STM32_CRYPTO_LIB_DIR=${STM32_CRYPTO_DIR}/lib ####################################### # programming @@ -50,263 +47,17 @@ CUBE_PROGRAMMER_ARGS = -c port=${PORT} br=${BAUD} P=even db=8 -w ${BUILD_DIR}/${ DOCKER_IMAGE = build-hactar-ui mft=compile -###################################### -# source -###################################### -# HAL C sources -SRCS_C = \ -main.c \ -stm32f4xx_hal_msp.c \ -stm32f4xx_it.c \ -system_stm32f4xx.c \ -stm32f4xx_hal.c \ -stm32f4xx_hal_adc.c \ -stm32f4xx_hal_cortex.c \ -stm32f4xx_hal_dma.c \ -stm32f4xx_hal_dma_ex.c \ -stm32f4xx_hal_exti.c \ -stm32f4xx_hal_flash.c \ -stm32f4xx_hal_flash_ex.c \ -stm32f4xx_hal_flash_ramfunc.c \ -stm32f4xx_hal_gpio.c \ -stm32f4xx_hal_i2c.c \ -stm32f4xx_hal_i2s.c \ -stm32f4xx_hal_i2s_ex.c \ -stm32f4xx_hal_pwr.c \ -stm32f4xx_hal_pwr_ex.c \ -stm32f4xx_hal_spi.c \ -stm32f4xx_hal_tim.c \ -stm32f4xx_hal_tim_ex.c \ -stm32f4xx_hal_rcc.c \ -stm32f4xx_hal_rcc_ex.c \ -stm32f4xx_hal_uart.c \ -stm32f4xx_hal_rng.c \ -stm32f4xx_hal_crc.c \ -sysmem.c \ -syscalls.c - -# User C/C++ sources -SRCS_CC = $(shell find src -name '*.cc' -exec basename {} \;) -SRCS_CC += serial_handler.cc - -SRCS_C += $(shell find src -name '*.c' -exec basename {} \;) - -SRCS = ${SRCS_CC} ${SRCS_C} - -# ASM sources -ASM_SOURCES = \ -startup_stm32f405xx.s - -# C includes -INCS = \ --IDrivers/STM32F4xx_HAL_Driver/Inc \ --IDrivers/STM32F4xx_HAL_Driver/Inc/Legacy \ --IDrivers/CMSIS/Device/ST/STM32F4xx/Include \ --IDrivers/CMSIS/Include - -ifdef STM32_CRYPTO_DIR -INCS += -I${STM32_CRYPTO_INCLUDE_DIR} -endif - -INCS += $(addprefix -I,$(shell find inc -type d)) -INCS += $(addprefix -I,$(shell find Core/Inc -type d)) -INCS += -I../shared_inc -INCS += -I../shared - -####################################### -# vpaths -####################################### -VPATH = $(shell find src -type d) -VPATH += $(shell find Core/Src -type d) -VPATH += Drivers/STM32F4xx_HAL_Driver/Src -VPATH += $(shell find ../shared -type d) -# VPATH += $(BSP_SRC_DIR) -# VPATH += $(CMSIS_CORE_SRC_DIR) -# VPATH += $(CMSIS_DEVICE_SRC_DIR) -# VPATH += $(HAL_SRC_DIR) - -####################################### -# openocd -####################################### -# TODO - - -####################################### -# binaries -####################################### -PREFIX = arm-none-eabi- -# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx) -# either it can be added to the PATH environment variable. -ifdef GCC_PATH -CC = $(GCC_PATH)/$(PREFIX)g++ -AS = $(GCC_PATH)/$(PREFIX)g++ -x assembler-with-cpp -CP = $(GCC_PATH)/$(PREFIX)objcopy -DP = $(GCC_PATH)/$(PREFIX)objdump -SZ = $(GCC_PATH)/$(PREFIX)size -else -CC = $(PREFIX)g++ -AS = $(PREFIX)g++ -x assembler-with-cpp -CP = $(PREFIX)objcopy -DP = $(PREFIX)objdump -SZ = $(PREFIX)size -endif -HEX = $(CP) -O ihex -BIN = $(CP) -O binary -S - -####################################### -# CFLAGS -####################################### -# cpu -CPU = -mcpu=cortex-m4 - -# fpu -FPU = -mfpu=fpv4-sp-d16 - -# float-abi -FLOAT-ABI = -mfloat-abi=hard - -# mcu -MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI) - -# macros for gcc -# AS defines -AS_DEFS = - -# C defines -C_DEFS = \ --DUSE_HAL_DRIVER \ --DSTM32F405xx - - -# AS includes -AS_INCLUDES = - - -# compile gcc flags -ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections - -CFLAGS += $(MCU) $(C_DEFS) $(INCS) $(OPT) -std=c++17 \ - -Wall -Wextra \ - -fdata-sections -ffunction-sections -fexceptions - # -Wshadow \ - # -Wnon-virtual-dtor \ - # -Wcast-align \ - # -Wunused \ - # -Woverloaded-virtual \ - # -Wpedantic \ - # -Wconversion \ - # -Wsign-conversion \ - # -Wnull-dereference \ - # -Wdouble-promotion \ - # -Wformat=2 \ - # -Wimplicit-fallthrough - -HAL_CFLAGS += $(MCU) $(C_DEFS) $(INCS) -Os -Wall -fdata-sections -ffunction-sections - -ifeq ($(DEBUG), 1) -CFLAGS += -g -gdwarf-2 -HAL_CFLAGS += -g -gdwarf-2 -endif - -ifdef STM32_CRYPTO_DIR -CFLAGS += -DCRYPTO -DNO_ALLOC -endif - -ifeq (${PROGRAMMER}, CUBE) - ifeq (${OS}, WINDOWS_NT) - EXT = .exe - else - EXT = - endif -endif - OCD_DIR = /usr/share/openocd/scripts OCDFLAGS = -f interface/stlink.cfg -f target/stm32f4x.cfg - -# Generate dependency informationINCS = $(addprefix -I,$(shell find inc -type d))INCS = $(addprefix -I,$(shell find inc -type d))INCS = $(addprefix -I,$(shell find inc -type d)) -CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -HAL_CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" - - -####################################### -# LDFLAGS -####################################### -# link script -LDSCRIPT = stm32f405rgtx_flash.ld - -# libraries -# LIBS = -lc -lm -lnosys -lrdimon -lSTM32Cryptographic_CM4 -LIBS = -lc -lm -lnosys -LIBDIR = -Llib -LDFLAGS = $(MCU) --specs=nosys.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/${TARGET}.map,--cref -Wl,--gc-sections - -ifdef STM32_CRYPTO_DIR -LIBS += -lSTM32Cryptographic_CM4 -LIBDIR += -L$(STM32_CRYPTO_LIB_DIR) -endif -####################################### -# build the application -####################################### -# list of objects -OBJECTS_C = $(addprefix $(BUILD_DIR)/,$(SRCS_C:.c=.o)) -# vpath %.c $(sort $(dir $(SRCS_C))) -OBJECTS_CC = $(addprefix $(BUILD_DIR)/,$(SRCS_CC:.cc=.o)) -# vpath %.cc $(sort $(dir $(SRCS_CC))) -# list of ASM program objects -OBJECTS_S = $(addprefix $(BUILD_DIR)/,$(ASM_SOURCES:.s=.o)) -# vpath %.s $(sort $(dir $(ASM_SOURCES))) - -OBJECTS = ${OBJECTS_C} ${OBJECTS_CC} ${OBJECTS_S} - -# Deps -DEPS_C = $(addprefix ${BUILD_DIR}/,$(SRCS_C:.c=.d)) -DEPS_CC = $(addprefix ${BUILD_DIR}/,$(SRCS_CC:.cc=.d)) -DEPS = ${DEPS_C} ${DEPS_CC} - .PHONY: all # default action: build all all: info compile --include $(DEPS) - -# So I can silence the warning from the HAL lib -${BUILD_DIR}/stm32f4%.o : stm32f4%.c | ${BUILD_DIR} - @echo "[C] $(notdir $<)" - @$(CC) $(HAL_CFLAGS) -c -o $@ $< -MMD -MF ${BUILD_DIR}/$(*F).d -${BUILD_DIR}/main.o : main.c | ${BUILD_DIR} - @echo "[C] $(notdir $<)" - @$(CC) $(HAL_CFLAGS) -c -o $@ $< -MMD -MF ${BUILD_DIR}/$(*F).d - -${BUILD_DIR}/%.o : %.c | ${BUILD_DIR} - @echo "[C] $(notdir $<)" - @$(CC) $(CFLAGS) -c -o $@ $< -MMD -MF ${BUILD_DIR}/$(*F).d - -${BUILD_DIR}/%.o : %.cc | ${BUILD_DIR} - @echo "[CC] $(notdir $<)" - @$(CC) $(CFLAGS) -c -o $@ $< -MMD -MF ${BUILD_DIR}/$(*F).d - -$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR) - @echo "[S] $(notdir $<)" - @$(AS) -c $(CFLAGS) $< -o $@ - -$(BUILD_DIR)/${TARGET}.elf: ${OBJECTS} | ${BUILD_DIR} - @echo "[LD] ${TARGET}.elf" - @$(CC) $(OBJECTS) $(LDFLAGS) -o $@ - @$(DP) -St $@ >$(BUILD_DIR)/${TARGET}.lst - $(SZ) $@ - -$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR) - @echo "[LD] ${TARGET}.hex" - @$(HEX) $< $@ - $(SZ) $@ - -$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR) - @echo "[LD] ${TARGET}.bin" - @$(BIN) $< $@ - -compile: $(BUILD_DIR)/${TARGET}.bin $(BUILD_DIR)/${TARGET}.hex +compile: CMakeLists.txt + cmake -B $(BUILD_DIR) -DCMAKE_TOOLCHAIN_FILE=cmake/gcc-arm-none-eabi.cmake -DSTM32Cryptographic_ROOT_DIR=${STM32_CRYPTO_DIR} + cmake --build $(BUILD_DIR) -j upload: compile st-flash --reset --format ihex write ${BUILD_DIR}/${TARGET}.hex @@ -326,7 +77,6 @@ upload_cube_swd: compile STM32_Programmer_CLI${EXT} ${CUBE_PROGRAMMER_ARGS_SWD} ; \ fi \ - # NOTE - mft is the makefile target if you want to use something other than compile docker: @if ! docker image inspect ${DOCKER_IMAGE} > /dev/null 2>&1; then \ @@ -351,7 +101,6 @@ openocd: monitor: python3 ../tools/monitor.py ${PORT} ${BAUD} - format: find inc -iname "*.h" -or -iname "*.hh" | xargs clang-format -i find src -iname "*.c" -or -iname "*.cc" | xargs clang-format -i diff --git a/firmware/ui/STM32F405XX_FLASH.ld b/firmware/ui/STM32F405XX_FLASH.ld new file mode 100644 index 00000000..5bbe8618 --- /dev/null +++ b/firmware/ui/STM32F405XX_FLASH.ld @@ -0,0 +1,227 @@ +/* +****************************************************************************** +** + +** File : LinkerScript.ld +** +** Author : STM32CubeMX +** +** Abstract : Linker script for STM32F405RGTx series +** 1024Kbytes FLASH and 192Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +**

© COPYRIGHT(c) 2025 STMicroelectronics

+** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of STMicroelectronics nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K +CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K +FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + _siccmram = LOADADDR(.ccmram); + + /* CCM-RAM section + * + * IMPORTANT NOTE! + * If initialized variables will be placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; /* create a global symbol at ccmram start */ + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; /* create a global symbol at ccmram end */ + } >CCMRAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + +} + + diff --git a/firmware/ui/cmake/gcc-arm-none-eabi.cmake b/firmware/ui/cmake/gcc-arm-none-eabi.cmake new file mode 100644 index 00000000..86693d25 --- /dev/null +++ b/firmware/ui/cmake/gcc-arm-none-eabi.cmake @@ -0,0 +1,45 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ARM) + +set(CMAKE_C_COMPILER_ID GNU) +set(CMAKE_CXX_COMPILER_ID GNU) + +# Some default GCC settings +# arm-none-eabi- must be part of path environment +set(TOOLCHAIN_PREFIX arm-none-eabi-) + +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy) +set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size) + +set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +# MCU specific flags +set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard ") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}") +set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -fdata-sections -ffunction-sections") + +set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") +set(CMAKE_C_FLAGS_RELEASE "-Os -g0") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") +set(CMAKE_CXX_FLAGS_RELEASE "-Os -g0") + +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics") + +set(CMAKE_C_LINK_FLAGS "${TARGET_FLAGS}") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T \"${CMAKE_SOURCE_DIR}/STM32F405XX_FLASH.ld\"") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --specs=nano.specs") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lc -lm -Wl,--end-group") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--print-memory-usage") + +set(CMAKE_CXX_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group") \ No newline at end of file diff --git a/firmware/ui/cmake/stm32cubemx/CMakeLists.txt b/firmware/ui/cmake/stm32cubemx/CMakeLists.txt new file mode 100644 index 00000000..b28bb47a --- /dev/null +++ b/firmware/ui/cmake/stm32cubemx/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.22) +# Enable CMake support for ASM and C languages +enable_language(C ASM) +# STM32CubeMX generated symbols (macros) +set(MX_Defines_Syms + USE_HAL_DRIVER + STM32F405xx + $<$:DEBUG> +) + +# STM32CubeMX generated include paths +set(MX_Include_Dirs + ${CMAKE_SOURCE_DIR}/Core/Inc + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Inc + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Inc/Legacy + ${CMAKE_SOURCE_DIR}/Drivers/CMSIS/Device/ST/STM32F4xx/Include + ${CMAKE_SOURCE_DIR}/Drivers/CMSIS/Include +) + +# STM32CubeMX generated application sources +set(MX_Application_Src + ${CMAKE_SOURCE_DIR}/Core/Src/main.c + ${CMAKE_SOURCE_DIR}/Core/Src/stm32f4xx_it.c + ${CMAKE_SOURCE_DIR}/Core/Src/stm32f4xx_hal_msp.c + ${CMAKE_SOURCE_DIR}/Core/Src/sysmem.c + ${CMAKE_SOURCE_DIR}/Core/Src/syscalls.c + ${CMAKE_SOURCE_DIR}/startup_stm32f405xx.s +) + +# STM32 HAL/LL Drivers +set(STM32_Drivers_Src + ${CMAKE_SOURCE_DIR}/Core/Src/system_stm32f4xx.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_crc.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c + ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c +) + +# Drivers Midllewares + + + +# Link directories setup +set(MX_LINK_DIRS + +) +# Project static libraries +set(MX_LINK_LIBS + STM32_Drivers + +) +# Interface library for includes and symbols +add_library(stm32cubemx INTERFACE) +target_include_directories(stm32cubemx INTERFACE ${MX_Include_Dirs}) +target_compile_definitions(stm32cubemx INTERFACE ${MX_Defines_Syms}) + +# Create STM32_Drivers static library +add_library(STM32_Drivers OBJECT) +target_sources(STM32_Drivers PRIVATE ${STM32_Drivers_Src}) +target_link_libraries(STM32_Drivers PUBLIC stm32cubemx) + + +# Add STM32CubeMX generated application sources to the project +target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${MX_Application_Src}) + +# Link directories setup +target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE ${MX_LINK_DIRS}) + +# Add libraries to the project +target_link_libraries(${CMAKE_PROJECT_NAME} ${MX_LINK_LIBS}) + +# Add the map file to the list of files to be removed with 'clean' target +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_PROJECT_NAME}.map) + +# Validate that STM32CubeMX code is compatible with C standard +if((CMAKE_C_STANDARD EQUAL 90) OR (CMAKE_C_STANDARD EQUAL 99)) + message(ERROR "Generated code requires C11 or higher") +endif() diff --git a/firmware/ui/dependencies/sframe b/firmware/ui/dependencies/sframe new file mode 160000 index 00000000..3b43c93c --- /dev/null +++ b/firmware/ui/dependencies/sframe @@ -0,0 +1 @@ +Subproject commit 3b43c93c63df10214aab2b0526684a40b0406850 diff --git a/firmware/ui/inc/app_main.hh b/firmware/ui/inc/app_main.hh index b1d81977..bd16e19d 100644 --- a/firmware/ui/inc/app_main.hh +++ b/firmware/ui/inc/app_main.hh @@ -45,8 +45,8 @@ inline void LEDR(GPIO_PinState r); inline void LEDG(GPIO_PinState g); inline void LEDB(GPIO_PinState b); inline void LEDS(GPIO_PinState r, GPIO_PinState g, GPIO_PinState b); -inline void RaiseFlag(Timer_Flags flag); -inline void LowerFlag(Timer_Flags flag); +inline void RaiseFlag(enum Timer_Flags flag); +inline void LowerFlag(enum Timer_Flags flag); inline void LowPowerMode(); inline void WakeUp(); inline void CheckFlags(); diff --git a/firmware/ui/inc/gsl/gsl-lite.hpp b/firmware/ui/inc/gsl/gsl-lite.hpp deleted file mode 100644 index 859f9ccc..00000000 --- a/firmware/ui/inc/gsl/gsl-lite.hpp +++ /dev/null @@ -1,4156 +0,0 @@ -// -// gsl-lite is based on GSL: Guidelines Support Library. -// For more information see https://github.com/gsl-lite/gsl-lite -// -// Copyright (c) 2015-2018 Martin Moene -// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef GSL_GSL_LITE_HPP_INCLUDED -#define GSL_GSL_LITE_HPP_INCLUDED - -#include // for swap() [pre-C++11], equal(), lexicographical_compare() -#include // for exception, terminate(), uncaught_exceptions() -#include // for data(), size(), reverse_iterator<>, iterator_traits<> -#include -#include // for addressof(), unique_ptr<>, shared_ptr<> -#include // for basic_ostream<> -#include // for ios_base, streamsize -#include // for logic_error -#include -#include // for move(), forward<>(), swap() -#include // for size_t, ptrdiff_t, nullptr_t - -#define gsl_lite_MAJOR 0 -#define gsl_lite_MINOR 37 -#define gsl_lite_PATCH 0 - -#define gsl_lite_VERSION gsl_STRINGIFY(gsl_lite_MAJOR) "." gsl_STRINGIFY(gsl_lite_MINOR) "." gsl_STRINGIFY(gsl_lite_PATCH) - -// gsl-lite backward compatibility: - -#if !defined( gsl_CONFIG_DEFAULTS_VERSION ) -# define gsl_CONFIG_DEFAULTS_VERSION gsl_lite_MAJOR -#endif - -#ifdef gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR -# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR -# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") -#endif - -#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) -# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ON is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ON.") -# define gsl_CONFIG_CONTRACT_CHECKING_ON -#endif -#if defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) -# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_OFF is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_OFF.") -# define gsl_CONFIG_CONTRACT_CHECKING_OFF -#endif -#if defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) -# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF.") -# define gsl_CONFIG_CONTRACT_CHECKING_ON -# define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) -# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF.") -# define gsl_CONFIG_CONTRACT_CHECKING_ON -# define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF -#endif - -// M-GSL compatibility: - -#if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS -#endif - -#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES -#endif - -#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_CHECKING_OFF -#endif - -// Configuration: Features - -#ifndef gsl_FEATURE_WITH_CONTAINER_TO_STD -# define gsl_FEATURE_WITH_CONTAINER_TO_STD 99 -#endif - -#ifndef gsl_FEATURE_MAKE_SPAN_TO_STD -# define gsl_FEATURE_MAKE_SPAN_TO_STD 99 -#endif - -#ifndef gsl_FEATURE_BYTE_SPAN_TO_STD -# define gsl_FEATURE_BYTE_SPAN_TO_STD 99 -#endif - -#ifndef gsl_FEATURE_IMPLICIT_MACRO -# define gsl_FEATURE_IMPLICIT_MACRO 0 -#endif - -#ifndef gsl_FEATURE_OWNER_MACRO -# define gsl_FEATURE_OWNER_MACRO (gsl_CONFIG_DEFAULTS_VERSION == 0) -#endif - -#ifndef gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD -# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 -#endif - -#ifndef gsl_FEATURE_GSL_LITE_NAMESPACE -# define gsl_FEATURE_GSL_LITE_NAMESPACE (gsl_CONFIG_DEFAULTS_VERSION >= 1) -#endif - -// Configuration: Other - -#if defined( gsl_CONFIG_TRANSPARENT_NOT_NULL ) && gsl_CONFIG_TRANSPARENT_NOT_NULL && defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) -# error configuration option gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF is meaningless if gsl_CONFIG_TRANSPARENT_NOT_NULL=1 -#endif - -#ifndef gsl_CONFIG_DEPRECATE_TO_LEVEL -# if gsl_CONFIG_DEFAULTS_VERSION >= 1 -# define gsl_CONFIG_DEPRECATE_TO_LEVEL 6 -# else -# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0 -# endif -#endif - -#ifndef gsl_CONFIG_SPAN_INDEX_TYPE -# define gsl_CONFIG_SPAN_INDEX_TYPE std::size_t -#endif - -#ifndef gsl_CONFIG_INDEX_TYPE -# if gsl_CONFIG_DEFAULTS_VERSION >= 1 -// p0122r3 uses std::ptrdiff_t -# define gsl_CONFIG_INDEX_TYPE std::ptrdiff_t -# else -# define gsl_CONFIG_INDEX_TYPE gsl_CONFIG_SPAN_INDEX_TYPE -# endif -#endif - -#ifndef gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR -# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR (gsl_CONFIG_DEFAULTS_VERSION >= 1) -#endif - -#ifndef gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF -# define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF 0 -#endif - -#ifndef gsl_CONFIG_TRANSPARENT_NOT_NULL -# define gsl_CONFIG_TRANSPARENT_NOT_NULL (gsl_CONFIG_DEFAULTS_VERSION >= 1) -#endif - -#ifndef gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS -# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 -#endif - -#ifndef gsl_CONFIG_ALLOWS_SPAN_COMPARISON -# define gsl_CONFIG_ALLOWS_SPAN_COMPARISON (gsl_CONFIG_DEFAULTS_VERSION == 0) -#endif - -#ifndef gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON -# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 -#endif - -#ifndef gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR -# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 -#endif - -#ifndef gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION -# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION (gsl_CONFIG_DEFAULTS_VERSION >= 1) -#endif - -#if 1 < defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) -# error only one of gsl_CONFIG_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_CONTRACT_CHECKING_ON, and gsl_CONFIG_CONTRACT_CHECKING_OFF may be defined -#endif -#if 1 < defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) -# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS, gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES, and gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER may be defined -#endif -#if 1 < defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) -# error only one of gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE may be defined -#endif - -// C++ language version detection (C++20 is speculative): -// Note: VC14.0/1900 (VS2015) lacks too much from C++14. - -#ifndef gsl_CPLUSPLUS -# if defined(_MSVC_LANG ) && !defined(__clang__) -# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) -# else -# define gsl_CPLUSPLUS __cplusplus -# endif -#endif - -#define gsl_CPP98_OR_GREATER ( gsl_CPLUSPLUS >= 199711L ) -#define gsl_CPP11_OR_GREATER ( gsl_CPLUSPLUS >= 201103L ) -#define gsl_CPP14_OR_GREATER ( gsl_CPLUSPLUS >= 201402L ) -#define gsl_CPP17_OR_GREATER ( gsl_CPLUSPLUS >= 201703L ) -#define gsl_CPP20_OR_GREATER ( gsl_CPLUSPLUS >= 202000L ) - -// C++ language version (represent 98 as 3): - -#define gsl_CPLUSPLUS_V ( gsl_CPLUSPLUS / 100 - (gsl_CPLUSPLUS > 200000 ? 2000 : 1994) ) - -// half-open range [lo..hi): -#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) - -// Compiler versions: - -// MSVC++ 6.0 _MSC_VER == 1200 gsl_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) -// MSVC++ 7.0 _MSC_VER == 1300 gsl_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) -// MSVC++ 7.1 _MSC_VER == 1310 gsl_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) -// MSVC++ 8.0 _MSC_VER == 1400 gsl_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) -// MSVC++ 9.0 _MSC_VER == 1500 gsl_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) -// MSVC++ 10.0 _MSC_VER == 1600 gsl_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) -// MSVC++ 11.0 _MSC_VER == 1700 gsl_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) -// MSVC++ 12.0 _MSC_VER == 1800 gsl_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) -// MSVC++ 14.0 _MSC_VER == 1900 gsl_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) -// MSVC++ 14.1 _MSC_VER >= 1910 gsl_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) -// MSVC++ 14.2 _MSC_VER >= 1920 gsl_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) - -#if defined(_MSC_VER ) && !defined(__clang__) -# define gsl_COMPILER_MSVC_VER (_MSC_VER ) -# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) -# define gsl_COMPILER_MSVC_VERSION_FULL (_MSC_VER - 100 * ( 5 + (_MSC_VER < 1900 ) ) ) -#else -# define gsl_COMPILER_MSVC_VER 0 -# define gsl_COMPILER_MSVC_VERSION 0 -# define gsl_COMPILER_MSVC_VERSION_FULL 0 -#endif - -#define gsl_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) - -// AppleClang 7.0.0 __apple_build_version__ == 7000172 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0) -// AppleClang 7.0.0 __apple_build_version__ == 7000176 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0) -// AppleClang 7.0.2 __apple_build_version__ == 7000181 gsl_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0) -// AppleClang 7.3.0 __apple_build_version__ == 7030029 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0) -// AppleClang 7.3.0 __apple_build_version__ == 7030031 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0) -// AppleClang 8.0.0 __apple_build_version__ == 8000038 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0) -// AppleClang 8.0.0 __apple_build_version__ == 8000042 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0) -// AppleClang 8.1.0 __apple_build_version__ == 8020038 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0) -// AppleClang 8.1.0 __apple_build_version__ == 8020041 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0) -// AppleClang 8.1.0 __apple_build_version__ == 8020042 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0) -// AppleClang 9.0.0 __apple_build_version__ == 9000037 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0?) -// AppleClang 9.0.0 __apple_build_version__ == 9000038 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0?) -// AppleClang 9.0.0 __apple_build_version__ == 9000039 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0?) -// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2?) -// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2?) -// AppleClang 10.0.0 __apple_build_version__ == 10001145 gsl_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1?) -// AppleClang 10.0.1 __apple_build_version__ == 10010046 gsl_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0?) -// AppleClang 11.0.0 __apple_build_version__ == 11000033 gsl_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3) (LLVM 8.0.0?) - -#if defined( __apple_build_version__ ) -# define gsl_COMPILER_APPLECLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) -# define gsl_COMPILER_CLANG_VERSION 0 -#elif defined( __clang__ ) -# define gsl_COMPILER_APPLECLANG_VERSION 0 -# define gsl_COMPILER_CLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) -#else -# define gsl_COMPILER_APPLECLANG_VERSION 0 -# define gsl_COMPILER_CLANG_VERSION 0 -#endif - -#if defined(__GNUC__) && !defined(__clang__) -# define gsl_COMPILER_GNUC_VERSION gsl_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) -#else -# define gsl_COMPILER_GNUC_VERSION 0 -#endif - -// Compiler non-strict aliasing: - -#if defined(__clang__) || defined(__GNUC__) -# define gsl_may_alias __attribute__((__may_alias__)) -#else -# define gsl_may_alias -#endif - -// Presence of gsl, language and library features: - -#define gsl_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= gsl_CPLUSPLUS_V ) - -#define gsl_DEPRECATE_TO_LEVEL( level ) ( level <= gsl_CONFIG_DEPRECATE_TO_LEVEL ) -#define gsl_FEATURE_TO_STD( feature ) ( gsl_IN_STD( gsl_FEATURE( feature##_TO_STD ) ) ) -#define gsl_FEATURE( feature ) ( gsl_FEATURE_##feature ) -#define gsl_CONFIG( feature ) ( gsl_CONFIG_##feature ) -#define gsl_HAVE( feature ) ( gsl_HAVE_##feature ) - -// Presence of wide character support: - -#ifdef __DJGPP__ -# define gsl_HAVE_WCHAR 0 -#else -# define gsl_HAVE_WCHAR 1 -#endif - -// Presence of language & library features: - -#if gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500) || gsl_BETWEEN(gsl_COMPILER_CLANG_VERSION, 1, 360) || gsl_COMPILER_APPLECLANG_VERSION -# ifdef __EXCEPTIONS -# define gsl_HAVE_EXCEPTIONS 1 -# else -# define gsl_HAVE_EXCEPTIONS 0 -# endif // __EXCEPTIONS -#elif gsl_COMPILER_GNUC_VERSION >= 500 || gsl_COMPILER_CLANG_VERSION >= 500 -# ifdef __cpp_exceptions -# define gsl_HAVE_EXCEPTIONS 1 -# else -# define gsl_HAVE_EXCEPTIONS 0 -# endif // __cpp_exceptions -#elif gsl_COMPILER_MSVC_VERSION -# ifdef _CPPUNWIND -# define gsl_HAVE_EXCEPTIONS 1 -# else -# define gsl_HAVE_EXCEPTIONS 0 -# endif // _CPPUNWIND -#else -// For all other compilers, assume exceptions are always enabled. -# define gsl_HAVE_EXCEPTIONS 1 -#endif - -#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) -# error Cannot use gsl_CONFIG_CONTRACT_VIOLATION_THROWS if exceptions are disabled. -#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) - -#ifdef _HAS_CPP0X -# define gsl_HAS_CPP0X _HAS_CPP0X -#else -# define gsl_HAS_CPP0X 0 -#endif - -#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) -#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) -#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) -#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) - -#define gsl_CPP14_000 (gsl_CPP14_OR_GREATER) -#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) -#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) - -#define gsl_CPP17_000 (gsl_CPP17_OR_GREATER) -#define gsl_CPP17_140 (gsl_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) - -#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) -#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) - -// Presence of C++11 language features: - -#define gsl_HAVE_AUTO gsl_CPP11_100 -#define gsl_HAVE_NULLPTR gsl_CPP11_100 -#define gsl_HAVE_RVALUE_REFERENCE gsl_CPP11_100 -#define gsl_HAVE_FUNCTION_REF_QUALIFIER ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 481 ) ) - -#define gsl_HAVE_ENUM_CLASS gsl_CPP11_110 - -#define gsl_HAVE_ALIAS_TEMPLATE gsl_CPP11_120 -#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_120 -#define gsl_HAVE_EXPLICIT gsl_CPP11_120 -#define gsl_HAVE_INITIALIZER_LIST gsl_CPP11_120 -#define gsl_HAVE_VARIADIC_TEMPLATE gsl_CPP11_120 -#define gsl_HAVE_IS_DELETE gsl_CPP11_120 - -#define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_140 -#define gsl_HAVE_IS_DEFAULT gsl_CPP11_140 -#define gsl_HAVE_NOEXCEPT gsl_CPP11_140 -#define gsl_HAVE_NORETURN ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 480 ) ) - -#define gsl_HAVE_EXPRESSION_SFINAE gsl_CPP11_140 - -#if gsl_CPP11_OR_GREATER -// see above -#endif - -// Presence of C++14 language features: - -#define gsl_HAVE_CONSTEXPR_14 ( gsl_CPP14_000 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 600 ) ) -#define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_140 -#define gsl_HAVE_DEPRECATED ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 142 ) ) - -// Presence of C++17 language features: -// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 - -#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_000 -#define gsl_HAVE_DEDUCTION_GUIDES ( gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION_FULL, 1, 1414 ) ) -#define gsl_HAVE_NODISCARD gsl_CPP17_000 -#define gsl_HAVE_CONSTEXPR_17 gsl_CPP17_OR_GREATER - -// Presence of C++20 language features: - -#define gsl_HAVE_CONSTEXPR_20 gsl_CPP20_OR_GREATER - -// Presence of C++ library features: - -#define gsl_HAVE_ADDRESSOF gsl_CPP17_000 -#define gsl_HAVE_ARRAY gsl_CPP11_110 -#define gsl_HAVE_TYPE_TRAITS gsl_CPP11_110 -#define gsl_HAVE_TR1_TYPE_TRAITS gsl_CPP11_110 - -#define gsl_HAVE_CONTAINER_DATA_METHOD gsl_CPP11_140_CPP0X_90 -#define gsl_HAVE_STD_DATA gsl_CPP17_000 -#ifdef __cpp_lib_ssize -# define gsl_HAVE_STD_SSIZE 1 -#else -# define gsl_HAVE_STD_SSIZE ( gsl_COMPILER_GNUC_VERSION >= 1000 && __cplusplus > 201703L ) -#endif - -#define gsl_HAVE_SIZED_TYPES gsl_CPP11_140 - -#define gsl_HAVE_MAKE_SHARED gsl_CPP11_140_CPP0X_100 -#define gsl_HAVE_SHARED_PTR gsl_CPP11_140_CPP0X_100 -#define gsl_HAVE_UNIQUE_PTR gsl_CPP11_140_CPP0X_100 - -#define gsl_HAVE_MAKE_UNIQUE gsl_CPP14_120 - -#define gsl_HAVE_UNCAUGHT_EXCEPTIONS gsl_CPP17_140 - -#define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS -#define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS -#define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS -#define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS -#define gsl_HAVE_REMOVE_CVREF gsl_CPP20_OR_GREATER - -#define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS -#define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS -#define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS -#define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS - -// C++ feature usage: - -#if gsl_HAVE( ADDRESSOF ) -# define gsl_ADDRESSOF(x) std::addressof(x) -#else -# define gsl_ADDRESSOF(x) (&x) -#endif - -#if gsl_HAVE( CONSTEXPR_11 ) -# define gsl_constexpr constexpr -#else -# define gsl_constexpr /*constexpr*/ -#endif - -#if gsl_HAVE( CONSTEXPR_14 ) -# define gsl_constexpr14 constexpr -#else -# define gsl_constexpr14 /*constexpr*/ -#endif - -#if gsl_HAVE( CONSTEXPR_17 ) -# define gsl_constexpr17 constexpr -#else -# define gsl_constexpr17 /*constexpr*/ -#endif - -#if gsl_HAVE( CONSTEXPR_20 ) -# define gsl_constexpr20 constexpr -#else -# define gsl_constexpr20 /*constexpr*/ -#endif - -#if gsl_HAVE( EXPLICIT ) -# define gsl_explicit explicit -#else -# define gsl_explicit /*explicit*/ -#endif - -#if gsl_FEATURE( IMPLICIT_MACRO ) -# define implicit /*implicit*/ -#endif - -#if gsl_HAVE( IS_DELETE ) -# define gsl_is_delete = delete -#else -# define gsl_is_delete -#endif - -#if gsl_HAVE( IS_DELETE ) -# define gsl_is_delete_access public -#else -# define gsl_is_delete_access private -#endif - -#if !gsl_HAVE( NOEXCEPT ) || defined( gsl_TESTING_ ) -# define gsl_noexcept /*noexcept*/ -#else -# define gsl_noexcept noexcept -#endif - -#if gsl_HAVE( NULLPTR ) -# define gsl_nullptr nullptr -#else -# define gsl_nullptr NULL -#endif - -#if gsl_HAVE( NODISCARD ) -# define gsl_NODISCARD [[nodiscard]] -#else -# define gsl_NODISCARD -#endif - -#if gsl_HAVE( NORETURN ) -# define gsl_NORETURN [[noreturn]] -#elif defined(_MSC_VER) -# define gsl_NORETURN __declspec(noreturn) -#else -# define gsl_NORETURN -#endif - -#if gsl_HAVE( DEPRECATED ) && !defined( gsl_TESTING_ ) -# define gsl_DEPRECATED [[deprecated]] -# define gsl_DEPRECATED_MSG( msg ) [[deprecated( msg )]] -#else -# define gsl_DEPRECATED -# define gsl_DEPRECATED_MSG( msg ) -#endif - -#if gsl_HAVE( TYPE_TRAITS ) - -#define gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) \ - gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ - operator~( ENUM val ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return ENUM( ~U( val ) ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ - operator|( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return ENUM( U( lhs ) | U( rhs ) ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ - operator&( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return ENUM( U( lhs ) & U( rhs ) ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ - operator^( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return ENUM( U( lhs ) ^ U( rhs ) ); \ - } \ - gsl_api inline gsl_constexpr14 ENUM & \ - operator|=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ - { \ - return lhs = lhs | rhs; \ - } \ - gsl_api inline gsl_constexpr14 ENUM & \ - operator&=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ - { \ - return lhs = lhs & rhs; \ - } \ - gsl_api inline gsl_constexpr14 ENUM & \ - operator^=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ - { \ - return lhs = lhs ^ rhs; \ - } - -#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \ - gsl_NODISCARD gsl_api inline gsl_constexpr bool \ - operator<( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return U( lhs ) < U( rhs ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr bool \ - operator>( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return U( lhs ) > U( rhs ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr bool \ - operator<=( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return U( lhs ) <= U( rhs ); \ - } \ - gsl_NODISCARD gsl_api inline gsl_constexpr bool \ - operator>=( ENUM lhs, ENUM rhs ) gsl_noexcept \ - { \ - typedef typename ::gsl::std11::underlying_type::type U; \ - return U( lhs ) >= U( rhs ); \ - } - - // - // Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the given enum type. - //ᅟ - //ᅟ enum class Vegetables { - //ᅟ tomato = 0b001, - //ᅟ onion = 0b010, - //ᅟ eggplant = 0b100 - //ᅟ }; - //ᅟ gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables ) - // -#define gsl_DEFINE_ENUM_BITMASK_OPERATORS( ENUM ) gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) - - // - // Defines relational operators `<`, `>`, `<=`, `>=` for the given enum type. - //ᅟ - //ᅟ enum class OperatorPrecedence { - //ᅟ additive = 0, - //ᅟ multiplicative = 1, - //ᅟ power = 2 - //ᅟ }; - //ᅟ gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence ) - // -#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( ENUM ) gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) - -#endif // gsl_HAVE( TYPE_TRAITS ) - -#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) - - -// Method enabling (C++98, VC120 (VS2013) cannot use __VA_ARGS__) - -#if gsl_HAVE( EXPRESSION_SFINAE ) -# define gsl_DECLTYPE_(T, EXPR) decltype( EXPR ) -#else -# define gsl_DECLTYPE_(T, EXPR) T -#endif - -// NOTE: When using SFINAE in gsl-lite, please note that overloads of function templates must always use SFINAE with non-type default arguments -// as explained in https://en.cppreference.com/w/cpp/types/enable_if#Notes. `gsl_ENABLE_IF_()` implements graceful fallback to default -// type arguments (for compilers that don't support non-type default arguments); please verify that this is appropriate in the given -// situation, and add additional checks if necessary. -// -// Also, please note that `gsl_ENABLE_IF_()` doesn't enforce the constraint at all if no compiler/library support is available (i.e. pre-C++11). - -#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) -# if !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) // VS 2013 seems to have trouble with SFINAE for default non-type arguments -# define gsl_ENABLE_IF_(VA) , typename std::enable_if< ( VA ), int >::type = 0 -# else -# define gsl_ENABLE_IF_(VA) , typename = typename std::enable_if< ( VA ), ::gsl::detail::enabler >::type -# endif -#else -# define gsl_ENABLE_IF_(VA) -#endif - - -// Other features: - -#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR \ - ( gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD ) - -// Note: !defined(__NVCC__) doesn't work with nvcc here: -#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR \ - ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && (__NVCC__== 0) ) - -// GSL API (e.g. for CUDA platform): - -// Guidelines for using `gsl_api`: -// -// NVCC imposes the restriction that a function annotated `__host__ __device__` cannot call host-only or device-only functions. -// This makes `gsl_api` inappropriate for generic functions that call unknown code, e.g. the template constructors of `span<>` -// or functions like `finally()` which accept an arbitrary function object. -// It is often preferable to annotate functions only with `gsl_constexpr` or `gsl_constexpr14`. The "extended constexpr" mode -// of NVCC (currently an experimental feature) will implicitly consider constexpr functions `__host__ __device__` functions -// but tolerates calls to host-only or device-only functions. - -#ifndef gsl_api -# ifdef __CUDACC__ -# define gsl_api __host__ __device__ -# else -# define gsl_api /*gsl_api*/ -# endif -#endif - -// Additional includes: - -#if gsl_HAVE( ARRAY ) -# include -#endif - -#if !gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || !gsl_HAVE( AUTO ) -# include -#endif - -#if gsl_HAVE( INITIALIZER_LIST ) -# include -#endif - -#if gsl_HAVE( TYPE_TRAITS ) -# include // for enable_if<>, - // add_const<>, add_pointer<>, common_type<>, make_signed<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, remove_cvref<>, remove_pointer<>, underlying_type<>, - // is_assignable<>, is_constructible<>, is_const<>, is_convertible<>, is_integral<>, is_pointer<>, is_signed<>, - // integral_constant<>, declval() -#elif gsl_HAVE( TR1_TYPE_TRAITS ) -# include // for add_const<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, integral_constant<> -#endif - -// MSVC warning suppression macros: - -#if gsl_COMPILER_MSVC_VERSION >= 140 && !defined(__NVCC__) -# define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] -# define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) -# define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) -# define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) -#else -// TODO: define for Clang -# define gsl_SUPPRESS_MSGSL_WARNING(expr) -# define gsl_SUPPRESS_MSVC_WARNING(code, descr) -# define gsl_DISABLE_MSVC_WARNINGS(codes) -# define gsl_RESTORE_MSVC_WARNINGS() -#endif - -// Suppress the following MSVC GSL warnings: -// - C26432: gsl::c.21 : if you define or delete any default operation in the type '...', define or delete them all -// - C26410: gsl::r.32 : the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead -// - C26415: gsl::r.30 : smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead -// - C26418: gsl::r.36 : shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead -// - C26472: gsl::t.1 : don't use a static_cast for arithmetic conversions; -// use brace initialization, gsl::narrow_cast or gsl::narrow -// - C26439: gsl::f.6 : special function 'function' can be declared 'noexcept' -// - C26440: gsl::f.6 : function 'function' can be declared 'noexcept' -// - C26455: gsl::f.6 : default constructor may not throw. Declare it 'noexcept' -// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same -// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead -// - C26482: gsl::b.2 : only index into arrays using constant expressions -// - C26446: gdl::b.4 : prefer to use gsl::at() instead of unchecked subscript operator -// - C26490: gsl::t.1 : don't use reinterpret_cast -// - C26487: gsl::l.4 : don't return a pointer '('s result)' that may be invalid - -gsl_DISABLE_MSVC_WARNINGS( 26432 26410 26415 26418 26472 26439 26440 26455 26473 26481 26482 26446 26490 26487 ) - -namespace gsl { - -// forward declare span<>: - -template< class T > -class span; - -// C++11 emulation: - -namespace std11 { - -#if gsl_HAVE( ADD_CONST ) - -using std::add_const; - -#elif gsl_HAVE( TR1_ADD_CONST ) - -using std::tr1::add_const; - -#else - -template< class T > struct add_const { typedef const T type; }; - -#endif // gsl_HAVE( ADD_CONST ) - -#if gsl_HAVE( REMOVE_CONST ) - -using std::remove_cv; -using std::remove_const; -using std::remove_volatile; - -#elif gsl_HAVE( TR1_REMOVE_CONST ) - -using std::tr1::remove_cv; -using std::tr1::remove_const; -using std::tr1::remove_volatile; - -#else - -template< class T > struct remove_const { typedef T type; }; -template< class T > struct remove_const { typedef T type; }; - -template< class T > struct remove_volatile { typedef T type; }; -template< class T > struct remove_volatile { typedef T type; }; - -template< class T > -struct remove_cv -{ - typedef typename remove_volatile::type>::type type; -}; - -#endif // gsl_HAVE( REMOVE_CONST ) - -#if gsl_HAVE( REMOVE_REFERENCE ) - -using std::remove_reference; - -#elif gsl_HAVE( TR1_REMOVE_REFERENCE ) - -using std::tr1::remove_reference; - -#else - -template< class T > struct remove_reference { typedef T type; }; -template< class T > struct remove_reference { typedef T type; }; -# if gsl_HAVE( RVALUE_REFERENCE ) -template< class T > struct remove_reference { typedef T type; }; -# endif - -#endif // gsl_HAVE( REMOVE_REFERENCE ) - - -#if gsl_HAVE( INTEGRAL_CONSTANT ) - -using std::integral_constant; -using std::true_type; -using std::false_type; - -#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT ) - -using std::tr1::integral_constant; -using std::tr1::true_type; -using std::tr1::false_type; - -#else - -template< class T, T v > struct integral_constant { enum { value = v }; }; -typedef integral_constant< bool, true > true_type; -typedef integral_constant< bool, false > false_type; - -#endif - -#if gsl_HAVE( TYPE_TRAITS ) - -using std::underlying_type; - -#elif gsl_HAVE( TR1_TYPE_TRAITS ) - -using std::tr1::underlying_type; - -#else - -// We could try to define `underlying_type<>` for pre-C++11 here, but let's not until someone actually needs it. - -#endif - -} // namespace std11 - -// C++14 emulation: - -namespace std14 { - -#if gsl_HAVE( UNIQUE_PTR ) -# if gsl_HAVE( MAKE_UNIQUE ) - -using std::make_unique; - -# elif gsl_HAVE( VARIADIC_TEMPLATE ) - -template< class T, class... Args > -std::unique_ptr make_unique( Args &&... args ) -{ - return std::unique_ptr( new T( std::forward( args )... ) ); -} - -# endif // gsl_HAVE( MAKE_UNIQUE ), gsl_HAVE( VARIADIC_TEMPLATE ) -#endif // gsl_HAVE( UNIQUE_PTR ) - -} // namespace std14 - -namespace detail { - -#if gsl_HAVE( VARIADIC_TEMPLATE ) - -template < bool V0, class T0, class... Ts > struct conjunction_ { using type = T0; }; -template < class T0, class T1, class... Ts > struct conjunction_ : conjunction_ { }; -template < bool V0, class T0, class... Ts > struct disjunction_ { using type = T0; }; -template < class T0, class T1, class... Ts > struct disjunction_ : disjunction_ { }; - -#endif - -} // namespace detail - -// C++17 emulation: - -namespace std17 { - -template< bool v > struct bool_constant : std11::integral_constant{}; - -#if gsl_CPP11_120 - -template < class... Ts > struct conjunction; -template < > struct conjunction< > : std11::true_type { }; -template < class T0, class... Ts > struct conjunction : detail::conjunction_::type { }; -template < class... Ts > struct disjunction; -template < > struct disjunction< > : std11::false_type { }; -template < class T0, class... Ts > struct disjunction : detail::disjunction_::type { }; -template < class T > struct negation : std11::integral_constant { }; - -# if gsl_CPP14_OR_GREATER - -template < class... Ts > constexpr bool conjunction_v = conjunction::value; -template < class... Ts > constexpr bool disjunction_v = disjunction::value; -template < class T > constexpr bool negation_v = negation::value; - -# endif // gsl_CPP14_OR_GREATER - -template< class... Ts > -struct make_void { typedef void type; }; - -template< class... Ts > -using void_t = typename make_void< Ts... >::type; - -#endif // gsl_CPP11_120 - -#if gsl_HAVE( STD_DATA ) - -using std::data; -using std::size; - -#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - -template< class T, size_t N > -gsl_api inline gsl_constexpr auto size( T const(&)[N] ) gsl_noexcept -> size_t -{ - return N; -} - -template< class C > -inline gsl_constexpr auto size( C const & cont ) -> decltype( cont.size() ) -{ - return cont.size(); -} - -template< class T, size_t N > -gsl_api inline gsl_constexpr auto data( T(&arr)[N] ) gsl_noexcept -> T* -{ - return &arr[0]; -} - -template< class C > -inline gsl_constexpr auto data( C & cont ) -> decltype( cont.data() ) -{ - return cont.data(); -} - -template< class C > -inline gsl_constexpr auto data( C const & cont ) -> decltype( cont.data() ) -{ - return cont.data(); -} - -template< class E > -inline gsl_constexpr auto data( std::initializer_list il ) gsl_noexcept -> E const * -{ - return il.begin(); -} - -#endif // span_HAVE( DATA ) - -} // namespace std17 - -// C++20 emulation: - -namespace std20 { - -#if gsl_CPP11_100 - -struct identity -{ - template < class T > - gsl_constexpr T && operator ()( T && arg ) const gsl_noexcept - { - return std::forward( arg ); - } -}; - -#endif // gsl_CPP11_100 - -template< class T > -struct type_identity -{ - typedef T type; -}; -#if gsl_HAVE( ALIAS_TEMPLATE ) -template< class T > -using type_identity_t = typename type_identity::type; -#endif // gsl_HAVE( ALIAS_TEMPLATE ) - -#if gsl_HAVE( STD_SSIZE ) - -using std::ssize; - -#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - -template < class C > -gsl_constexpr auto ssize( C const & c ) - -> typename std::common_type::type>::type -{ - using R = typename std::common_type::type>::type; - return static_cast( c.size() ); -} - -template -gsl_constexpr auto ssize( T const(&)[N] ) gsl_noexcept -> std::ptrdiff_t -{ - return std::ptrdiff_t( N ); -} - -#endif // gsl_HAVE( STD_SSIZE ) - -#if gsl_HAVE( REMOVE_CVREF ) - -using std::remove_cvref; - -#else - -template< class T > struct remove_cvref { typedef typename std11::remove_cv< typename std11::remove_reference< T >::type >::type type; }; - -#endif // gsl_HAVE( REMOVE_CVREF ) - -} // namespace std20 - -namespace detail { - -/// for nsel_REQUIRES_T - -/*enum*/ class enabler{}; - -#if gsl_HAVE( TYPE_TRAITS ) - -template< class Q > -struct is_span_oracle : std::false_type{}; - -template< class T> -struct is_span_oracle< span > : std::true_type{}; - -template< class Q > -struct is_span : is_span_oracle< typename std::remove_cv::type >{}; - -template< class Q > -struct is_std_array_oracle : std::false_type{}; - -#if gsl_HAVE( ARRAY ) - -template< class T, std::size_t Extent > -struct is_std_array_oracle< std::array > : std::true_type{}; - -#endif - -template< class Q > -struct is_std_array : is_std_array_oracle< typename std::remove_cv::type >{}; - -template< class Q > -struct is_array : std::false_type{}; - -template< class T > -struct is_array : std::true_type{}; - -template< class T, std::size_t N > -struct is_array : std::true_type{}; - -# if gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) - -template< class, class = void > -struct has_size_and_data : std::false_type{}; - -template< class C > -struct has_size_and_data -< - C, std17::void_t< - decltype( std17::size(std::declval()) ), - decltype( std17::data(std::declval()) ) > -> : std::true_type{}; - -template< class, class, class = void > -struct is_compatible_element : std::false_type {}; - -template< class C, class E > -struct is_compatible_element -< - C, E, std17::void_t< - decltype( std17::data(std::declval()) ), - typename std::remove_pointer() ) )>::type(*)[] > -> : std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >{}; - -template< class C > -struct is_container : std17::bool_constant -< - ! is_span< C >::value - && ! is_array< C >::value - && ! is_std_array< C >::value - && has_size_and_data< C >::value ->{}; - -template< class C, class E > -struct is_compatible_container : std17::bool_constant -< - is_container::value - && is_compatible_element::value ->{}; - -# else // ^^^ gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) ^^^ / vvv ! gsl_CPP11_140 || gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) vvv - -template< - class C, class E - , typename = typename std::enable_if< - ! is_span< C >::value - && ! is_array< C >::value - && ! is_std_array< C >::value - && ( std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >::value) - // && has_size_and_data< C >::value - , enabler>::type - , class = decltype( std17::size(std::declval()) ) - , class = decltype( std17::data(std::declval()) ) -> -# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) -// VS2013 has insufficient support for expression SFINAE; we cannot make `is_compatible_container<>` a proper type trait here -struct is_compatible_container : std::true_type { }; -# else -struct is_compatible_container_r { is_compatible_container_r(int); }; -template< class C, class E > -std::true_type is_compatible_container_f( is_compatible_container_r ); -template< class C, class E > -std::false_type is_compatible_container_f( ... ); - -template< class C, class E > -struct is_compatible_container : decltype( is_compatible_container_f< C, E >( 0 ) ) { }; -# endif // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) - -# endif // gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) - -#endif // gsl_HAVE( TYPE_TRAITS ) - -} // namespace detail - -// -// GSL.util: utilities -// - -// Integer type for indices (e.g. in a loop). -typedef gsl_CONFIG_INDEX_TYPE index; - -// -// GSL.owner: ownership pointers -// -#if gsl_HAVE( SHARED_PTR ) - using std::unique_ptr; - using std::shared_ptr; - using std::make_shared; -# if gsl_HAVE( MAKE_UNIQUE ) || gsl_HAVE( VARIADIC_TEMPLATE ) - using std14::make_unique; -# endif -#endif - -#if gsl_HAVE( ALIAS_TEMPLATE ) - template< class T -#if gsl_HAVE( TYPE_TRAITS ) - , typename = typename std::enable_if< std::is_pointer::value >::type -#endif - > - using owner = T; -#elif gsl_CONFIG_DEFAULTS_VERSION == 0 - // TODO vNext: remove - template< class T > struct owner { typedef T type; }; -#endif - -#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE - -// TODO vNext: remove -#if gsl_FEATURE( OWNER_MACRO ) -# if gsl_HAVE( OWNER_TEMPLATE ) -# define Owner(t) ::gsl::owner -# else -# define Owner(t) ::gsl::owner::type -# endif -#endif - -// -// GSL.assert: assertions -// - -#if gsl_HAVE( TYPE_TRAITS ) -# define gsl_ELIDE_CONTRACT_( x ) static_assert(::std::is_constructible::value, "argument of contract check must be convertible to bool") -#else -# define gsl_ELIDE_CONTRACT_( x ) -#endif - -#if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) -# define gsl_ASSUME( x ) gsl_ELIDE_CONTRACT_( x ) /* there is no assume intrinsic in CUDA device code */ -#elif gsl_COMPILER_MSVC_VERSION -# define gsl_ASSUME( x ) __assume( x ) -#elif gsl_COMPILER_GNUC_VERSION -# define gsl_ASSUME( x ) (( x ) ? static_cast(0) : __builtin_unreachable()) -#elif defined(__has_builtin) -# if __has_builtin(__builtin_unreachable) -# define gsl_ASSUME( x ) (( x ) ? static_cast(0) : __builtin_unreachable()) -# endif -#else -# define gsl_ASSUME( x ) gsl_ELIDE_CONTRACT_( x ) /* unknown compiler; cannot rely on assume intrinsic */ -#endif - -#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) -# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::fail_fast_assert_handler( #x, "GSL: " str, __FILE__, __LINE__ ) ) -#elif defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) -# define gsl_CONTRACT_CHECK_( str, x ) assert( ( x ) && str ) -#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) -# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::detail::fail_fast_throw( "GSL: " str " at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) -#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] -# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::detail::fail_fast_terminate() ) -#endif - -#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) -# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) -# define gsl_Expects( x ) gsl_ASSUME( x ) -# else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] -# define gsl_Expects( x ) gsl_ELIDE_CONTRACT_( x ) -# endif -#else -# define gsl_Expects( x ) gsl_CONTRACT_CHECK_( "Precondition failure", x ) -#endif -#define Expects( x ) gsl_Expects( x ) - -#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) -# define gsl_ExpectsAudit( x ) gsl_ELIDE_CONTRACT_( x ) -#else -# define gsl_ExpectsAudit( x ) gsl_CONTRACT_CHECK_( "Precondition failure (audit)", x ) -#endif - -#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) -# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) -# define gsl_Ensures( x ) gsl_ASSUME( x ) -# else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] -# define gsl_Ensures( x ) gsl_ELIDE_CONTRACT_( x ) -# endif -#else -# define gsl_Ensures( x ) gsl_CONTRACT_CHECK_( "Postcondition failure", x ) -#endif -#define Ensures( x ) gsl_Ensures( x ) - -#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) -# define gsl_EnsuresAudit( x ) gsl_ELIDE_CONTRACT_( x ) -#else -# define gsl_EnsuresAudit( x ) gsl_CONTRACT_CHECK_( "Postcondition failure (audit)", x ) -#endif - -#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) -#define gsl_STRINGIFY_( x ) #x - -struct fail_fast : public std::logic_error -{ - explicit fail_fast( char const * message ) - : std::logic_error( message ) {} -}; - -namespace detail { - - -#if gsl_HAVE( EXCEPTIONS ) -gsl_NORETURN inline void fail_fast_throw( char const * message ) -{ - throw fail_fast( message ); -} -#endif // gsl_HAVE( EXCEPTIONS ) -gsl_NORETURN inline void fail_fast_terminate() gsl_noexcept -{ - std::terminate(); -} - -} // namespace detail - -// Should be defined by user -gsl_api void fail_fast_assert_handler( char const * const expression, char const * const message, char const * const file, int line ); - -#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) - -# if gsl_HAVE( EXCEPTIONS ) -gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") -gsl_constexpr14 inline -void fail_fast_assert( bool cond, char const * const message ) -{ - if ( !cond ) - throw fail_fast( message ); -} -# endif // gsl_HAVE( EXCEPTIONS ) - -#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) - -gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") -gsl_api gsl_constexpr14 inline -void fail_fast_assert( bool cond, char const * const expression, char const * const message, char const * const file, int line ) -{ - if ( !cond ) - ::gsl::fail_fast_assert_handler( expression, message, file, line ); -} - -#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] - -gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") -gsl_constexpr14 inline -void fail_fast_assert( bool cond ) gsl_noexcept -{ - if ( !cond ) - std::terminate(); -} - -#endif - - -// -// GSL.util: utilities -// - -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -// Add uncaught_exceptions for pre-2017 MSVC, GCC and Clang -// Return unsigned char to save stack space, uncaught_exceptions can only increase by 1 in a scope - -namespace detail { - -gsl_api inline unsigned char to_uchar( unsigned x ) gsl_noexcept -{ - return static_cast( x ); -} - -} // namespace detail - -namespace std11 { - -#if gsl_HAVE( UNCAUGHT_EXCEPTIONS ) - -inline unsigned char uncaught_exceptions() gsl_noexcept -{ - return detail::to_uchar( std::uncaught_exceptions() ); -} - -#elif gsl_COMPILER_MSVC_VERSION - -extern "C" char * __cdecl _getptd(); -inline unsigned char uncaught_exceptions() gsl_noexcept -{ - return detail::to_uchar( *reinterpret_cast(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90) ) ); -} - -#elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION - -extern "C" char * __cxa_get_globals(); -inline unsigned char uncaught_exceptions() gsl_noexcept -{ - return detail::to_uchar( *reinterpret_cast(__cxa_get_globals() + sizeof(void*) ) ); -} -#endif -} // namespace std11 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 - -template< class F > -class final_action -{ -public: - explicit final_action( F action ) gsl_noexcept - : action_( std::move( action ) ) - , invoke_( true ) - {} - - final_action( final_action && other ) gsl_noexcept - : action_( std::move( other.action_ ) ) - , invoke_( other.invoke_ ) - { - other.invoke_ = false; - } - - gsl_SUPPRESS_MSGSL_WARNING(f.6) - virtual ~final_action() gsl_noexcept - { - if ( invoke_ ) - action_(); - } - -gsl_is_delete_access: - final_action( final_action const & ) gsl_is_delete; - final_action & operator=( final_action const & ) gsl_is_delete; - final_action & operator=( final_action && ) gsl_is_delete; - -protected: - void dismiss() gsl_noexcept - { - invoke_ = false; - } - -private: - F action_; - bool invoke_; -}; - -template< class F > -inline final_action finally( F const & action ) gsl_noexcept -{ - return final_action( action ); -} - -template< class F > -inline final_action finally( F && action ) gsl_noexcept -{ - return final_action( std::forward( action ) ); -} - -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -template< class F > -class final_action_return : public final_action -{ -public: - explicit final_action_return( F && action ) gsl_noexcept - : final_action( std::move( action ) ) - , exception_count( std11::uncaught_exceptions() ) - {} - - final_action_return( final_action_return && other ) gsl_noexcept - : final_action( std::move( other ) ) - , exception_count( std11::uncaught_exceptions() ) - {} - - ~final_action_return() override - { - if ( std11::uncaught_exceptions() != exception_count ) - this->dismiss(); - } - -gsl_is_delete_access: - final_action_return( final_action_return const & ) gsl_is_delete; - final_action_return & operator=( final_action_return const & ) gsl_is_delete; - -private: - unsigned char exception_count; -}; - -template< class F > -inline final_action_return on_return( F const & action ) gsl_noexcept -{ - return final_action_return( action ); -} - -template< class F > -inline final_action_return on_return( F && action ) gsl_noexcept -{ - return final_action_return( std::forward( action ) ); -} - -template< class F > -class final_action_error : public final_action -{ -public: - explicit final_action_error( F && action ) gsl_noexcept - : final_action( std::move( action ) ) - , exception_count( std11::uncaught_exceptions() ) - {} - - final_action_error( final_action_error && other ) gsl_noexcept - : final_action( std::move( other ) ) - , exception_count( std11::uncaught_exceptions() ) - {} - - ~final_action_error() override - { - if ( std11::uncaught_exceptions() == exception_count ) - this->dismiss(); - } - -gsl_is_delete_access: - final_action_error( final_action_error const & ) gsl_is_delete; - final_action_error & operator=( final_action_error const & ) gsl_is_delete; - -private: - unsigned char exception_count; -}; - -template< class F > -inline final_action_error on_error( F const & action ) gsl_noexcept -{ - return final_action_error( action ); -} - -template< class F > -inline final_action_error on_error( F && action ) gsl_noexcept -{ - return final_action_error( std::forward( action ) ); -} - -#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -#else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 - -class final_action -{ -public: - typedef void (*Action)(); - - final_action( Action action ) - : action_( action ) - , invoke_( true ) - {} - - final_action( final_action const & other ) - : action_( other.action_ ) - , invoke_( other.invoke_ ) - { - other.invoke_ = false; - } - - virtual ~final_action() - { - if ( invoke_ ) - action_(); - } - -protected: - void dismiss() - { - invoke_ = false; - } - -private: - final_action & operator=( final_action const & ); - -private: - Action action_; - mutable bool invoke_; -}; - -template< class F > -inline final_action finally( F const & f ) -{ - return final_action(( f )); -} - -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -class final_action_return : public final_action -{ -public: - explicit final_action_return( Action action ) - : final_action( action ) - , exception_count( std11::uncaught_exceptions() ) - {} - - ~final_action_return() - { - if ( std11::uncaught_exceptions() != exception_count ) - this->dismiss(); - } - -private: - final_action_return & operator=( final_action_return const & ); - -private: - unsigned char exception_count; -}; - -template< class F > -inline final_action_return on_return( F const & action ) -{ - return final_action_return( action ); -} - -class final_action_error : public final_action -{ -public: - explicit final_action_error( Action action ) - : final_action( action ) - , exception_count( std11::uncaught_exceptions() ) - {} - - ~final_action_error() - { - if ( std11::uncaught_exceptions() == exception_count ) - this->dismiss(); - } - -private: - final_action_error & operator=( final_action_error const & ); - -private: - unsigned char exception_count; -}; - -template< class F > -inline final_action_error on_error( F const & action ) -{ - return final_action_error( action ); -} - -#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 110 - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 - -template< class T, class U > -gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept -{ - return static_cast( std::forward( u ) ); -} - -#else - -template< class T, class U > -gsl_api inline T narrow_cast( U u ) gsl_noexcept -{ - return static_cast( u ); -} - -#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 - -struct narrowing_error : public std::exception {}; - -#if gsl_HAVE( TYPE_TRAITS ) - -namespace detail { - - template< class T, class U > - struct is_same_signedness : public std::integral_constant::value == std::is_signed::value> - {}; - -# if defined( __NVCC__ ) - // We do this to circumvent NVCC warnings about pointless unsigned comparisons with 0. - template< class T > - gsl_constexpr gsl_api bool is_negative( T value, std::true_type /*isSigned*/ ) gsl_noexcept - { - return value < T(); - } - template< class T > - gsl_constexpr gsl_api bool is_negative( T /*value*/, std::false_type /*isUnsigned*/ ) gsl_noexcept - { - return false; - } - template< class T, class U > - gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::true_type /*isSameSignedness*/ ) gsl_noexcept - { - return true; - } - template< class T, class U > - gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::false_type /*isSameSignedness*/ ) gsl_noexcept - { - return detail::is_negative( t, std::is_signed() ) == detail::is_negative( u, std::is_signed() ); - } -# endif // defined( __NVCC__ ) - -} // namespace detail - -#endif - -#if gsl_HAVE( EXCEPTIONS ) || !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION -template< class T, class U > -# if !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) -gsl_api -# endif // !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) -inline T narrow( U u ) -{ - T t = static_cast( u ); - - if ( static_cast( t ) != u ) - { -# if gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) - throw narrowing_error(); -# else - std::terminate(); -# endif - } - -# if gsl_HAVE( TYPE_TRAITS ) -# if defined( __NVCC__ ) - if ( ! detail::have_same_sign( t, u, detail::is_same_signedness() ) ) -# else - gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) - if ( ! detail::is_same_signedness::value && ( t < T() ) != ( u < U() ) ) -# endif -# else - // Don't assume T() works: - gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) - if ( ( t < 0 ) != ( u < 0 ) ) -# endif - { -# if gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) - throw narrowing_error(); -# else - std::terminate(); -# endif - } - - return t; -} -#endif // gsl_HAVE( EXCEPTIONS ) || !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION - -template< class T, class U > -gsl_api inline T narrow_failfast( U u ) -{ - T t = static_cast( u ); - - gsl_Expects( static_cast( t ) == u ); - -#if gsl_HAVE( TYPE_TRAITS ) -# if defined( __NVCC__ ) - gsl_Expects( ::gsl::detail::have_same_sign( t, u, ::gsl::detail::is_same_signedness() ) ); -# else - gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) - gsl_Expects( ( ::gsl::detail::is_same_signedness::value || ( t < T() ) == ( u < U() ) ) ); -# endif -#else - // Don't assume T() works: - gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) - gsl_Expects( ( t < 0 ) == ( u < 0 ) ); -#endif - - return t; -} - - -// -// at() - Bounds-checked way of accessing static arrays, std::array, std::vector. -// - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t pos ) -{ - gsl_Expects( pos < N ); - return arr[pos]; -} - -template< class Container > -inline gsl_constexpr14 typename Container::value_type & at( Container & cont, size_t pos ) -{ - gsl_Expects( pos < cont.size() ); - return cont[pos]; -} - -template< class Container > -inline gsl_constexpr14 typename Container::value_type const & at( Container const & cont, size_t pos ) -{ - gsl_Expects( pos < cont.size() ); - return cont[pos]; -} - -#if gsl_HAVE( INITIALIZER_LIST ) - -template< class T > -inline const gsl_constexpr14 T at( std::initializer_list cont, size_t pos ) -{ - gsl_Expects( pos < cont.size() ); - return *( cont.begin() + pos ); -} -#endif - -template< class T > -gsl_api inline gsl_constexpr14 T & at( span s, size_t pos ) -{ - return s[ pos ]; -} - -// -// GSL.views: views -// - -// -// not_null<> - Wrap any indirection and enforce non-null. -// - -template< class T > -class not_null; - -namespace detail { - -// helper class to figure out the pointed-to type of a pointer -#if gsl_CPP11_OR_GREATER -template< class T, class E = void > -struct element_type_helper -{ - // For types without a member element_type (this will handle raw pointers) - typedef typename std::remove_reference< decltype( *std::declval() ) >::type type; -}; - -template< class T > -struct element_type_helper< T, std17::void_t< typename T::element_type > > -{ - // For types with a member element_type - typedef typename T::element_type type; -}; -#else -// Pre-C++11, we cannot have decltype, so we cannot handle types without a member element_type -template< class T, class E = void > -struct element_type_helper -{ - typedef typename T::element_type type; -}; - -template< class T > -struct element_type_helper< T* > -{ - typedef T type; -}; -#endif - -template< class T > -struct is_not_null_oracle : std11::false_type { }; -template< class T > -struct is_not_null_oracle< not_null > : std11::true_type { }; - -template< class T, bool IsCopyable = true > -struct not_null_data; -#if gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) -template< class T > -struct not_null_data< T, false > -{ - T ptr_; - - gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept - : ptr_( std::move( _ptr ) ) - { - } - - gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept - : ptr_( std::move( other.ptr_ ) ) - { - } - gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept - { - ptr_ = std::move( other.ptr_ ); - return *this; - } - -gsl_is_delete_access: - not_null_data( not_null_data const & other ) gsl_is_delete; - not_null_data & operator=( not_null_data const & other ) gsl_is_delete; -}; -#endif // gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) -template< class T > -struct not_null_data< T, true > -{ - T ptr_; - - gsl_constexpr14 not_null_data( T const & _ptr ) gsl_noexcept - : ptr_( _ptr ) - { - } - -#if gsl_HAVE( RVALUE_REFERENCE ) - gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept - : ptr_( std::move( _ptr ) ) - { - } - - gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept - : ptr_( std::move( other.ptr_ ) ) - { - } - gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept - { - ptr_ = std::move( other.ptr_ ); - return *this; - } -#endif // gsl_HAVE( RVALUE_REFERENCE ) - - gsl_constexpr14 not_null_data( not_null_data const & other ) - : ptr_( other.ptr_ ) - { - gsl_Expects( ptr_ != gsl_nullptr ); - } - gsl_constexpr14 not_null_data & operator=( not_null_data const & other ) - { - gsl_Expects( other.ptr_ != gsl_nullptr ); - ptr_ = other.ptr_; - return *this; - } -}; - -template< class T > -struct is_copyable -#if gsl_HAVE( TYPE_TRAITS ) -: std11::integral_constant< bool, std::is_copy_constructible::value && std::is_copy_assignable::value > -#else -: std11::true_type -#endif -{ -}; -#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) -// Type traits are buggy in VC++ 2013, so we explicitly declare `unique_ptr<>` non-copyable. -template< class T, class Deleter > -struct is_copyable< std::unique_ptr< T, Deleter > > : std11::false_type -{ -}; -#endif - -} // namespace detail - -template< class T > -class not_null -{ -private: - detail::not_null_data< T, detail::is_copyable< T >::value > data_; - - // need to access `not_null::data_` - template< class U > - friend class not_null; - -public: - typedef typename detail::element_type_helper::type element_type; - -#if gsl_HAVE( TYPE_TRAITS ) - static_assert( std::is_assignable::value, "T cannot be assigned nullptr." ); -#endif - -#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) -# if gsl_HAVE( RVALUE_REFERENCE ) - template< class U - // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. - // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. -# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value ), int >::type = 0 -# endif - > - gsl_constexpr14 explicit not_null( U other ) - : data_( T( std::move( other ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) - template< class U > - gsl_constexpr14 explicit not_null( U const& other ) - : data_( T( other ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# endif // gsl_HAVE( RVALUE_REFERENCE ) -#else // a.k.a. !gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) -# if gsl_HAVE( RVALUE_REFERENCE ) - // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. - // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. -# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value && !std::is_convertible::value ), int >::type = 0 - > - gsl_constexpr14 explicit not_null( U other ) - : data_( T( std::move( other ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } - - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_convertible::value ), int >::type = 0 - > - gsl_constexpr14 not_null( U other ) - : data_( T( std::move( other ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) - // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. - template< class U > - gsl_constexpr14 not_null( U other ) - : data_( T( std::move( other ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) -# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) - template< class U > - gsl_constexpr14 not_null( U const& other ) - : data_( T( other ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# endif // gsl_HAVE( RVALUE_REFERENCE ) -#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) - -# if gsl_HAVE( RVALUE_REFERENCE ) - // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. - // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. -# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value && !std::is_convertible::value ), int >::type = 0 - > - gsl_constexpr14 explicit not_null( not_null other ) - : data_( T( std::move( other.data_.ptr_ ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } - - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_convertible::value ), int >::type = 0 - > - gsl_constexpr14 not_null( not_null other ) - : data_( T( std::move( other.data_.ptr_ ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } -# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) - // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. - template< class U > - gsl_constexpr14 not_null( not_null other ) - : data_( T( std::move( other.data_.ptr_ ) ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } - template< class U > - gsl_constexpr14 not_null& operator=( not_null other ) - { - gsl_Expects( other.data_.ptr_ != gsl_nullptr ); - data_.ptr_ = std::move( other.data_.ptr_ ); - return *this; - } -# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) -# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) - template< class U > - gsl_constexpr14 not_null( not_null const& other ) - : data_( T( other.data_.ptr_ ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } - template< class U > - gsl_constexpr14 not_null& operator=( not_null const & other ) - { - gsl_Expects( other.data_.ptr_ != gsl_nullptr ); - data_.ptr_ = other.data_.ptr_; - return *this; - } -# endif // gsl_HAVE( RVALUE_REFERENCE ) - -#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) - gsl_constexpr14 element_type * - get() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_.get(); - } -#else -# if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) - gsl_constexpr14 T const & get() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_; - } -# else - gsl_constexpr14 T get() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_; - } -# endif -#endif - - // We want an implicit conversion operator that can be used to convert from both lvalues (by - // const reference or by copy) and rvalues (by move). So it seems like we could define - // - // template< class U > - // operator U const &() const & { ... } - // template< class U > - // operator U &&() && { ... } - // - // However, having two conversion operators with different return types renders the assignment - // operator of the result type ambiguous: - // - // not_null> p( ... ); - // std::unique_ptr q; - // q = std::move( p ); // ambiguous - // - // To avoid this ambiguity, we have both overloads of the conversion operator return `U` - // rather than `U const &` or `U &&`. This implies that converting an lvalue always induces - // a copy, which can cause unnecessary copies or even fail to compile in some situations: - // - // not_null> sp( ... ); - // std::shared_ptr const & rs = sp; // unnecessary copy - // std::unique_ptr const & ru = p; // error: cannot copy `unique_ptr` - // - // However, these situations are rather unusual, and the following, more frequent situations - // remain unimpaired: - // - // std::shared_ptr vs = sp; // no extra copy - // std::unique_ptr vu = std::move( p ); - -#if gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) - // explicit conversion operator - - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value && !std::is_convertible::value && !detail::is_not_null_oracle::value ), int >::type = 0 - > - gsl_constexpr14 explicit - operator U() const -# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) - & -# endif - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return U( data_.ptr_ ); - } -# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value && !std::is_convertible::value && !detail::is_not_null_oracle::value ), int >::type = 0 - > - gsl_constexpr14 explicit - operator U() && - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return U( std::move( data_.ptr_ ) ); - } -# endif - - // implicit conversion operator - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_constructible::value && std::is_convertible::value && !detail::is_not_null_oracle::value ), int >::type = 0 - > - gsl_constexpr14 - operator U() const -# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) - & -# endif - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_; - } -# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) - template< class U - // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. - , typename std::enable_if< ( std::is_convertible::value && !detail::is_not_null_oracle::value ), int >::type = 0 - > - gsl_constexpr14 - operator U() && - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return std::move( data_.ptr_ ); - } -# endif -#else // a.k.a. #if !( gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) ) - template< class U > - gsl_constexpr14 - operator U() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_; - } -#endif // gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) - - gsl_constexpr14 T const & - operator->() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return data_.ptr_; - } - - gsl_constexpr14 element_type & - operator*() const - { - gsl_Ensures( data_.ptr_ != gsl_nullptr ); - return *data_.ptr_; - } - -#if gsl_HAVE( RVALUE_REFERENCE ) - // Visual C++ 2013 doesn't generate default move constructors, so we declare them explicitly. - gsl_constexpr14 not_null( not_null && other ) gsl_noexcept - : data_( std::move( other.data_ ) ) - { - gsl_Expects( data_.ptr_ != gsl_nullptr ); - } - gsl_constexpr14 not_null & operator=( not_null && other ) gsl_noexcept - { - gsl_Expects( other.data_.ptr_ != gsl_nullptr ); - data_ = std::move( other.data_ ); - return *this; - } -#endif // gsl_HAVE( RVALUE_REFERENCE ) - -#if gsl_HAVE( IS_DEFAULT ) - gsl_constexpr14 not_null( not_null const & other ) = default; - gsl_constexpr14 not_null & operator=( not_null const & other ) = default; -#endif - -gsl_is_delete_access: - not_null() gsl_is_delete; - // prevent compilation when initialized with a nullptr or literal 0: -#if gsl_HAVE( NULLPTR ) - not_null( std::nullptr_t ) gsl_is_delete; - not_null & operator=( std::nullptr_t ) gsl_is_delete; -#else - not_null( int ) gsl_is_delete; - not_null & operator=( int ) gsl_is_delete; -#endif - - // unwanted operators...pointers only point to single objects! - not_null & operator++() gsl_is_delete; - not_null & operator--() gsl_is_delete; - not_null operator++( int ) gsl_is_delete; - not_null operator--( int ) gsl_is_delete; - not_null & operator+ ( size_t ) gsl_is_delete; - not_null & operator+=( size_t ) gsl_is_delete; - not_null & operator- ( size_t ) gsl_is_delete; - not_null & operator-=( size_t ) gsl_is_delete; - not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; - not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; - void operator[]( std::ptrdiff_t ) const gsl_is_delete; -}; -#if gsl_HAVE( DEDUCTION_GUIDES ) -template< class U > -not_null( U ) -> not_null; -template< class U > -not_null( not_null ) -> not_null; -#endif - -#if gsl_HAVE( NULLPTR ) -void make_not_null( std::nullptr_t ) gsl_is_delete; -#endif // gsl_HAVE( NULLPTR ) -#if gsl_HAVE( RVALUE_REFERENCE ) -template< class U > -not_null make_not_null( U u ) -{ - return not_null( std::move( u ) ); -} -template< class U > -not_null make_not_null( not_null u ) -{ - return std::move( u ); -} -#else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) -template< class U > -not_null make_not_null( U const & u ) -{ - return not_null( u ); -} -template< class U > -not_null make_not_null( not_null const & u ) -{ - return u; -} -#endif // gsl_HAVE( RVALUE_REFERENCE ) - - -// not_null with implicit constructor, allowing copy-initialization: - -template< class T > -class not_null_ic : public not_null -{ -public: - template< class U - gsl_ENABLE_IF_(( std::is_constructible::value )) - > - gsl_constexpr14 -#if gsl_HAVE( RVALUE_REFERENCE ) - not_null_ic( U && u ) - : not_null( std::forward( u ) ) -#else - not_null_ic( U const & u ) - : not_null( u ) -#endif - {} -}; - -// more not_null unwanted operators - -template< class T, class U > -std::ptrdiff_t operator-( not_null const &, not_null const & ) gsl_is_delete; - -template< class T > -not_null operator-( not_null const &, std::ptrdiff_t ) gsl_is_delete; - -template< class T > -not_null operator+( not_null const &, std::ptrdiff_t ) gsl_is_delete; - -template< class T > -not_null operator+( std::ptrdiff_t, not_null const & ) gsl_is_delete; - -// not_null comparisons - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) -operator==( not_null const & l, not_null const & r ) -{ - return l.operator->() == r.operator->(); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) -operator==( not_null const & l, U const & r ) -{ - return l.operator->() == r; -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) -operator==( T const & l, not_null const & r ) -{ - return l == r.operator->(); -} - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator<( not_null const & l, not_null const & r ) -{ - return l.operator->() < r.operator->(); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator<( not_null const & l, U const & r ) -{ - return l.operator->() < r; -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator<( T const & l, not_null const & r ) -{ - return l < r.operator->(); -} - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) -operator!=( not_null const & l, not_null const & r ) -{ - return !( l == r ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) -operator!=( not_null const & l, U const & r ) -{ - return !( l == r ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) -operator!=( T const & l, not_null const & r ) -{ - return !( l == r ); -} - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator<=( not_null const & l, not_null const & r ) -{ - return !( r < l ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator<=( not_null const & l, U const & r ) -{ - return !( r < l ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator<=( T const & l, not_null const & r ) -{ - return !( r < l ); -} - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator>( not_null const & l, not_null const & r ) -{ - return r < l; -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator>( not_null const & l, U const & r ) -{ - return r < l; -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) -operator>( T const & l, not_null const & r ) -{ - return r < l; -} - -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator>=( not_null const & l, not_null const & r ) -{ - return !( l < r ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator>=( not_null const & l, U const & r ) -{ - return !( l < r ); -} -template< class T, class U > -inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) -operator>=( T const & l, not_null const & r ) -{ - return !( l < r ); -} - -// print not_null - -template< class CharType, class Traits, class T > -std::basic_ostream< CharType, Traits > & operator<<( std::basic_ostream< CharType, Traits > & os, not_null const & p ) -{ - return os << p.operator->(); -} - - -// -// Byte-specific type. -// -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - enum class gsl_may_alias byte : unsigned char {}; -#else - struct gsl_may_alias byte { typedef unsigned char type; type v; }; -#endif - -template< class T > -gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return static_cast( v ); -#elif gsl_HAVE( CONSTEXPR_11 ) - return { static_cast( v ) }; -#else - byte b = { static_cast( v ) }; return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_(( std::is_integral::value )) > -gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return static_cast::type>( b ); -#else - return b.v; -#endif -} - -gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept -{ - return to_integer( b ); -} - -gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept -{ - return static_cast( i ); -} - -template< class IntegerType gsl_ENABLE_IF_(( std::is_integral::value )) > -gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return b = ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); -#else - b.v = ::gsl::to_uchar( b.v << shift ); return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_(( std::is_integral::value )) > -gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept -{ - return ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); -} - -template< class IntegerType gsl_ENABLE_IF_(( std::is_integral::value )) > -gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return b = ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); -#else - b.v = ::gsl::to_uchar( b.v >> shift ); return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_(( std::is_integral::value )) > -gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept -{ - return ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); -} - -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) -gsl_DEFINE_ENUM_BITMASK_OPERATORS( byte ) -gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( byte ) -#else // a.k.a. !gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) -gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept -{ - return l.v == r.v; -} - -gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept -{ - return !( l == r ); -} - -gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept -{ - return l.v < r.v; -} - -gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept -{ - return !( r < l ); -} - -gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept -{ - return ( r < l ); -} - -gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept -{ - return !( l < r ); -} - -gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept -{ - l.v |= r.v; return l; -} - -gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept -{ - return ::gsl::to_byte( l.v | r.v ); -} - -gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept -{ - l.v &= r.v; return l; -} - -gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept -{ - return ::gsl::to_byte( l.v & r.v ); -} - -gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept -{ - l.v ^= r.v; return l; -} - -gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept -{ - return ::gsl::to_byte( l.v ^ r.v ); -} - -gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept -{ - return ::gsl::to_byte( ~b.v ); -} -#endif // gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) - -// Tag to select span constructor taking a container: - -struct with_container_t { gsl_constexpr with_container_t() gsl_noexcept {} }; -const gsl_constexpr with_container_t with_container; // TODO: this can lead to ODR violations because the symbol will be defined in multiple translation units - -#endif - -// -// span<> - A 1D view of contiguous T's, replace (*,len). -// -template< class T > -class span -{ - template< class U > friend class span; - -public: - typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; - - typedef T element_type; - typedef typename std11::remove_cv< T >::type value_type; - - typedef T & reference; - typedef T * pointer; - typedef T const * const_pointer; - typedef T const & const_reference; - - typedef pointer iterator; - typedef const_pointer const_iterator; - - typedef std::reverse_iterator< iterator > reverse_iterator; - typedef std::reverse_iterator< const_iterator > const_reverse_iterator; - - typedef typename std::iterator_traits< iterator >::difference_type difference_type; - - // 26.7.3.2 Constructors, copy, and assignment [span.cons] - - gsl_api gsl_constexpr14 span() gsl_noexcept - : first_( gsl_nullptr ) - , last_ ( gsl_nullptr ) - { - } - -#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - -#if gsl_HAVE( NULLPTR ) - gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) - : first_( nullptr ) - , last_ ( nullptr ) - { - gsl_Expects( size_in == 0 ); - } -#endif - -#if gsl_HAVE( IS_DELETE ) - gsl_DEPRECATED - gsl_api gsl_constexpr span( reference data_in ) - : span( &data_in, 1 ) - {} - - gsl_api gsl_constexpr span( element_type && ) = delete; -#endif - -#endif // deprecate - - gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - gsl_Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - - gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) - : first_( first_in ) - , last_ ( last_in ) - { - gsl_Expects( first_in <= last_in ); - } - -#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - - template< class U > - gsl_api gsl_constexpr14 span( U * data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - gsl_Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - -#endif // deprecate - -#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - template< class U, size_t N > - gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept - : first_( gsl_ADDRESSOF( arr[0] ) ) - , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) - {} -#else - template< size_t N - gsl_ENABLE_IF_(( std::is_convertible::value )) - > - gsl_api gsl_constexpr span( element_type (&arr)[N] ) gsl_noexcept - : first_( gsl_ADDRESSOF( arr[0] ) ) - , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) - {} -#endif // deprecate - -#if gsl_HAVE( ARRAY ) -#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - - template< class U, size_t N > - gsl_constexpr span( std::array< U, N > & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - - template< class U, size_t N > - gsl_constexpr span( std::array< U, N > const & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - -#else - - template< size_t N - gsl_ENABLE_IF_(( std::is_convertible::value )) - > - gsl_constexpr span( std::array< value_type, N > & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - - template< size_t N - gsl_ENABLE_IF_(( std::is_convertible::value )) - > - gsl_constexpr span( std::array< value_type, N > const & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - -#endif // deprecate -#endif // gsl_HAVE( ARRAY ) - -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - template< class Container - gsl_ENABLE_IF_(( detail::is_compatible_container< Container, element_type >::value )) - > - gsl_constexpr span( Container & cont ) gsl_noexcept - : first_( std17::data( cont ) ) - , last_ ( std17::data( cont ) + std17::size( cont ) ) - {} - - template< class Container - gsl_ENABLE_IF_(( - std::is_const< element_type >::value - && detail::is_compatible_container< Container, element_type >::value - )) - > - gsl_constexpr span( Container const & cont ) gsl_noexcept - : first_( std17::data( cont ) ) - , last_ ( std17::data( cont ) + std17::size( cont ) ) - {} - -#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) - - template< class Container > - gsl_constexpr span( Container & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - - template< class Container > - gsl_constexpr span( Container const & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - -#endif - -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) - - template< class Container > - gsl_constexpr span( with_container_t, Container & cont ) gsl_noexcept - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - - template< class Container > - gsl_constexpr span( with_container_t, Container const & cont ) gsl_noexcept - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - -#endif - -#if !gsl_DEPRECATE_TO_LEVEL( 4 ) - // constructor taking shared_ptr deprecated since 0.29.0 - -# if gsl_HAVE( SHARED_PTR ) - gsl_DEPRECATED - gsl_constexpr span( shared_ptr const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) - {} -# endif - - // constructors taking unique_ptr deprecated since 0.29.0 - -# if gsl_HAVE( UNIQUE_PTR ) -# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - template< class ArrayElementType = typename std::add_pointer::type > -# else - template< class ArrayElementType > -# endif - gsl_DEPRECATED - gsl_constexpr span( unique_ptr const & ptr, index_type count ) - : first_( ptr.get() ) - , last_ ( ptr.get() + count ) - {} - - gsl_DEPRECATED - gsl_constexpr span( unique_ptr const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) - {} -# endif - -#endif // deprecate shared_ptr, unique_ptr - -#if gsl_HAVE( IS_DEFAULT ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600) - gsl_constexpr span( span && ) gsl_noexcept = default; - gsl_constexpr span( span const & ) = default; -#else - gsl_api gsl_constexpr span( span const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} -#endif - -#if gsl_HAVE( IS_DEFAULT ) - gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default; - gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default; -#else - gsl_constexpr14 span & operator=( span other ) gsl_noexcept - { - first_ = other.first_; - last_ = other.last_; - return *this; - } -#endif - - template< class U - gsl_ENABLE_IF_(( std::is_convertible::value )) - > - gsl_api gsl_constexpr span( span const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} - -#if 0 - // Converting from other span ? - template< class U > operator=(); -#endif - - // 26.7.3.3 Subviews [span.sub] - - gsl_api gsl_constexpr14 span first( index_type count ) const - { - gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); - return span( this->data(), count ); - } - - gsl_api gsl_constexpr14 span last( index_type count ) const - { - gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); - return span( this->data() + this->size() - count, count ); - } - - gsl_api gsl_constexpr14 span subspan( index_type offset ) const - { - gsl_Expects( std::size_t( offset ) <= std::size_t( this->size() ) ); - return span( this->data() + offset, this->size() - offset ); - } - - gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const - { - gsl_Expects( - std::size_t( offset ) <= std::size_t( this->size() ) && - std::size_t( count ) <= std::size_t( this->size() - offset ) ); - return span( this->data() + offset, count ); - } - - // 26.7.3.4 Observers [span.obs] - - gsl_api gsl_constexpr index_type size() const gsl_noexcept - { - return narrow_cast( last_ - first_ ); - } - - gsl_api gsl_constexpr std::ptrdiff_t ssize() const gsl_noexcept - { - return narrow_cast( last_ - first_ ); - } - - gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept - { - return size() * narrow_cast( sizeof( element_type ) ); - } - - gsl_api gsl_constexpr bool empty() const gsl_noexcept - { - return size() == 0; - } - - // 26.7.3.5 Element access [span.elem] - - gsl_api gsl_constexpr14 reference operator[]( index_type pos ) const - { - gsl_Expects( pos < size() ); - return first_[ pos ]; - } - -#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) - gsl_DEPRECATED_MSG("use subscript indexing instead") - gsl_api gsl_constexpr14 reference operator()( index_type pos ) const - { - return (*this)[ pos ]; - } - - gsl_DEPRECATED_MSG("use subscript indexing instead") - gsl_api gsl_constexpr14 reference at( index_type pos ) const - { - return (*this)[ pos ]; - } -#endif // deprecate - - gsl_api gsl_constexpr14 reference front() const - { - gsl_Expects( first_ != last_ ); - return *first_; - } - - gsl_api gsl_constexpr14 reference back() const - { - gsl_Expects( first_ != last_ ); - return *(last_ - 1); - } - - gsl_api gsl_constexpr pointer data() const gsl_noexcept - { - return first_; - } - - // 26.7.3.6 Iterator support [span.iterators] - - gsl_api gsl_constexpr iterator begin() const gsl_noexcept - { - return iterator( first_ ); - } - - gsl_api gsl_constexpr iterator end() const gsl_noexcept - { - return iterator( last_ ); - } - - gsl_api gsl_constexpr const_iterator cbegin() const gsl_noexcept - { -#if gsl_CPP11_OR_GREATER - return { begin() }; -#else - return const_iterator( begin() ); -#endif - } - - gsl_api gsl_constexpr const_iterator cend() const gsl_noexcept - { -#if gsl_CPP11_OR_GREATER - return { end() }; -#else - return const_iterator( end() ); -#endif - } - - gsl_constexpr17 reverse_iterator rbegin() const gsl_noexcept - { - return reverse_iterator( end() ); - } - - gsl_constexpr17 reverse_iterator rend() const gsl_noexcept - { - return reverse_iterator( begin() ); - } - - gsl_constexpr17 const_reverse_iterator crbegin() const gsl_noexcept - { - return const_reverse_iterator( cend() ); - } - - gsl_constexpr17 const_reverse_iterator crend() const gsl_noexcept - { - return const_reverse_iterator( cbegin() ); - } - - gsl_constexpr14 void swap( span & other ) gsl_noexcept - { - std::swap( first_, other.first_ ); - std::swap( last_ , other.last_ ); - } - -#if ! gsl_DEPRECATE_TO_LEVEL( 3 ) - // member length() deprecated since 0.29.0 - - gsl_DEPRECATED_MSG("use size() instead") - gsl_api gsl_constexpr index_type length() const gsl_noexcept - { - return size(); - } - - // member length_bytes() deprecated since 0.29.0 - - gsl_DEPRECATED_MSG("use size_bytes() instead") - gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept - { - return size_bytes(); - } -#endif - -#if ! gsl_DEPRECATE_TO_LEVEL( 2 ) - // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 - - gsl_DEPRECATED_MSG("use free function gsl::as_bytes() instead") - gsl_api span< const byte > as_bytes() const gsl_noexcept - { - return span< const byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT - } - - gsl_DEPRECATED_MSG("use free function gsl::as_writable_bytes() instead") - gsl_api span< byte > as_writeable_bytes() const gsl_noexcept - { - return span< byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT - } - -#endif - - template< class U > - gsl_api span< U > as_span() const - { - gsl_Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); - return span< U >( reinterpret_cast( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT - } - -private: - pointer first_; - pointer last_; -}; - -// class template argument deduction guides: - -#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER - -template< class T, size_t N > -span( T (&)[N] ) -> span; - -template< class T, size_t N > -span( std::array & ) -> span; - -template< class T, size_t N > -span( std::array const & ) -> span; - -template< class Container > -span( Container& ) -> span; - -template< class Container > -span( Container const & ) -> span; - -#endif // gsl_HAVE( DEDUCTION_GUIDES ) - -// 26.7.3.7 Comparison operators [span.comparison] - -#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) -# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T, class U > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr bool operator==( span const & l, span const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} - -template< class T, class U > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr bool operator< ( span const & l, span const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -# else // a.k.a. !gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr bool operator==( span const & l, span const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} - -template< class T > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr bool operator< ( span const & l, span const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T, class U > -inline gsl_constexpr bool operator!=( span const & l, span const & r ) -{ - return !( l == r ); -} - -template< class T, class U > -inline gsl_constexpr bool operator<=( span const & l, span const & r ) -{ - return !( r < l ); -} - -template< class T, class U > -inline gsl_constexpr bool operator> ( span const & l, span const & r ) -{ - return ( r < l ); -} - -template< class T, class U > -inline gsl_constexpr bool operator>=( span const & l, span const & r ) -{ - return !( l < r ); -} -#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) - -// span algorithms - -template< class T > -gsl_api inline gsl_constexpr std::size_t size( span const & spn ) -{ - return static_cast( spn.size() ); -} - -template< class T > -gsl_api inline gsl_constexpr std::ptrdiff_t ssize( span const & spn ) -{ - return spn.ssize(); -} - -namespace detail { - -template< class II, class N, class OI > -gsl_api gsl_constexpr14 inline OI copy_n( II first, N count, OI result ) -{ - if ( count > 0 ) - { - *result++ = *first; - for ( N i = 1; i < count; ++i ) - { - *result++ = *++first; - } - } - return result; -} -} - -template< class T, class U > -gsl_api gsl_constexpr14 inline void copy( span src, span dest ) -{ -#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4) - static_assert( std::is_assignable::value, "Cannot assign elements of source span to elements of destination span" ); -#endif - gsl_Expects( dest.size() >= src.size() ); - detail::copy_n( src.data(), src.size(), dest.data() ); -} - -// span creator functions (see ctors) - -template< class T > -gsl_api inline span< const byte > as_bytes( span spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} - -template< class T> -gsl_api inline span< byte > as_writable_bytes( span spn ) gsl_noexcept -{ - return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} - -#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) -template< class T> -gsl_DEPRECATED_MSG("use as_writable_bytes() (different spelling) instead") -gsl_api inline span< byte > as_writeable_bytes( span spn ) gsl_noexcept -{ - return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} -#endif // deprecate - -#if gsl_FEATURE_TO_STD( MAKE_SPAN ) - -template< class T > -gsl_api inline gsl_constexpr span -make_span( T * ptr, typename span::index_type count ) -{ - return span( ptr, count ); -} - -template< class T > -gsl_api inline gsl_constexpr span -make_span( T * first, T * last ) -{ - return span( first, last ); -} - -template< class T, size_t N > -gsl_api inline gsl_constexpr span -make_span( T (&arr)[N] ) -{ - return span( gsl_ADDRESSOF( arr[0] ), N ); -} - -#if gsl_HAVE( ARRAY ) - -template< class T, size_t N > -inline gsl_constexpr span -make_span( std::array & arr ) -{ - return span( arr ); -} - -template< class T, size_t N > -inline gsl_constexpr span -make_span( std::array const & arr ) -{ - return span( arr ); -} -#endif - -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO ) - -template< class Container, class EP = decltype( std17::data(std::declval())) > -inline gsl_constexpr auto -make_span( Container & cont ) -> span< typename std::remove_pointer::type > -{ - return span< typename std::remove_pointer::type >( cont ); -} - -template< class Container, class EP = decltype( std17::data(std::declval())) > -inline gsl_constexpr auto -make_span( Container const & cont ) -> span< const typename std::remove_pointer::type > -{ - return span< const typename std::remove_pointer::type >( cont ); -} - -#else - -template< class T > -inline span -make_span( std::vector & cont ) -{ - return span( with_container, cont ); -} - -template< class T > -inline span -make_span( std::vector const & cont ) -{ - return span( with_container, cont ); -} -#endif - -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) - -template< class Container > -inline gsl_constexpr span -make_span( with_container_t, Container & cont ) gsl_noexcept -{ - return span< typename Container::value_type >( with_container, cont ); -} - -template< class Container > -inline gsl_constexpr span -make_span( with_container_t, Container const & cont ) gsl_noexcept -{ - return span< const typename Container::value_type >( with_container, cont ); -} - -#endif // gsl_FEATURE_TO_STD( WITH_CONTAINER ) - -#if !gsl_DEPRECATE_TO_LEVEL( 4 ) -template< class Ptr > -gsl_DEPRECATED -inline span -make_span( Ptr & ptr ) -{ - return span( ptr ); -} -#endif // !gsl_DEPRECATE_TO_LEVEL( 4 ) - -template< class Ptr > -gsl_DEPRECATED -inline span -make_span( Ptr & ptr, typename span::index_type count ) -{ - return span( ptr, count ); -} - -#endif // gsl_FEATURE_TO_STD( MAKE_SPAN ) - -#if gsl_FEATURE_TO_STD( BYTE_SPAN ) - -template< class T > -gsl_api inline gsl_constexpr span -byte_span( T & t ) gsl_noexcept -{ - return span( reinterpret_cast( &t ), sizeof(T) ); -} - -template< class T > -gsl_api inline gsl_constexpr span -byte_span( T const & t ) gsl_noexcept -{ - return span( reinterpret_cast( &t ), sizeof(T) ); -} - -#endif // gsl_FEATURE_TO_STD( BYTE_SPAN ) - -// -// basic_string_span: -// - -template< class T > -class basic_string_span; - -namespace detail { - -template< class T > -struct is_basic_string_span_oracle : std11::false_type {}; - -template< class T > -struct is_basic_string_span_oracle< basic_string_span > : std11::true_type {}; - -template< class T > -struct is_basic_string_span : is_basic_string_span_oracle< typename std11::remove_cv::type > {}; - -template< class T > -gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) -{ - if ( ptr == gsl_nullptr || max <= 0 ) - return 0; - - std::size_t len = 0; - while ( len < max && ptr[len] ) // NOLINT - ++len; - - return len; -} - -} // namespace detail - -// -// basic_string_span<> - A view of contiguous characters, replace (*,len). -// -template< class T > -class basic_string_span -{ -public: - typedef T element_type; - typedef span span_type; - - typedef typename span_type::index_type index_type; - typedef typename span_type::difference_type difference_type; - - typedef typename span_type::pointer pointer ; - typedef typename span_type::reference reference ; - - typedef typename span_type::iterator iterator ; - typedef typename span_type::const_iterator const_iterator ; - typedef typename span_type::reverse_iterator reverse_iterator; - typedef typename span_type::const_reverse_iterator const_reverse_iterator; - - // construction: - -#if gsl_HAVE( IS_DEFAULT ) - gsl_constexpr basic_string_span() gsl_noexcept = default; -#else - gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} -#endif - -#if gsl_HAVE( NULLPTR ) - gsl_api gsl_constexpr basic_string_span( std::nullptr_t ) gsl_noexcept - : span_( nullptr, static_cast( 0 ) ) - {} -#endif - -#ifdef __CUDACC_RELAXED_CONSTEXPR__ - gsl_api -#endif // __CUDACC_RELAXED_CONSTEXPR__ - gsl_constexpr basic_string_span( pointer ptr ) - : span_( remove_z( ptr, (std::numeric_limits::max)() ) ) - {} - - gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) - : span_( ptr, count ) - {} - - gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) - : span_( firstElem, lastElem ) - {} - - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] ) - : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) ) - {} - -#if gsl_HAVE( ARRAY ) - - template< std::size_t N > - gsl_constexpr basic_string_span( std::array< typename std11::remove_const::type, N> & arr ) - : span_( remove_z( arr ) ) - {} - - template< std::size_t N > - gsl_constexpr basic_string_span( std::array< typename std11::remove_const::type, N> const & arr ) - : span_( remove_z( arr ) ) - {} - -#endif - -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - - // Exclude: array, [basic_string,] basic_string_span - - template< class Container - gsl_ENABLE_IF_(( - ! detail::is_std_array< Container >::value - && ! detail::is_basic_string_span< Container >::value - && std::is_convertible< typename Container::pointer, pointer >::value - && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value - )) - > - gsl_constexpr basic_string_span( Container & cont ) - : span_( ( cont ) ) - {} - - // Exclude: array, [basic_string,] basic_string_span - - template< class Container - gsl_ENABLE_IF_(( - ! detail::is_std_array< Container >::value - && ! detail::is_basic_string_span< Container >::value - && std::is_convertible< typename Container::pointer, pointer >::value - && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value - )) - > - gsl_constexpr basic_string_span( Container const & cont ) - : span_( ( cont ) ) - {} - -#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) - - template< class Container > - gsl_constexpr basic_string_span( Container & cont ) - : span_( cont ) - {} - - template< class Container > - gsl_constexpr basic_string_span( Container const & cont ) - : span_( cont ) - {} - -#else - - template< class U > - gsl_api gsl_constexpr basic_string_span( span const & rhs ) - : span_( rhs ) - {} - -#endif - -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) - - template< class Container > - gsl_constexpr basic_string_span( with_container_t, Container & cont ) - : span_( with_container, cont ) - {} -#endif - -#if gsl_HAVE( IS_DEFAULT ) -# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) - gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default; - - gsl_constexpr basic_string_span( basic_string_span && rhs ) = default; -# else - gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default; - - gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default; -# endif -#endif - - template< class U - gsl_ENABLE_IF_(( std::is_convertible::pointer, pointer>::value )) - > - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) - : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT - {} - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 - template< class U - gsl_ENABLE_IF_(( std::is_convertible::pointer, pointer>::value )) - > - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) - : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT - {} -#endif - - template< class CharTraits, class Allocator > - gsl_constexpr basic_string_span( - std::basic_string< typename std11::remove_const::type, CharTraits, Allocator > & str ) - : span_( gsl_ADDRESSOF( str[0] ), str.length() ) - {} - - template< class CharTraits, class Allocator > - gsl_constexpr basic_string_span( - std::basic_string< typename std11::remove_const::type, CharTraits, Allocator > const & str ) - : span_( gsl_ADDRESSOF( str[0] ), str.length() ) - {} - - // assignment: - -#if gsl_HAVE( IS_DEFAULT ) - gsl_constexpr14 basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default; - - gsl_constexpr14 basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default; -#endif - - // sub span: - - /*gsl_api*/ // currently disabled due to an apparent NVCC bug - gsl_constexpr14 basic_string_span first( index_type count ) const - { - return span_.first( count ); - } - - /*gsl_api*/ // currently disabled due to an apparent NVCC bug - gsl_constexpr14 basic_string_span last( index_type count ) const - { - return span_.last( count ); - } - - /*gsl_api*/ // currently disabled due to an apparent NVCC bug - gsl_constexpr14 basic_string_span subspan( index_type offset ) const - { - return span_.subspan( offset ); - } - - /*gsl_api*/ // currently disabled due to an apparent NVCC bug - gsl_constexpr14 basic_string_span subspan( index_type offset, index_type count ) const - { - return span_.subspan( offset, count ); - } - - // observers: - - gsl_api gsl_constexpr index_type length() const gsl_noexcept - { - return span_.size(); - } - - gsl_api gsl_constexpr index_type size() const gsl_noexcept - { - return span_.size(); - } - - gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept - { - return span_.size_bytes(); - } - - gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept - { - return span_.size_bytes(); - } - - gsl_api gsl_constexpr bool empty() const gsl_noexcept - { - return size() == 0; - } - - gsl_api gsl_constexpr14 reference operator[]( index_type idx ) const - { - return span_[idx]; - } - -#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) - gsl_DEPRECATED_MSG("use subscript indexing instead") - gsl_api gsl_constexpr14 reference operator()( index_type idx ) const - { - return span_[idx]; - } -#endif // deprecate - - gsl_api gsl_constexpr14 reference front() const - { - return span_.front(); - } - - gsl_api gsl_constexpr14 reference back() const - { - return span_.back(); - } - - gsl_api gsl_constexpr pointer data() const gsl_noexcept - { - return span_.data(); - } - - gsl_api gsl_constexpr iterator begin() const gsl_noexcept - { - return span_.begin(); - } - - gsl_api gsl_constexpr iterator end() const gsl_noexcept - { - return span_.end(); - } - - gsl_constexpr17 reverse_iterator rbegin() const gsl_noexcept - { - return span_.rbegin(); - } - - gsl_constexpr17 reverse_iterator rend() const gsl_noexcept - { - return span_.rend(); - } - - // const version not in p0123r2: - - gsl_api gsl_constexpr const_iterator cbegin() const gsl_noexcept - { - return span_.cbegin(); - } - - gsl_api gsl_constexpr const_iterator cend() const gsl_noexcept - { - return span_.cend(); - } - - gsl_constexpr17 const_reverse_iterator crbegin() const gsl_noexcept - { - return span_.crbegin(); - } - - gsl_constexpr17 const_reverse_iterator crend() const gsl_noexcept - { - return span_.crend(); - } - -private: - gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max ) - { - return span_type( sz, detail::string_length( sz, max ) ); - } - -#if gsl_HAVE( ARRAY ) - template< size_t N > - static gsl_constexpr14 span_type remove_z( std::array::type, N> & arr ) - { - return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); - } - - template< size_t N > - static gsl_constexpr14 span_type remove_z( std::array::type, N> const & arr ) - { - return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); - } -#endif - -private: - span_type span_; -}; - -// basic_string_span comparison functions: - -#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T, class U > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator==( basic_string_span const & l, U const & u ) gsl_noexcept -{ - const basic_string_span< typename std11::add_const::type > r( u ); - - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T, class U > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator<( basic_string_span const & l, U const & u ) gsl_noexcept -{ - const basic_string_span< typename std11::add_const::type > r( u ); - - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator==( U const & u, basic_string_span const & r ) gsl_noexcept -{ - const basic_string_span< typename std11::add_const::type > l( u ); - - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator<( U const & u, basic_string_span const & r ) gsl_noexcept -{ - const basic_string_span< typename std11::add_const::type > l( u ); - - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -#endif - -#else //gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator==( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept -{ - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T > -gsl_SUPPRESS_MSGSL_WARNING(stl.1) -inline gsl_constexpr14 bool operator<( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -#endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - -template< class T, class U > -inline gsl_constexpr14 bool operator!=( basic_string_span const & l, U const & r ) gsl_noexcept -{ - return !( l == r ); -} - -template< class T, class U > -inline gsl_constexpr14 bool operator<=( basic_string_span const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - return !( r < l ); -#else - basic_string_span< typename std11::add_const::type > rr( r ); - return !( rr < l ); -#endif -} - -template< class T, class U > -inline gsl_constexpr14 bool operator>( basic_string_span const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - return ( r < l ); -#else - basic_string_span< typename std11::add_const::type > rr( r ); - return ( rr < l ); -#endif -} - -template< class T, class U > -inline gsl_constexpr14 bool operator>=( basic_string_span const & l, U const & r ) gsl_noexcept -{ - return !( l < r ); -} - -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( l == r ); -} - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( r < l ); -} - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -inline gsl_constexpr14 bool operator>( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return ( r < l ); -} - -template< class T, class U - gsl_ENABLE_IF_(( !detail::is_basic_string_span::value )) -> -inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( l < r ); -} - -#endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - -// convert basic_string_span to byte span: - -template< class T > -gsl_api inline span< const byte > as_bytes( basic_string_span spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} - -// -// String types: -// - -typedef char * zstring; -typedef const char * czstring; - -#if gsl_HAVE( WCHAR ) -typedef wchar_t * wzstring; -typedef const wchar_t * cwzstring; -#endif - -typedef basic_string_span< char > string_span; -typedef basic_string_span< char const > cstring_span; - -#if gsl_HAVE( WCHAR ) -typedef basic_string_span< wchar_t > wstring_span; -typedef basic_string_span< wchar_t const > cwstring_span; -#endif - -// to_string() allow (explicit) conversions from string_span to string - -#if 0 - -template< class T > -inline std::basic_string< typename std::remove_const::type > to_string( basic_string_span spn ) -{ - std::string( spn.data(), spn.length() ); -} - -#else - -inline std::string to_string( string_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} - -inline std::string to_string( cstring_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} - -#if gsl_HAVE( WCHAR ) - -inline std::wstring to_string( wstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} - -inline std::wstring to_string( cwstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} - -#endif // gsl_HAVE( WCHAR ) -#endif // to_string() - -// -// Stream output for string_span types -// - -namespace detail { - -template< class Stream > -void write_padding( Stream & os, std::streamsize n ) -{ - for ( std::streamsize i = 0; i < n; ++i ) - os.rdbuf()->sputc( os.fill() ); -} - -template< class Stream, class Span > -Stream & write_to_stream( Stream & os, Span const & spn ) -{ - typename Stream::sentry sentry( os ); - - if ( !os ) - return os; - - const std::streamsize length = narrow( spn.length() ); - - // Whether, and how, to pad - const bool pad = ( length < os.width() ); - const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; - - if ( left_pad ) - write_padding( os, os.width() - length ); - - // Write span characters - os.rdbuf()->sputn( spn.begin(), length ); - - if ( pad && !left_pad ) - write_padding( os, os.width() - length ); - - // Reset output stream width - os.width(0); - - return os; -} - -} // namespace detail - -template< typename Traits > -std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -template< typename Traits > -std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -#if gsl_HAVE( WCHAR ) - -template< typename Traits > -std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -template< typename Traits > -std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -#endif // gsl_HAVE( WCHAR ) - -// -// ensure_sentinel() -// -// Provides a way to obtain a span from a contiguous sequence -// that ends with a (non-inclusive) sentinel value. -// -// Will fail-fast if sentinel cannot be found before max elements are examined. -// -namespace detail { - -template< class T, class SizeType, const T Sentinel > -gsl_api static span ensure_sentinel( T * seq, SizeType max = (std::numeric_limits::max)() ) -{ - typedef T * pointer; - - gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) - pointer cur = seq; - - while ( static_cast( cur - seq ) < max && *cur != Sentinel ) - ++cur; - - gsl_Expects( *cur == Sentinel ); - - return span( seq, narrow_cast< typename span::index_type >( cur - seq ) ); -} -} // namespace detail - -// -// ensure_z - creates a string_span for a czstring or cwzstring. -// Will fail fast if a null-terminator cannot be found before -// the limit of size_type. -// - -template< class T > -gsl_api inline span ensure_z( T * const & sz, size_t max = (std::numeric_limits::max)() ) -{ - return detail::ensure_sentinel( sz, max ); -} - -template< class T, size_t N > -gsl_api inline span ensure_z( T (&sz)[N] ) -{ - return ::gsl::ensure_z( gsl_ADDRESSOF( sz[0] ), N ); -} - -# if gsl_HAVE( TYPE_TRAITS ) - -template< class Container > -inline span< typename std::remove_pointer::type > -ensure_z( Container & cont ) -{ - return ::gsl::ensure_z( cont.data(), cont.length() ); -} -# endif - -// -// basic_zstring_span<> - A view of contiguous null-terminated characters, replace (*,len). -// - -template -class basic_zstring_span -{ -public: - typedef T element_type; - typedef span span_type; - - typedef typename span_type::index_type index_type; - typedef typename span_type::difference_type difference_type; - - typedef element_type * czstring_type; - typedef basic_string_span string_span_type; - - gsl_api gsl_constexpr14 basic_zstring_span( span_type s ) - : span_( s ) - { - // expects a zero-terminated span - gsl_Expects( s[s.size() - 1] == '\0'); - } - -#if gsl_HAVE( IS_DEFAULT ) - gsl_constexpr basic_zstring_span( basic_zstring_span const & other ) = default; - gsl_constexpr basic_zstring_span( basic_zstring_span && other ) = default; - gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span const & other ) = default; - gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span && other ) = default; -#else - gsl_api gsl_constexpr basic_zstring_span( basic_zstring_span const & other) : span_ ( other.span_ ) {} - gsl_api gsl_constexpr basic_zstring_span & operator=( basic_zstring_span const & other ) { span_ = other.span_; return *this; } -#endif - - gsl_api gsl_constexpr bool empty() const gsl_noexcept - { - return span_.size() == 0; - } - - gsl_api gsl_constexpr string_span_type as_string_span() const gsl_noexcept - { - return string_span_type( span_.data(), span_.size() > 1 ? span_.size() - 1 : 0 ); - } - - /*gsl_api*/ // currently disabled due to an apparent NVCC bug - gsl_constexpr string_span_type ensure_z() const - { - return ::gsl::ensure_z(span_.data(), span_.size()); - } - - gsl_api gsl_constexpr czstring_type assume_z() const gsl_noexcept - { - return span_.data(); - } - -private: - span_type span_; -}; - -// -// zString types: -// - -typedef basic_zstring_span< char > zstring_span; -typedef basic_zstring_span< char const > czstring_span; - -#if gsl_HAVE( WCHAR ) -typedef basic_zstring_span< wchar_t > wzstring_span; -typedef basic_zstring_span< wchar_t const > cwzstring_span; -#endif - -} // namespace gsl - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 - -namespace std { - -template<> -struct hash< ::gsl::byte > -{ -public: - gsl_constexpr std::size_t operator()( ::gsl::byte v ) const gsl_noexcept - { - return ::gsl::to_integer( v ); - } -}; - -} // namespace std - -#endif - -#if gsl_FEATURE_GSL_LITE_NAMESPACE - -// gsl_lite namespace: - -// gsl-lite currently keeps all symbols in the namespace `gsl`. The `gsl_lite` namespace contains all the symbols in the -// `gsl` namespace, plus some extensions that are not specified in the Core Guidelines. -// -// Going forward, we want to support coexistence of gsl-lite with M-GSL, so we want to encourage using the `gsl_lite` -// namespace when consuming gsl-lite. Typical use in library code would be: -// -// #include // instead of -// -// namespace foo { -// namespace gsl = ::gsl_lite; // convenience alias -// double mean(gsl::span elements) { -// gsl_Expects(!elements.empty()); // instead of Expects() -// ... -// } -// } // namespace foo -// -// In a future version, the new header will only define the `gsl_lite` namespace and no -// unprefixed `Expects()` and `Ensures()` macros to avoid collision with M-GSL. To ensure backward compatibility, the -// old header will keep defining the `gsl` namespace and the `Expects()` and `Ensures()` macros. - -namespace gsl_lite -{ - -namespace std11 = ::gsl::std11; -namespace std14 = ::gsl::std14; -namespace std17 = ::gsl::std17; -namespace std20 = ::gsl::std20; - -using namespace std11; -using namespace std14; -using namespace std17; -using namespace std20; - -#if gsl_HAVE( SHARED_PTR ) -using std::unique_ptr; -using std::shared_ptr; -using std::make_shared; -#endif - -using ::gsl::index; - -// Integer type for dimensions. -typedef gsl_CONFIG_INDEX_TYPE dim; - -// Integer type for array strides. -typedef gsl_CONFIG_INDEX_TYPE stride; - -// Integer type for pointer, iterator, or index differences. -typedef gsl_CONFIG_INDEX_TYPE diff; - -#if gsl_HAVE( ALIAS_TEMPLATE ) -using ::gsl::owner; -#endif - -using ::gsl::fail_fast; - -using ::gsl::finally; -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -using ::gsl::on_return; -using ::gsl::on_error; -#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) - -using ::gsl::narrow_cast; -using ::gsl::narrowing_error; -using ::gsl::narrow; -using ::gsl::narrow_failfast; - - -using ::gsl::at; - -using ::gsl::not_null; -using ::gsl::make_not_null; - -using ::gsl::byte; - -using ::gsl::with_container_t; -using ::gsl::with_container; - -using ::gsl::span; -using ::gsl::make_span; -using ::gsl::byte_span; -using ::gsl::copy; -using ::gsl::as_bytes; -using ::gsl::as_writable_bytes; -#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) -using ::gsl::as_writeable_bytes; -#endif - -using ::gsl::basic_string_span; -using ::gsl::string_span; -using ::gsl::cstring_span; - -using ::gsl::basic_zstring_span; -using ::gsl::zstring_span; -using ::gsl::czstring_span; - -using ::gsl::zstring; -using ::gsl::czstring; - -#if gsl_HAVE( WCHAR ) -using ::gsl::wzstring; -using ::gsl::cwzstring; - -using ::gsl::wzstring_span; -using ::gsl::cwzstring_span; -#endif // gsl_HAVE( WCHAR ) - -} // namespace gsl_lite - -#endif // gsl_FEATURE_GSL_LITE_NAMESPACE - -gsl_RESTORE_MSVC_WARNINGS() - -#endif // GSL_GSL_LITE_HPP_INCLUDED - -// end of file diff --git a/firmware/ui/inc/sframe/map.h b/firmware/ui/inc/sframe/map.h deleted file mode 100644 index b404181e..00000000 --- a/firmware/ui/inc/sframe/map.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#ifdef NO_ALLOC - -#include - -namespace sframe { - -template -class map : private vector>, N> -{ -public: - template - void emplace(Args&&... args) - { - const auto pos = std::find_if( - this->begin(), this->end(), [&](const auto& pair) { return !pair; }); - if (pos == this->end()) { - throw std::out_of_range("map out of space"); - } - - pos->emplace(args...); - } - - auto find(const K& key) - { - return std::find_if(this->begin(), this->end(), [&](const auto& pair) { - return pair && pair.value().first == key; - }); - } - - auto find(const K& key) const - { - return std::find_if(this->begin(), this->end(), [&](const auto& pair) { - return pair && pair.value().first == key; - }); - } - - bool contains(const K& key) const { return find(key) != this->end(); } - - const V& at(const K& key) const - { - const auto pos = find(key); - if (pos == this->end()) { - throw std::out_of_range("map key not found"); - } - - return pos->value().second; - } - - V& at(const K& key) - { - auto pos = find(key); - if (pos == this->end()) { - throw std::out_of_range("map key not found"); - } - - return pos->value().second; - } - - template - void erase_if_key(F&& f) - { - const auto to_erase = [&f](const auto& maybe_pair) { - return maybe_pair && f(maybe_pair.value().first); - }; - - std::replace_if(this->begin(), this->end(), to_erase, std::nullopt); - } -}; - -} // namespace sframe - -#else // ifdef NO_ALLOC - -#include - -namespace sframe { - -// NOTE: NOT RECOMMENDED FOR USE OUTSIDE THIS LIBRARY -// -// We have used public inheritance from std::map to simplify the interface -// here. This works fine for the use cases we have within this library. If you -// choose to use this map type outside this library, you MUST NOT store it as a -// std::map pointer or reference. This will cause memory leaks, because the -// destructor ~std::map is not virtual. -template -class map : public std::map -{ -private: - using parent = std::map; - -public: - bool contains(const K& key) const { return this->count(key) > 0; } - - template - void erase_if_key(F&& f) - { - for (auto iter = this->begin(); iter != this->end();) { - if (f(iter->first)) { - iter = this->erase(iter); - } else { - ++iter; - } - } - } -}; - -} // namespace sframe - -#endif // def NO_ALLOC diff --git a/firmware/ui/inc/sframe/sframe.h b/firmware/ui/inc/sframe/sframe.h deleted file mode 100644 index ba38e2ac..00000000 --- a/firmware/ui/inc/sframe/sframe.h +++ /dev/null @@ -1,205 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -// These constants define the size of certain internal data structures if -// we are configured not to depend on dynamic allocations, i.e., if the NO_ALLOC -// flag is set. If you are using an allocator, you can ignore them. -// -// Note that these constants must be the same at the time when the library is -// built as at the time when it is used. If you are using a pre-built binary, -// you must make sure that these parameters have the same values as when the -// library was built. -#ifndef SFRAME_MAX_KEYS -#define SFRAME_MAX_KEYS 200 -#endif - -#ifndef SFRAME_EPOCH_BITS -#define SFRAME_EPOCH_BITS 4 -#endif - -namespace sframe { - -struct crypto_error : std::runtime_error -{ - crypto_error(); -}; - -struct unsupported_ciphersuite_error : std::runtime_error -{ - unsupported_ciphersuite_error(); -}; - -struct authentication_error : std::runtime_error -{ - authentication_error(); -}; - -struct buffer_too_small_error : std::runtime_error -{ - using parent = std::runtime_error; - using parent::parent; -}; - -struct invalid_parameter_error : std::runtime_error -{ - using parent = std::runtime_error; - using parent::parent; -}; - -struct invalid_key_usage_error : std::runtime_error -{ - using parent = std::runtime_error; - using parent::parent; -}; - -enum class CipherSuite : uint16_t -{ - AES_128_CTR_HMAC_SHA256_80 = 1, - AES_128_CTR_HMAC_SHA256_64 = 2, - AES_128_CTR_HMAC_SHA256_32 = 3, - AES_GCM_128_SHA256 = 4, - AES_GCM_256_SHA512 = 5, -}; - -using input_bytes = gsl::span; -using output_bytes = gsl::span; - -template -using owned_bytes = vector; - -using KeyID = uint64_t; -using Counter = uint64_t; -class Header; - -enum struct KeyUsage -{ - protect, - unprotect, -}; - -struct KeyRecord -{ - static KeyRecord from_base_key(CipherSuite suite, - KeyID key_id, - KeyUsage usage, - input_bytes base_key); - - static constexpr size_t max_key_size = 48; - static constexpr size_t max_salt_size = 12; - - owned_bytes key; - owned_bytes salt; - KeyUsage usage; - Counter counter; -}; - -// Context applies the full SFrame transform. It tracks a counter for each key -// to ensure nonce uniqueness, adds the SFrame header on protect, and -// reads/strips the SFrame header on unprotect. -class Context -{ -public: - Context(CipherSuite suite); - virtual ~Context(); - - void add_key(KeyID kid, KeyUsage usage, input_bytes key); - - output_bytes protect(KeyID key_id, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata); - output_bytes unprotect(output_bytes plaintext, - input_bytes ciphertext, - input_bytes metadata); - - static constexpr size_t max_overhead = 17 + 16; - static constexpr size_t max_metadata_size = 512; - -protected: - CipherSuite suite; - map keys; - - output_bytes protect_inner(const Header& header, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata); - output_bytes unprotect_inner(const Header& header, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata); -}; - -// MLSContext augments Context with logic for deriving keys from MLS. Instead -// of adding individual keys, salts, and key IDs, the caller adds a secret for -// an epoch, and keys / salts / key IDs are derived as needed. -class MLSContext : protected Context -{ -public: - using EpochID = uint64_t; - using SenderID = uint64_t; - using ContextID = uint64_t; - - MLSContext(CipherSuite suite_in, size_t epoch_bits_in); - - void add_epoch(EpochID epoch_id, input_bytes sframe_epoch_secret); - void add_epoch(EpochID epoch_id, - input_bytes sframe_epoch_secret, - size_t sender_bits); - void purge_before(EpochID keeper); - - output_bytes protect(EpochID epoch_id, - SenderID sender_id, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata); - output_bytes protect(EpochID epoch_id, - SenderID sender_id, - ContextID context_id, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata); - - output_bytes unprotect(output_bytes plaintext, - input_bytes ciphertext, - input_bytes metadata); - -private: - struct EpochKeys - { - static constexpr size_t max_secret_size = 64; - - EpochID full_epoch; - owned_bytes sframe_epoch_secret; - size_t sender_bits; - size_t context_bits; - uint64_t max_sender_id; - uint64_t max_context_id; - - EpochKeys(EpochID full_epoch_in, - input_bytes sframe_epoch_secret_in, - size_t epoch_bits, - size_t sender_bits_in); - owned_bytes base_key(CipherSuite suite, - SenderID sender_id) const; - }; - - void purge_epoch(EpochID epoch_id); - - KeyID form_key_id(EpochID epoch_id, - SenderID sender_id, - ContextID context_id) const; - void ensure_key(KeyID key_id, KeyUsage usage); - - const size_t epoch_bits; - const size_t epoch_mask; - - static constexpr size_t max_epochs = 1 << SFRAME_EPOCH_BITS; - vector, max_epochs> epoch_cache; -}; - -} // namespace sframe diff --git a/firmware/ui/inc/sframe/vector.h b/firmware/ui/inc/sframe/vector.h deleted file mode 100644 index 649d2c37..00000000 --- a/firmware/ui/inc/sframe/vector.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include - -#ifdef NO_ALLOC - -namespace sframe { - -template -class vector -{ -private: - std::array _data; - size_t _size; - -public: - constexpr vector() - : _size(N) - { - std::fill(_data.begin(), _data.end(), T()); - } - - constexpr vector(size_t size) - { - std::fill(_data.begin(), _data.end(), T()); - resize(size); - } - - constexpr vector(std::initializer_list content) - { - resize(content.size()); - std::copy(content.begin(), content.end(), _data.begin()); - } - - constexpr vector(gsl::span content) - { - resize(content.size()); - std::copy(content.begin(), content.end(), _data.begin()); - } - - // XXX(RLB) This constructor seems redundant with the prior one, but for some - // reason the compiler won't auto-convert from vector to span. - template - constexpr vector(const vector& content) - { - resize(content.size()); - std::copy(content.begin(), content.end(), _data.begin()); - } - - uint8_t* data() { return _data.data(); } - - auto begin() const { return _data.begin(); } - auto begin() { return _data.begin(); } - - auto end() const { return _data.begin() + _size; } - auto end() { return _data.begin() + _size; } - - auto size() const { return _size; } - auto capacity() const { return N; } - void resize(size_t size) - { - if (size > N) { - throw std::out_of_range("vector out of space"); - } - - _size = size; - } - - void push(T&& item) - { - resize(_size + 1); - _data.at(_size - 1) = item; - } - - void append(gsl::span content) - { - const auto start = _size; - resize(_size + content.size()); - std::copy(content.begin(), content.end(), begin() + start); - } - - auto& operator[](size_t i) { return _data.at(i); } - const auto& operator[](size_t i) const { return _data.at(i); } - - operator gsl::span() const { return gsl::span(_data).first(_size); } - operator gsl::span() { return gsl::span(_data).first(_size); } -}; - -} // namespace sframe - -#else // ifdef NO_ALLOC - -#include - -namespace sframe { - -// NOTE: NOT RECOMMENDED FOR USE OUTSIDE THIS LIBRARY -// -// We have used public inheritance from std::vector to simplify the interface -// here. This works fine for the use cases we have within this library. If you -// choose to use this vector type outside this library, you MUST NOT store it as -// a std::vector pointer or reference. This will cause memory leaks, because -// the destructor ~std::vector is not virtual. -template -class vector : public std::vector -{ -private: - using parent = std::vector; - -public: - constexpr vector() - : parent(N) - { - } - - constexpr vector(size_t size) - : parent(size) - { - } - - constexpr vector(gsl::span content) - : parent(content.begin(), content.end()) - { - } - - template - constexpr vector(const vector& content) - : parent(content) - { - } - - void append(gsl::span content) - { - const auto start = this->size(); - this->resize(start + content.size()); - std::copy(content.begin(), content.end(), this->begin() + start); - } -}; - -} // namespace sframe - -#endif // def NO_ALLOC diff --git a/firmware/ui/src/sframe/crypto.cc b/firmware/ui/src/sframe/crypto.cc deleted file mode 100644 index 92f9ca02..00000000 --- a/firmware/ui/src/sframe/crypto.cc +++ /dev/null @@ -1,97 +0,0 @@ -#include "crypto.h" -#include "header.h" - -namespace sframe { - -size_t -cipher_digest_size(CipherSuite suite) -{ - switch (suite) { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - case CipherSuite::AES_GCM_128_SHA256: - return 32; - - case CipherSuite::AES_GCM_256_SHA512: - return 64; - - default: - throw unsupported_ciphersuite_error(); - } -} - -size_t -cipher_key_size(CipherSuite suite) -{ - switch (suite) { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - // 16-byte AES key + 32-byte HMAC key - return 48; - - case CipherSuite::AES_GCM_128_SHA256: - return 16; - - case CipherSuite::AES_GCM_256_SHA512: - return 32; - - default: - throw unsupported_ciphersuite_error(); - } -} - -size_t -cipher_enc_key_size(CipherSuite suite) -{ - switch (suite) { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - return 16; - - default: - throw unsupported_ciphersuite_error(); - } -} - -size_t -cipher_nonce_size(CipherSuite suite) -{ - switch (suite) { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - case CipherSuite::AES_GCM_128_SHA256: - case CipherSuite::AES_GCM_256_SHA512: - return 12; - - default: - throw unsupported_ciphersuite_error(); - } -} - -size_t -cipher_overhead(CipherSuite suite) -{ - switch (suite) { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - return 10; // 80-bit tag - - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - return 8; // 64-bit tag - - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - return 4; // 32-bit tag - - case CipherSuite::AES_GCM_128_SHA256: - case CipherSuite::AES_GCM_256_SHA512: - return 16; // Full 128-bit AES-GCM tag - - default: - throw unsupported_ciphersuite_error(); - } -} - -} // namespace sframe diff --git a/firmware/ui/src/sframe/crypto.h b/firmware/ui/src/sframe/crypto.h deleted file mode 100644 index b39b66dd..00000000 --- a/firmware/ui/src/sframe/crypto.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -namespace sframe { - -size_t -cipher_digest_size(CipherSuite suite); -size_t -cipher_key_size(CipherSuite suite); -size_t -cipher_enc_key_size(CipherSuite suite); -size_t -cipher_nonce_size(CipherSuite suite); -size_t -cipher_overhead(CipherSuite suite); - -/// -/// HKDF -/// - -static constexpr size_t max_hkdf_extract_size = 64; -static constexpr size_t max_hkdf_expand_size = 64; - -owned_bytes -hkdf_extract(CipherSuite suite, input_bytes salt, input_bytes ikm); - -owned_bytes -hkdf_expand(CipherSuite suite, input_bytes prk, input_bytes info, size_t size); - -/// -/// AEAD Algorithms -/// - -output_bytes -seal(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes ct, - input_bytes aad, - input_bytes pt); - -output_bytes -open(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes pt, - input_bytes aad, - input_bytes ct); - -} // namespace sframe diff --git a/firmware/ui/src/sframe/crypto_stm32.cc b/firmware/ui/src/sframe/crypto_stm32.cc deleted file mode 100644 index 0570d443..00000000 --- a/firmware/ui/src/sframe/crypto_stm32.cc +++ /dev/null @@ -1,273 +0,0 @@ -#ifdef CRYPTO - -#include "crypto.h" -#include "header.h" -#include -#include -#include - -namespace sframe -{ - -#define VERIFY_CMOX_CALL(func, success_code) \ - do \ - { \ - auto retval = func; \ - if (retval != success_code) \ - { \ - cmox_error = retval; \ - throw crypto_error(); \ - } \ - } while (0) - -/// -/// Convert between native identifiers / errors and cmox ones -/// - -std::optional cmox_error; - -crypto_error::crypto_error() : - std::runtime_error(cmox_error.has_value() - ? "CMOX crypto error (error=" + std::to_string(cmox_error.value()) + ")" - : "unknown CMOX crypto error") -{ -} - -cmox_mac_algo_t cmox_hmac_algo(CipherSuite suite) -{ - switch (suite) - { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - case CipherSuite::AES_GCM_128_SHA256: - return CMOX_HMAC_SHA256_ALGO; - case CipherSuite::AES_GCM_256_SHA512: - return CMOX_HMAC_SHA512_ALGO; - default: - throw unsupported_ciphersuite_error(); - } -} - -cmox_hmac_impl_t cmox_hmac_impl(CipherSuite suite) -{ - switch (suite) - { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - case CipherSuite::AES_GCM_128_SHA256: - return CMOX_HMAC_SHA256; - case CipherSuite::AES_GCM_256_SHA512: - return CMOX_HMAC_SHA512; - default: - throw unsupported_ciphersuite_error(); - } -} - -std::size_t cmox_hmac_size(CipherSuite suite) -{ - switch (suite) - { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - case CipherSuite::AES_GCM_128_SHA256: - return CMOX_SHA256_SIZE; - case CipherSuite::AES_GCM_256_SHA512: - return CMOX_SHA512_SIZE; - default: - throw unsupported_ciphersuite_error(); - } -} - -/// -/// HKDF -/// - -owned_bytes -hkdf_extract(CipherSuite suite, input_bytes salt, input_bytes ikm) -{ - std::size_t computed_size = 0; - const auto hmac_size = cmox_hmac_size(suite); - auto out = owned_bytes(hmac_size); - VERIFY_CMOX_CALL(cmox_mac_compute(cmox_hmac_algo(suite), ikm.data(), ikm.size(), salt.data(), - salt.size(), nullptr, 0, out.data(), out.size(), - &computed_size), - CMOX_MAC_SUCCESS); - - return out; -} - -owned_bytes -hkdf_expand(CipherSuite suite, input_bytes prk, input_bytes info, size_t size) -{ - cmox_hmac_handle_t Hmac_Ctx; - cmox_mac_handle_t* mac_ctx; - - // Compute N = ceil(L/HashLen) - const auto digest_size = cmox_hmac_size(suite); - auto N = static_cast(size / digest_size); - if ((N * digest_size) < size) - { - N++; - } - - mac_ctx = cmox_hmac_construct(&Hmac_Ctx, cmox_hmac_impl(suite)); - if (mac_ctx == nullptr) - { - throw crypto_error(); - } - - owned_bytes computed_hash(size); - owned_bytes out(size); - - uint32_t index = 0; - for (uint8_t i = 1; i <= N; i++) - { - VERIFY_CMOX_CALL(cmox_mac_init(mac_ctx), CMOX_MAC_SUCCESS); - - /* For the last iteration, tag length may be reduced to fit requested length L */ - if (i == N) - { - VERIFY_CMOX_CALL(cmox_mac_setTagLen(mac_ctx, size - index), CMOX_MAC_SUCCESS); - } - - VERIFY_CMOX_CALL(cmox_mac_setKey(mac_ctx, prk.data(), prk.size()), CMOX_MAC_SUCCESS); - - if (i > 1) - { - VERIFY_CMOX_CALL(cmox_mac_append(mac_ctx, computed_hash.data(), digest_size), - CMOX_MAC_SUCCESS); - } - - VERIFY_CMOX_CALL(cmox_mac_append(mac_ctx, info.data(), info.size()), CMOX_MAC_SUCCESS); - VERIFY_CMOX_CALL(cmox_mac_append(mac_ctx, &i, 1), CMOX_MAC_SUCCESS); - VERIFY_CMOX_CALL(cmox_mac_generateTag(mac_ctx, computed_hash.data(), nullptr), - CMOX_MAC_SUCCESS); - - if (i == N) - { - memcpy(&out[index], computed_hash.data(), size - index); - index = size; - } - else - { - memcpy(&out[index], computed_hash.data(), digest_size); - index += digest_size; - } - } - - VERIFY_CMOX_CALL(cmox_mac_cleanup(mac_ctx), CMOX_MAC_SUCCESS); - - return out; -} - -static output_bytes seal_aead(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes ct, - input_bytes aad, - input_bytes pt) -{ - auto tag_size = cipher_overhead(suite); - if (ct.size() < pt.size() + tag_size) - { - throw buffer_too_small_error("Ciphertext buffer too small"); - } - - std::size_t computed_size = 0; - - VERIFY_CMOX_CALL(cmox_aead_encrypt(CMOX_AESFAST_GCMFAST_ENC_ALGO, pt.data(), pt.size(), - tag_size, key.data(), key.size(), nonce.data(), nonce.size(), - aad.data(), aad.size(), ct.data(), &computed_size), - CMOX_CIPHER_SUCCESS); - - return ct.subspan(0, computed_size); -} - -output_bytes seal(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes ct, - input_bytes aad, - input_bytes pt) -{ - switch (suite) - { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - { - throw unsupported_ciphersuite_error(); - // return seal_ctr(suite, key, nonce, ct, aad, pt); - } - - case CipherSuite::AES_GCM_128_SHA256: - case CipherSuite::AES_GCM_256_SHA512: - { - return seal_aead(suite, key, nonce, ct, aad, pt); - } - - default: - throw unsupported_ciphersuite_error(); - } - - throw unsupported_ciphersuite_error(); -} - -static output_bytes open_aead(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes pt, - input_bytes aad, - input_bytes ct) -{ - auto tag_size = cipher_overhead(suite); - if (ct.size() < tag_size) - { - throw buffer_too_small_error("Ciphertext buffer too small"); - } - - std::size_t computed_size = 0; - - VERIFY_CMOX_CALL(cmox_aead_decrypt(CMOX_AESFAST_GCMFAST_DEC_ALGO, ct.data(), ct.size(), - tag_size, key.data(), key.size(), nonce.data(), nonce.size(), - aad.data(), aad.size(), pt.data(), &computed_size), - CMOX_CIPHER_AUTH_SUCCESS); - - return pt.subspan(0, computed_size); -} - -output_bytes open(CipherSuite suite, - input_bytes key, - input_bytes nonce, - output_bytes pt, - input_bytes aad, - input_bytes ct) -{ - switch (suite) - { - case CipherSuite::AES_128_CTR_HMAC_SHA256_80: - case CipherSuite::AES_128_CTR_HMAC_SHA256_64: - case CipherSuite::AES_128_CTR_HMAC_SHA256_32: - { - throw unsupported_ciphersuite_error(); - // return open_ctr(suite, key, nonce, pt, aad, ct); - } - - case CipherSuite::AES_GCM_128_SHA256: - case CipherSuite::AES_GCM_256_SHA512: - { - return open_aead(suite, key, nonce, pt, aad, ct); - } - default: - throw unsupported_ciphersuite_error(); - } - - throw unsupported_ciphersuite_error(); -} - -} // namespace sframe - -#endif diff --git a/firmware/ui/src/sframe/header.cc b/firmware/ui/src/sframe/header.cc deleted file mode 100644 index ab4c46cc..00000000 --- a/firmware/ui/src/sframe/header.cc +++ /dev/null @@ -1,203 +0,0 @@ -#include "header.h" - -namespace sframe { - -static size_t -uint_size(uint64_t val) -{ - if (val < 0x08) { - // Fits in the config byte - return 0; - } - - for (unsigned int i = 0; i < 8; i += 1) { - if ((val >> (8 * i)) == 0) { - return i; - } - } - - return 8; -} - -void -encode_uint(uint64_t val, output_bytes buffer) -{ - size_t size = buffer.size(); - for (size_t i = 0; i < size && i < 8; i++) { - buffer[size - i - 1] = uint8_t(val >> (8 * i)); - } -} - -static uint64_t -decode_uint(input_bytes data) -{ - if (!data.empty() && data[0] == 0) { - throw invalid_parameter_error("Integer is not minimally encoded"); - } - - uint64_t val = 0; - for (size_t i = 0; i < data.size(); i++) { - val = (val << 8) + static_cast(data[i]); - } - return val; -} - -struct ValueOrLength -{ - bool is_length = false; - uint8_t value_or_length = 0; - - static ValueOrLength for_u64(uint64_t value) - { - if (value >= 0x08) { - return { true, static_cast(uint_size(value) - 1) }; - } else { - return { false, static_cast(value) }; - } - } - - static ValueOrLength decode(uint8_t encoded) - { - const auto is_length = (encoded & 0x08) != 0; - const auto value_or_length = (encoded & 0x07); - return { is_length, static_cast(value_or_length) }; - } - - uint8_t encode() const - { - return (((is_length) ? 1 : 0) << 3) | (value_or_length & 0x07); - } - - size_t value_size() const - { - if (!is_length) { - return 0; - } - - return value_or_length + 1; - } - - std::tuple read(input_bytes data) const - { - if (!is_length) { - // Nothing to read; value is already in config byte - return { value_or_length, data }; - } - - const auto size = value_size(); - const auto value = decode_uint(data.subspan(0, size)); - const auto remaining = data.subspan(size); - return { value, remaining }; - } - -private: - ValueOrLength(bool is_length_in, uint8_t value_or_length_in) - : is_length(is_length_in) - , value_or_length(value_or_length_in) - { - } -}; - -struct ConfigByte -{ - ValueOrLength kid; - ValueOrLength ctr; - - ConfigByte(uint64_t kid_in, uint64_t ctr_in) - : kid(ValueOrLength::for_u64(kid_in)) - , ctr(ValueOrLength::for_u64(ctr_in)) - { - } - - explicit ConfigByte(uint8_t encoded) - : kid(ValueOrLength::decode(encoded >> 4)) - , ctr(ValueOrLength::decode(encoded & 0x0f)) - { - } - - size_t encoded_size() const - { - return 1 + kid.value_size() + ctr.value_size(); - } - - uint8_t encode() const { return (kid.encode() << 4) | ctr.encode(); } -}; - -Header::Header(KeyID key_id_in, Counter counter_in) - : key_id(key_id_in) - , counter(counter_in) -{ - const auto cfg = ConfigByte{ key_id, counter }; - - _encoded[0] = cfg.encode(); - _encoded.resize(cfg.encoded_size()); - - const auto encoded = output_bytes(_encoded); - const auto after_cfg = encoded.subspan(1); - encode_uint(key_id, after_cfg.subspan(0, cfg.kid.value_size())); - - const auto after_kid = after_cfg.subspan(cfg.kid.value_size()); - encode_uint(counter, after_kid.subspan(0, cfg.ctr.value_size())); -} - -Header -Header::parse(input_bytes buffer) -{ - if (buffer.size() < Header::min_size) { - throw buffer_too_small_error("Ciphertext too small to decode header"); - } - - const auto cfg = ConfigByte{ buffer[0] }; - const auto after_cfg = buffer.subspan(1); - const auto [key_id, after_kid] = cfg.kid.read(after_cfg); - const auto [counter, _] = cfg.ctr.read(after_kid); - const auto encoded = buffer.subspan(0, cfg.encoded_size()); - - return Header(key_id, counter, encoded); -} - -Header::Header(KeyID key_id_in, Counter counter_in, input_bytes encoded_in) - : key_id(key_id_in) - , counter(counter_in) - , _encoded(encoded_in) -{ -} - -#if 0 -std::tuple -decode(input_bytes buffer) -{ - if (buffer.size() < Header::min_size) { - throw buffer_too_small_error("Ciphertext too small to decode header"); - } - - const auto cfg = ConfigByte{ buffer[0] }; - const auto after_cfg = buffer.subspan(1); - const auto [kid, after_kid] = cfg.kid.read(after_cfg); - const auto [ctr, after_ctr] = cfg.ctr.read(after_kid); - const auto header = Header{ KeyID(kid), Counter(ctr) }; - - return { header, after_ctr }; -} - -size_t -Header::encode(output_bytes buffer) const -{ - if (buffer.size() < size()) { - throw buffer_too_small_error("Buffer too small to encode header"); - } - - const auto cfg = ConfigByte{ key_id, counter }; - buffer[0] = cfg.encode(); - - const auto after_cfg = buffer.subspan(1); - encode_uint(key_id, after_cfg.subspan(0, cfg.kid.size())); - - const auto after_kid = after_cfg.subspan(cfg.kid.size()); - encode_uint(counter, after_kid.subspan(0, cfg.ctr.size())); - - return size(); -} -#endif - -} // namespace sframe diff --git a/firmware/ui/src/sframe/header.h b/firmware/ui/src/sframe/header.h deleted file mode 100644 index f431d7da..00000000 --- a/firmware/ui/src/sframe/header.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -namespace sframe { - -void -encode_uint(uint64_t val, output_bytes buffer); - -class Header -{ -public: - const KeyID key_id; - const Counter counter; - - Header(KeyID key_id_in, Counter counter_in); - static Header parse(input_bytes buffer); - - input_bytes encoded() const { return _encoded; } - size_t size() const { return _encoded.size(); } - - // Configuration byte plus 8-byte KID and CTR - static constexpr size_t max_size = 1 + 8 + 8; - -private: - // Just the configuration byte - static constexpr size_t min_size = 1; - - owned_bytes _encoded; - - Header(KeyID key_id_in, Counter counter_in, input_bytes encoded_in); -}; - -} // namespace sframe diff --git a/firmware/ui/src/sframe/sframe.cc b/firmware/ui/src/sframe/sframe.cc deleted file mode 100644 index 0e430c35..00000000 --- a/firmware/ui/src/sframe/sframe.cc +++ /dev/null @@ -1,358 +0,0 @@ -#include "crypto.h" -#include "header.h" -#include - -namespace sframe -{ - -/// -/// Errors -/// - -unsupported_ciphersuite_error::unsupported_ciphersuite_error() : - std::runtime_error("Unsupported ciphersuite") -{ -} - -authentication_error::authentication_error() : - std::runtime_error("AEAD authentication failure") -{ -} - -/// -/// KeyRecord -/// - -static auto from_ascii(const char* str, size_t len) -{ - const auto ptr = reinterpret_cast(str); - return input_bytes(ptr, len); -} - -static const auto base_label = from_ascii("SFrame 1.0 Secret ", 18); -static const auto key_label = from_ascii("key ", 4); -static const auto salt_label = from_ascii("salt ", 5); - -static owned_bytes<32> sframe_key_label(CipherSuite suite, KeyID key_id) -{ - auto label = owned_bytes<32>(base_label); - label.append(key_label); - label.resize(32); - - auto label_data = output_bytes(label); - encode_uint(key_id, label_data.subspan(22).first(8)); - encode_uint(static_cast(suite), label_data.subspan(30)); - - return label; -} - -static owned_bytes<33> sframe_salt_label(CipherSuite suite, KeyID key_id) -{ - auto label = owned_bytes<33>(base_label); - label.append(salt_label); - label.resize(33); - - auto label_data = output_bytes(label); - encode_uint(key_id, label_data.last(10).first(8)); - encode_uint(static_cast(suite), label_data.last(2)); - - return label; -} - -KeyRecord -KeyRecord::from_base_key(CipherSuite suite, KeyID key_id, KeyUsage usage, input_bytes base_key) -{ - auto key_size = cipher_key_size(suite); - auto nonce_size = cipher_nonce_size(suite); - - const auto empty_byte_string = owned_bytes<1>(0); - const auto key_label = sframe_key_label(suite, key_id); - const auto salt_label = sframe_salt_label(suite, key_id); - - auto secret = hkdf_extract(suite, empty_byte_string, base_key); - auto key = hkdf_expand(suite, secret, key_label, key_size); - auto salt = hkdf_expand(suite, secret, salt_label, nonce_size); - - return KeyRecord{key, salt, usage, 0}; -} - -/// -/// Context -/// - -Context::Context(CipherSuite suite_in) : - suite(suite_in) -{ -} - -Context::~Context() = default; - -void Context::add_key(KeyID key_id, KeyUsage usage, input_bytes base_key) -{ - keys.emplace(key_id, KeyRecord::from_base_key(suite, key_id, usage, base_key)); -} - -static owned_bytes form_nonce(Counter ctr, input_bytes salt) -{ - auto nonce = owned_bytes(salt); - for (size_t i = 0; i < sizeof(ctr); i++) - { - nonce[nonce.size() - i - 1] ^= uint8_t(ctr >> (8 * i)); - } - - return nonce; -} - -static constexpr auto max_aad_size = Header::max_size + Context::max_metadata_size; - -static owned_bytes form_aad(const Header& header, input_bytes metadata) -{ - if (metadata.size() > Context::max_metadata_size) - { - throw buffer_too_small_error("Metadata too large"); - } - - auto aad = owned_bytes(0); - aad.append(header.encoded()); - aad.append(metadata); - return aad; -} - -output_bytes -Context::protect(KeyID key_id, output_bytes ciphertext, input_bytes plaintext, input_bytes metadata) -{ - auto& key_record = keys.at(key_id); - const auto counter = key_record.counter; - key_record.counter += 1; - - const auto header = Header{key_id, counter}; - const auto header_data = header.encoded(); - if (ciphertext.size() < header_data.size()) - { - throw buffer_too_small_error("Ciphertext too small for SFrame header"); - } - - std::copy(header_data.begin(), header_data.end(), ciphertext.begin()); - auto inner_ciphertext = ciphertext.subspan(header_data.size()); - auto final_ciphertext = Context::protect_inner(header, inner_ciphertext, plaintext, metadata); - return ciphertext.first(header_data.size() + final_ciphertext.size()); -} - -output_bytes -Context::unprotect(output_bytes plaintext, input_bytes ciphertext, input_bytes metadata) -{ - const auto header = Header::parse(ciphertext); - const auto inner_ciphertext = ciphertext.subspan(header.size()); - return Context::unprotect_inner(header, plaintext, inner_ciphertext, metadata); -} - -output_bytes Context::protect_inner(const Header& header, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata) -{ - if (ciphertext.size() < plaintext.size() + cipher_overhead(suite)) - { - throw buffer_too_small_error("Ciphertext too small for cipher overhead"); - } - - const auto& key_and_salt = keys.at(header.key_id); - - const auto aad = form_aad(header, metadata); - const auto nonce = form_nonce(header.counter, key_and_salt.salt); - return seal(suite, key_and_salt.key, nonce, ciphertext, aad, plaintext); -} - -output_bytes Context::unprotect_inner(const Header& header, - output_bytes plaintext, - input_bytes ciphertext, - input_bytes metadata) -{ - if (ciphertext.size() < cipher_overhead(suite)) - { - throw buffer_too_small_error("Ciphertext too small for cipher overhead"); - } - - if (plaintext.size() < ciphertext.size() - cipher_overhead(suite)) - { - throw buffer_too_small_error("Plaintext too small for decrypted value"); - } - - const auto& key_and_salt = keys.at(header.key_id); - - const auto aad = form_aad(header, metadata); - const auto nonce = form_nonce(header.counter, key_and_salt.salt); - return open(suite, key_and_salt.key, nonce, plaintext, aad, ciphertext); -} - -/// -/// MLSContext -/// - -MLSContext::MLSContext(CipherSuite suite_in, size_t epoch_bits_in) : - Context(suite_in), - epoch_bits(epoch_bits_in), - epoch_mask((size_t(1) << epoch_bits_in) - 1) -{ - epoch_cache.resize(1 << epoch_bits_in); -} - -void MLSContext::add_epoch(EpochID epoch_id, input_bytes sframe_epoch_secret) -{ - add_epoch(epoch_id, sframe_epoch_secret, 0); -} - -void MLSContext::add_epoch(EpochID epoch_id, input_bytes sframe_epoch_secret, size_t sender_bits) -{ - auto epoch_index = epoch_id & epoch_mask; - auto& epoch = epoch_cache[epoch_index]; - - if (epoch) - { - purge_epoch(epoch->full_epoch); - } - - epoch.emplace(epoch_id, sframe_epoch_secret, epoch_bits, sender_bits); -} - -void MLSContext::purge_before(EpochID keeper) -{ - for (auto& ptr : epoch_cache) - { - if (ptr && ptr->full_epoch < keeper) - { - purge_epoch(ptr->full_epoch); - ptr.reset(); - } - } -} - -output_bytes MLSContext::protect(EpochID epoch_id, - SenderID sender_id, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata) -{ - return protect(epoch_id, sender_id, 0, ciphertext, plaintext, metadata); -} - -output_bytes MLSContext::protect(EpochID epoch_id, - SenderID sender_id, - ContextID context_id, - output_bytes ciphertext, - input_bytes plaintext, - input_bytes metadata) -{ - auto key_id = form_key_id(epoch_id, sender_id, context_id); - ensure_key(key_id, KeyUsage::protect); - return Context::protect(key_id, ciphertext, plaintext, metadata); -} - -output_bytes -MLSContext::unprotect(output_bytes plaintext, input_bytes ciphertext, input_bytes metadata) -{ - const auto header = Header::parse(ciphertext); - const auto inner_ciphertext = ciphertext.subspan(header.size()); - - ensure_key(header.key_id, KeyUsage::unprotect); - return Context::unprotect_inner(header, plaintext, inner_ciphertext, metadata); -} - -MLSContext::EpochKeys::EpochKeys(MLSContext::EpochID full_epoch_in, - input_bytes sframe_epoch_secret_in, - size_t epoch_bits, - size_t sender_bits_in) : - full_epoch(full_epoch_in), - sframe_epoch_secret(sframe_epoch_secret_in), - sender_bits(sender_bits_in) -{ - static constexpr uint64_t one = 1; - static constexpr size_t key_id_bits = 64; - - if (sender_bits > key_id_bits - epoch_bits) - { - throw invalid_parameter_error("Sender ID field too large"); - } - - // XXX(RLB) We use 0 as a signifier that the sender takes the rest of the key - // ID, and context IDs are not allowed. This would be more explicit if we - // used std::optional, but would require more modern C++. - if (sender_bits == 0) - { - sender_bits = key_id_bits - epoch_bits; - } - - context_bits = key_id_bits - sender_bits - epoch_bits; - max_sender_id = (one << sender_bits) - 1; - max_context_id = (one << context_bits) - 1; -} - -owned_bytes -MLSContext::EpochKeys::base_key(CipherSuite ciphersuite, SenderID sender_id) const -{ - const auto hash_size = cipher_digest_size(ciphersuite); - auto enc_sender_id = owned_bytes<8>(); - encode_uint(sender_id, enc_sender_id); - - return hkdf_expand(ciphersuite, sframe_epoch_secret, enc_sender_id, hash_size); -} - -void MLSContext::purge_epoch(EpochID epoch_id) -{ - const auto drop_bits = epoch_id & epoch_bits; - - keys.erase_if_key([&](const auto& epoch) { return (epoch & epoch_bits) == drop_bits; }); -} - -KeyID MLSContext::form_key_id(EpochID epoch_id, SenderID sender_id, ContextID context_id) const -{ - auto epoch_index = epoch_id & epoch_mask; - auto& epoch = epoch_cache[epoch_index]; - if (!epoch) - { - throw invalid_parameter_error("Unknown epoch. epoch_index: " + std::to_string(epoch_index) - + ", sender_id:" + std::to_string(sender_id)); - } - - if (sender_id > epoch->max_sender_id) - { - throw invalid_parameter_error("Sender ID overflow"); - } - - if (context_id > epoch->max_context_id) - { - throw invalid_parameter_error("Context ID overflow"); - } - - auto sender_part = uint64_t(sender_id) << epoch_bits; - auto context_part = uint64_t(0); - if (epoch->context_bits > 0) - { - context_part = uint64_t(context_id) << (epoch_bits + epoch->sender_bits); - } - - return KeyID(context_part | sender_part | epoch_index); -} - -void MLSContext::ensure_key(KeyID key_id, KeyUsage usage) -{ - // If the required key already exists, we are done - const auto epoch_index = key_id & epoch_mask; - auto& epoch = epoch_cache[epoch_index]; - if (!epoch) - { - throw invalid_parameter_error("Unknown epoch: " + std::to_string(epoch_index)); - } - - if (keys.contains(key_id)) - { - return; - } - - // Otherwise, derive a key and implant it - const auto sender_id = key_id >> epoch_bits; - Context::add_key(key_id, usage, epoch->base_key(suite, sender_id)); - return; -} - -} // namespace sframe diff --git a/firmware/ui/ui.ioc b/firmware/ui/ui.ioc index e6f83ff0..12028810 100644 --- a/firmware/ui/ui.ioc +++ b/firmware/ui/ui.ioc @@ -173,8 +173,8 @@ Mcu.PinsNb=52 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F405RGTx -MxCube.Version=6.13.0 -MxDb.Version=DB.6.0.130 +MxCube.Version=6.14.1 +MxDb.Version=DB.6.0.141 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.DMA1_Stream0_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true NVIC.DMA1_Stream5_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true @@ -400,6 +400,7 @@ PH1-OSC_OUT.Signal=RCC_OSC_OUT PinOutPanel.RotationAngle=0 ProjectManager.AskForMigrate=true ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC ProjectManager.CompilerOptimize=6 ProjectManager.ComputerToolchain=false ProjectManager.CoupleFile=false @@ -412,7 +413,7 @@ ProjectManager.FreePins=false ProjectManager.HalAssertFull=false ProjectManager.HeapSize=0x200 ProjectManager.KeepUserCode=true -ProjectManager.LastFirmware=true +ProjectManager.LastFirmware=false ProjectManager.LibraryCopy=0 ProjectManager.MainLocation=Core/Src ProjectManager.NoMain=false @@ -423,12 +424,12 @@ ProjectManager.ProjectName=ui ProjectManager.ProjectStructure= ProjectManager.RegisterCallBack= ProjectManager.StackSize=0x400 -ProjectManager.TargetToolchain=Makefile +ProjectManager.TargetToolchain=CMake ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true,6-MX_I2S3_Init-I2S3-false-HAL-true,7-MX_SPI1_Init-SPI1-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_USART2_UART_Init-USART2-false-HAL-true,10-MX_TIM2_Init-TIM2-false-HAL-true,11-MX_RNG_Init-RNG-false-HAL-true,12-MX_CRC_Init-CRC-false-HAL-true,13-MX_TIM3_Init-TIM3-false-HAL-true,14-MX_TIM6_Init-TIM6-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true,6-MX_I2S3_Init-I2S3-false-HAL-true,7-MX_SPI1_Init-SPI1-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_USART2_UART_Init-USART2-false-HAL-true,10-MX_TIM2_Init-TIM2-false-HAL-true,11-MX_RNG_Init-RNG-false-HAL-true,12-MX_CRC_Init-CRC-false-HAL-true,13-MX_TIM3_Init-TIM3-false-HAL-true RCC.48MHZClocksFreq_Value=48000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 From 0998fedc4e1d55c3b2a583cb74646df23bd279bd Mon Sep 17 00:00:00 2001 From: trigaux Date: Thu, 29 May 2025 10:47:14 -0400 Subject: [PATCH 2/6] Update sframe with better temp version. --- firmware/ui/dependencies/sframe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ui/dependencies/sframe b/firmware/ui/dependencies/sframe index 3b43c93c..47c70755 160000 --- a/firmware/ui/dependencies/sframe +++ b/firmware/ui/dependencies/sframe @@ -1 +1 @@ -Subproject commit 3b43c93c63df10214aab2b0526684a40b0406850 +Subproject commit 47c70755da9b62a962f0050d8522b3b2e20d6553 From 8cb6ad5387a772a7822fc9486ba44e2bf2545764 Mon Sep 17 00:00:00 2001 From: trigaux Date: Fri, 30 May 2025 11:13:18 -0400 Subject: [PATCH 3/6] Update cmake. --- firmware/ui/CMakeLists.txt | 38 ++++----- firmware/ui/Makefile | 2 +- .../ui/cmake/FindSTM32Cryptographic.cmake | 83 +++++++++++++++++++ firmware/ui/cmake/gcc-arm-none-eabi.cmake | 24 +++--- firmware/ui/dependencies/sframe | 2 +- 5 files changed, 114 insertions(+), 35 deletions(-) create mode 100644 firmware/ui/cmake/FindSTM32Cryptographic.cmake diff --git a/firmware/ui/CMakeLists.txt b/firmware/ui/CMakeLists.txt index 3b5ee695..cadeca25 100644 --- a/firmware/ui/CMakeLists.txt +++ b/firmware/ui/CMakeLists.txt @@ -1,10 +1,7 @@ cmake_minimum_required(VERSION 3.22) -set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake") -add_compile_options( - -mthumb - -fexceptions -) +set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake") +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # # This file is generated only once, @@ -14,18 +11,13 @@ add_compile_options( # # Setup compiler settings -set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) -set(CRYPTO "STM32_CM4" CACHE STRING "") -set(NO_ALLOC ON CACHE BOOL "") -add_subdirectory(dependencies/sframe) - - # Define the build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug") @@ -34,18 +26,23 @@ endif() # Set the project name set(CMAKE_PROJECT_NAME ui) -# Include toolchain file -include("cmake/gcc-arm-none-eabi.cmake") - # Enable compile command to ease indexing with e.g. clangd set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) +# Find dependencies +find_package(STM32Cryptographic COMPONENTS CM4 REQUIRED) +add_library(STM32Cryptographic ALIAS STM32Cryptographic::CM4) + +set(CRYPTO "STM32" CACHE STRING "") +set(NO_ALLOC ON CACHE BOOL "") +add_subdirectory(dependencies/sframe) + # Core project settings -project(${CMAKE_PROJECT_NAME}) +project(${CMAKE_PROJECT_NAME} CXX) message("Build type: " ${CMAKE_BUILD_TYPE}) # Enable CMake support for ASM and C languages -enable_language(C ASM) +enable_language(C CXX ASM) # Create an executable object type add_executable(${CMAKE_PROJECT_NAME}) @@ -60,6 +57,8 @@ target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE file(GLOB_RECURSE CXX_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc") file(GLOB_RECURSE SHARED_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../shared/*.cc") +message(STATUS ${CXX_SOURCES} + ${SHARED_SOURCES}) target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${CXX_SOURCES} ${SHARED_SOURCES} @@ -85,12 +84,9 @@ target_link_libraries(${CMAKE_PROJECT_NAME} sframe ) -set(BIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin") -set(HEX_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.hex") - add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.elf ${BIN_FILE} - COMMAND ${CMAKE_OBJCOPY} -O ihex ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.elf ${HEX_FILE} + COMMAND ${CMAKE_OBJCOPY} -O binary $ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin + COMMAND ${CMAKE_OBJCOPY} -O ihex $ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.hex COMMENT "Generating .bin and .hex files" ) diff --git a/firmware/ui/Makefile b/firmware/ui/Makefile index bad92cf0..a24674f4 100644 --- a/firmware/ui/Makefile +++ b/firmware/ui/Makefile @@ -56,7 +56,7 @@ OCDFLAGS = -f interface/stlink.cfg -f target/stm32f4x.cfg all: info compile compile: CMakeLists.txt - cmake -B $(BUILD_DIR) -DCMAKE_TOOLCHAIN_FILE=cmake/gcc-arm-none-eabi.cmake -DSTM32Cryptographic_ROOT_DIR=${STM32_CRYPTO_DIR} + cmake -B $(BUILD_DIR) -DSTM32Cryptographic_ROOT_DIR=${STM32_CRYPTO_DIR} cmake --build $(BUILD_DIR) -j upload: compile diff --git a/firmware/ui/cmake/FindSTM32Cryptographic.cmake b/firmware/ui/cmake/FindSTM32Cryptographic.cmake new file mode 100644 index 00000000..ad5dc432 --- /dev/null +++ b/firmware/ui/cmake/FindSTM32Cryptographic.cmake @@ -0,0 +1,83 @@ +set(PACKAGE_NAME "STM32Cryptographic") +set(LIBRARY_NAME "STM32Cryptographic") + +# Locate the include directory +find_path( + STM32Cryptographic_INCLUDE_DIR + "cmox_crypto.h" + PATHS + ${STM32Cryptographic_ROOT_DIR} + /usr/local/include + /usr/include + PATH_SUFFIXES include +) + +if(NOT STM32Cryptographic_INCLUDE_DIR) + message(WARNING "Could not find include dir for ${PACKAGE_NAME}") +else() + message(STATUS "Found include dir for ${PACKAGE_NAME}: ${STM32Cryptographic_INCLUDE_DIR}") + include_directories(${STM32Cryptographic_INCLUDE_DIR}) +endif() + +set(SUPPORTED_CORTICES "CM0_CM0PLUS;CM3;CM33;CM4;CM7") + +# Locate the libraries +foreach(STM32_CORTEX ${${PACKAGE_NAME}_FIND_COMPONENTS}) + find_library( + STM32Cryptographic_${STM32_CORTEX} + NAMES STM32Cryptographic_${STM32_CORTEX} + PATHS + ${STM32Cryptographic_ROOT_DIR} + /usr/local/lib + /usr/lib + PATH_SUFFIXES lib + NO_DEFAULT_PATH + ) + + if(NOT STM32Cryptographic_${STM32_CORTEX}) + message(WARNING "Could not find library: STM32Cryptographic_${STM32_CORTEX}") + else() + message(STATUS "Found library for ${PACKAGE_NAME}: STM32Cryptographic_${STM32_CORTEX} at ${STM32Cryptographic_${STM32_CORTEX}}") + endif() + + list(APPEND STM32Cryptographic_LIBRARY "${STM32Cryptographic_${STM32_CORTEX}}") +endforeach() + +# Set the STM32Cryptographic_FOUND variable +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(${PACKAGE_NAME} + REQUIRED_VARS + STM32Cryptographic_INCLUDE_DIR + STM32Cryptographic_LIBRARY +) + +# Set output variables +if(${PACKAGE_NAME}_FOUND) + set(STM32Cryptographic_INCLUDE_DIRS ${STM32Cryptographic_INCLUDE_DIR}) + set(STM32Cryptographic_LIBRARIES ${STM32Cryptographic_LIBRARY}) +else() + set(STM32Cryptographic_INCLUDE_DIRS "") + set(STM32Cryptographic_LIBRARIES "") +endif() + +mark_as_advanced( + STM32Cryptographic_INCLUDE_DIR + STM32Cryptographic_LIBRARY +) + +if (STM32Cryptographic_FOUND) + foreach(STM32_CORTEX ${${PACKAGE_NAME}_FIND_COMPONENTS}) + if(NOT TARGET ${PACKAGE_NAME}::${STM32_CORTEX} AND EXISTS "${${PACKAGE_NAME}_LIBRARY}") + add_library(${PACKAGE_NAME}::${STM32_CORTEX} UNKNOWN IMPORTED) + set_target_properties(${PACKAGE_NAME}::${STM32_CORTEX} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${${PACKAGE_NAME}_INCLUDE_DIR}" + ) + if(EXISTS "${${PACKAGE_NAME}_LIBRARY}") + set_target_properties(${PACKAGE_NAME}::${STM32_CORTEX} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${${PACKAGE_NAME}_LIBRARY}" + ) + endif() + endif() + endforeach() +endif() diff --git a/firmware/ui/cmake/gcc-arm-none-eabi.cmake b/firmware/ui/cmake/gcc-arm-none-eabi.cmake index 86693d25..a69dbe41 100644 --- a/firmware/ui/cmake/gcc-arm-none-eabi.cmake +++ b/firmware/ui/cmake/gcc-arm-none-eabi.cmake @@ -22,24 +22,24 @@ set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # MCU specific flags -set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard ") +set(TARGET_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS} -Wall -fdata-sections -ffunction-sections") set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -fdata-sections -ffunction-sections") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wpedantic") -set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") -set(CMAKE_C_FLAGS_RELEASE "-Os -g0") -set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") -set(CMAKE_CXX_FLAGS_RELEASE "-Os -g0") +set(CMAKE_C_FLAGS_DEBUG "-O0 -g -gdwarf-2") +set(CMAKE_C_FLAGS_RELEASE "-Os") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -gdwarf-2") +set(CMAKE_CXX_FLAGS_RELEASE "-Os") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") set(CMAKE_C_LINK_FLAGS "${TARGET_FLAGS}") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --specs=nosys.specs") set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T \"${CMAKE_SOURCE_DIR}/STM32F405XX_FLASH.ld\"") -set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --specs=nano.specs") -set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections") -set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lc -lm -Wl,--end-group") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -lc -lm -lnosys") +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map,--cref -Wl,--gc-sections") set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--print-memory-usage") -set(CMAKE_CXX_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group") \ No newline at end of file +set(CMAKE_CXX_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group") diff --git a/firmware/ui/dependencies/sframe b/firmware/ui/dependencies/sframe index 47c70755..cdec59ca 160000 --- a/firmware/ui/dependencies/sframe +++ b/firmware/ui/dependencies/sframe @@ -1 +1 @@ -Subproject commit 47c70755da9b62a962f0050d8522b3b2e20d6553 +Subproject commit cdec59ca6de55479edb14b0b714d74a27c108862 From 8b11a1e069e6846e247474ef26860208aab36931 Mon Sep 17 00:00:00 2001 From: trigaux Date: Fri, 30 May 2025 15:21:01 -0400 Subject: [PATCH 4/6] The ultimate fix. --- firmware/ui/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/ui/CMakeLists.txt b/firmware/ui/CMakeLists.txt index cadeca25..14ed2f7c 100644 --- a/firmware/ui/CMakeLists.txt +++ b/firmware/ui/CMakeLists.txt @@ -33,12 +33,13 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) find_package(STM32Cryptographic COMPONENTS CM4 REQUIRED) add_library(STM32Cryptographic ALIAS STM32Cryptographic::CM4) -set(CRYPTO "STM32" CACHE STRING "") -set(NO_ALLOC ON CACHE BOOL "") +set(CRYPTO "STM32" CACHE STRING "" FORCE) +set(NO_ALLOC ON CACHE BOOL "" FORCE) +add_compile_definitions(NO_ALLOC) add_subdirectory(dependencies/sframe) # Core project settings -project(${CMAKE_PROJECT_NAME} CXX) +project(${CMAKE_PROJECT_NAME} C CXX ASM) message("Build type: " ${CMAKE_BUILD_TYPE}) # Enable CMake support for ASM and C languages From d683f1f8d766ab579a5e2a1716f1ad4b2e93566f Mon Sep 17 00:00:00 2001 From: Tomas Rigaux Date: Tue, 3 Jun 2025 13:17:32 -0400 Subject: [PATCH 5/6] Adding cmox. (#243) * Adding cmox. * Addressing review comments and updating sframe. --- README.md | 10 +- firmware/ui/CMakeLists.txt | 1 + firmware/ui/Makefile | 2 +- .../ui/cmake/FindSTM32Cryptographic.cmake | 48 +- firmware/ui/dependencies/cmox/LICENSE.txt | 86 +++ firmware/ui/dependencies/cmox/ReadMe.txt | 36 ++ .../cmox/include/cipher/cmox_blockcipher.h | 103 ++++ .../cmox/include/cipher/cmox_cbc.h | 219 +++++++ .../cmox/include/cipher/cmox_ccm.h | 204 +++++++ .../cmox/include/cipher/cmox_cfb.h | 221 +++++++ .../cmox/include/cipher/cmox_chachapoly.h | 151 +++++ .../include/cipher/cmox_check_default_aes.h | 59 ++ .../include/cipher/cmox_check_default_gcm.h | 59 ++ .../cmox/include/cipher/cmox_cipher.h | 496 ++++++++++++++++ .../cmox/include/cipher/cmox_cipher_retvals.h | 105 ++++ .../cmox/include/cipher/cmox_ctr.h | 219 +++++++ .../cmox/include/cipher/cmox_ecb.h | 218 +++++++ .../cmox/include/cipher/cmox_gcm.h | 414 +++++++++++++ .../cmox/include/cipher/cmox_keywrap.h | 209 +++++++ .../cmox/include/cipher/cmox_ofb.h | 219 +++++++ .../cmox/include/cipher/cmox_xts.h | 196 +++++++ .../dependencies/cmox/include/cmox_common.h | 75 +++ .../dependencies/cmox/include/cmox_crypto.h | 142 +++++ .../ui/dependencies/cmox/include/cmox_cta.h | 50 ++ .../cmox/include/cmox_default_config.h | 363 ++++++++++++ .../cmox/include/cmox_default_defs.h | 551 ++++++++++++++++++ .../cmox/include/cmox_fast_config.h | 360 ++++++++++++ .../ui/dependencies/cmox/include/cmox_info.h | 70 +++ .../ui/dependencies/cmox/include/cmox_init.h | 114 ++++ .../cmox/include/cmox_low_level.h | 66 +++ .../cmox/include/cmox_small_config.h | 360 ++++++++++++ .../cmox/include/drbg/cmox_ctr_drbg.h | 180 ++++++ .../cmox/include/drbg/cmox_drbg.h | 147 +++++ .../cmox/include/drbg/cmox_drbg_retvals.h | 119 ++++ .../dependencies/cmox/include/ecc/cmox_ecc.h | 259 ++++++++ .../cmox/include/ecc/cmox_ecc_custom_curves.h | 126 ++++ .../cmox/include/ecc/cmox_ecc_retvals.h | 72 +++ .../cmox/include/ecc/cmox_ecc_types.h | 52 ++ .../dependencies/cmox/include/ecc/cmox_ecdh.h | 129 ++++ .../cmox/include/ecc/cmox_ecdsa.h | 295 ++++++++++ .../cmox/include/ecc/cmox_eddsa.h | 175 ++++++ .../dependencies/cmox/include/ecc/cmox_sm2.h | 218 +++++++ .../cmox/include/hash/cmox_hash.h | 278 +++++++++ .../cmox/include/hash/cmox_hash_retvals.h | 90 +++ .../dependencies/cmox/include/hash/cmox_md.h | 127 ++++ .../cmox/include/hash/cmox_sha1.h | 104 ++++ .../cmox/include/hash/cmox_sha224.h | 104 ++++ .../cmox/include/hash/cmox_sha256.h | 104 ++++ .../cmox/include/hash/cmox_sha3.h | 162 +++++ .../cmox/include/hash/cmox_sha384.h | 104 ++++ .../cmox/include/hash/cmox_sha512.h | 126 ++++ .../dependencies/cmox/include/hash/cmox_sm3.h | 105 ++++ .../cmox/include/hash/cmox_sponge.h | 85 +++ .../dependencies/cmox/include/mac/cmox_cmac.h | 169 ++++++ .../dependencies/cmox/include/mac/cmox_hmac.h | 259 ++++++++ .../dependencies/cmox/include/mac/cmox_kmac.h | 190 ++++++ .../dependencies/cmox/include/mac/cmox_mac.h | 284 +++++++++ .../cmox/include/mac/cmox_mac_retvals.h | 97 +++ .../dependencies/cmox/include/rsa/cmox_rsa.h | 175 ++++++ .../cmox/include/rsa/cmox_rsa_pkcs1v15.h | 206 +++++++ .../cmox/include/rsa/cmox_rsa_pkcs1v22.h | 226 +++++++ .../cmox/include/rsa/cmox_rsa_retvals.h | 73 +++ .../cmox/include/rsa/cmox_rsa_types.h | 118 ++++ .../cmox/include/utils/cmox_utils_compare.h | 69 +++ .../cmox/include/utils/cmox_utils_retvals.h | 62 ++ .../cmox/lib/libSTM32Cryptographic_CM4.a | Bin 0 -> 617262 bytes firmware/ui/dependencies/sframe | 2 +- firmware/ui/stm32f405rgtx_flash.ld | 208 ------- 68 files changed, 10490 insertions(+), 235 deletions(-) create mode 100644 firmware/ui/dependencies/cmox/LICENSE.txt create mode 100644 firmware/ui/dependencies/cmox/ReadMe.txt create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_blockcipher.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_cbc.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_ccm.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_cfb.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_chachapoly.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_aes.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_gcm.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_cipher.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_cipher_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_ctr.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_ecb.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_gcm.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_keywrap.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_ofb.h create mode 100644 firmware/ui/dependencies/cmox/include/cipher/cmox_xts.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_common.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_crypto.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_cta.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_default_config.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_default_defs.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_fast_config.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_info.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_init.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_low_level.h create mode 100644 firmware/ui/dependencies/cmox/include/cmox_small_config.h create mode 100644 firmware/ui/dependencies/cmox/include/drbg/cmox_ctr_drbg.h create mode 100644 firmware/ui/dependencies/cmox/include/drbg/cmox_drbg.h create mode 100644 firmware/ui/dependencies/cmox/include/drbg/cmox_drbg_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecc.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_custom_curves.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_types.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecdh.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_ecdsa.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_eddsa.h create mode 100644 firmware/ui/dependencies/cmox/include/ecc/cmox_sm2.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_hash.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_hash_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_md.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha1.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha224.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha256.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha3.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha384.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sha512.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sm3.h create mode 100644 firmware/ui/dependencies/cmox/include/hash/cmox_sponge.h create mode 100644 firmware/ui/dependencies/cmox/include/mac/cmox_cmac.h create mode 100644 firmware/ui/dependencies/cmox/include/mac/cmox_hmac.h create mode 100644 firmware/ui/dependencies/cmox/include/mac/cmox_kmac.h create mode 100644 firmware/ui/dependencies/cmox/include/mac/cmox_mac.h create mode 100644 firmware/ui/dependencies/cmox/include/mac/cmox_mac_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/rsa/cmox_rsa.h create mode 100644 firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v15.h create mode 100644 firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v22.h create mode 100644 firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_retvals.h create mode 100644 firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_types.h create mode 100644 firmware/ui/dependencies/cmox/include/utils/cmox_utils_compare.h create mode 100644 firmware/ui/dependencies/cmox/include/utils/cmox_utils_retvals.h create mode 100644 firmware/ui/dependencies/cmox/lib/libSTM32Cryptographic_CM4.a delete mode 100644 firmware/ui/stm32f405rgtx_flash.ld diff --git a/README.md b/README.md index d9132551..e38385ef 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ Hardware design for test device ## Table of contents: -1. [Where To Find Things](#where) -2. [Hardware](#hardware) -3. [Firmware](#firmware) +1. [License](#License) +2. [Where To Find Things](#where) +3. [Hardware](#hardware) +4. [Firmware](#firmware) 1. [Management](#management) 2. [User Interface](#ui) 3. [Network](#network) @@ -17,6 +18,9 @@ Hardware design for test device 2. [Python Serial Monitor](#serial_monitor) 5. [Hactar Setup](#hactar_setup) +## License + +The license for information in this repository is in [LICENSE]. This license covers everything in the repository except for the directory `firmware/ui/dependencies/cmox`, which is covered by the license in [firmware/ui/dependencies/cmox/LICENSE].

Where To Find Things

diff --git a/firmware/ui/CMakeLists.txt b/firmware/ui/CMakeLists.txt index 14ed2f7c..fdfee662 100644 --- a/firmware/ui/CMakeLists.txt +++ b/firmware/ui/CMakeLists.txt @@ -30,6 +30,7 @@ set(CMAKE_PROJECT_NAME ui) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) # Find dependencies +set(STM32Cryptographic_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/cmox) find_package(STM32Cryptographic COMPONENTS CM4 REQUIRED) add_library(STM32Cryptographic ALIAS STM32Cryptographic::CM4) diff --git a/firmware/ui/Makefile b/firmware/ui/Makefile index a24674f4..f7275319 100644 --- a/firmware/ui/Makefile +++ b/firmware/ui/Makefile @@ -56,7 +56,7 @@ OCDFLAGS = -f interface/stlink.cfg -f target/stm32f4x.cfg all: info compile compile: CMakeLists.txt - cmake -B $(BUILD_DIR) -DSTM32Cryptographic_ROOT_DIR=${STM32_CRYPTO_DIR} + cmake -B $(BUILD_DIR) cmake --build $(BUILD_DIR) -j upload: compile diff --git a/firmware/ui/cmake/FindSTM32Cryptographic.cmake b/firmware/ui/cmake/FindSTM32Cryptographic.cmake index ad5dc432..a5d218d5 100644 --- a/firmware/ui/cmake/FindSTM32Cryptographic.cmake +++ b/firmware/ui/cmake/FindSTM32Cryptographic.cmake @@ -1,22 +1,26 @@ set(PACKAGE_NAME "STM32Cryptographic") set(LIBRARY_NAME "STM32Cryptographic") +if (${PACKAGE_NAME}_FOUND) + return() +endif() + # Locate the include directory find_path( - STM32Cryptographic_INCLUDE_DIR + ${PACKAGE_NAME}_INCLUDE_DIR "cmox_crypto.h" PATHS - ${STM32Cryptographic_ROOT_DIR} + ${${PACKAGE_NAME}_ROOT_DIR} /usr/local/include /usr/include PATH_SUFFIXES include ) -if(NOT STM32Cryptographic_INCLUDE_DIR) +if(NOT ${PACKAGE_NAME}_INCLUDE_DIR) message(WARNING "Could not find include dir for ${PACKAGE_NAME}") else() - message(STATUS "Found include dir for ${PACKAGE_NAME}: ${STM32Cryptographic_INCLUDE_DIR}") - include_directories(${STM32Cryptographic_INCLUDE_DIR}) + message(STATUS "Found include dir for ${PACKAGE_NAME}: ${${PACKAGE_NAME}_INCLUDE_DIR}") + include_directories(${${PACKAGE_NAME}_INCLUDE_DIR}) endif() set(SUPPORTED_CORTICES "CM0_CM0PLUS;CM3;CM33;CM4;CM7") @@ -24,48 +28,48 @@ set(SUPPORTED_CORTICES "CM0_CM0PLUS;CM3;CM33;CM4;CM7") # Locate the libraries foreach(STM32_CORTEX ${${PACKAGE_NAME}_FIND_COMPONENTS}) find_library( - STM32Cryptographic_${STM32_CORTEX} - NAMES STM32Cryptographic_${STM32_CORTEX} + ${PACKAGE_NAME}_${STM32_CORTEX} + NAMES ${PACKAGE_NAME}_${STM32_CORTEX} PATHS - ${STM32Cryptographic_ROOT_DIR} + ${${PACKAGE_NAME}_ROOT_DIR} /usr/local/lib /usr/lib PATH_SUFFIXES lib NO_DEFAULT_PATH ) - if(NOT STM32Cryptographic_${STM32_CORTEX}) - message(WARNING "Could not find library: STM32Cryptographic_${STM32_CORTEX}") + if(NOT ${PACKAGE_NAME}_${STM32_CORTEX}) + message(WARNING "Could not find library: ${PACKAGE_NAME}_${STM32_CORTEX}") else() - message(STATUS "Found library for ${PACKAGE_NAME}: STM32Cryptographic_${STM32_CORTEX} at ${STM32Cryptographic_${STM32_CORTEX}}") + message(STATUS "Found library for ${PACKAGE_NAME}: ${PACKAGE_NAME}_${STM32_CORTEX} at ${${PACKAGE_NAME}_${STM32_CORTEX}}") endif() - list(APPEND STM32Cryptographic_LIBRARY "${STM32Cryptographic_${STM32_CORTEX}}") + list(APPEND ${PACKAGE_NAME}_LIBRARY "${${PACKAGE_NAME}_${STM32_CORTEX}}") endforeach() -# Set the STM32Cryptographic_FOUND variable +# Set the ${PACKAGE_NAME}_FOUND variable include(FindPackageHandleStandardArgs) find_package_handle_standard_args(${PACKAGE_NAME} REQUIRED_VARS - STM32Cryptographic_INCLUDE_DIR - STM32Cryptographic_LIBRARY + ${PACKAGE_NAME}_INCLUDE_DIR + ${PACKAGE_NAME}_LIBRARY ) # Set output variables if(${PACKAGE_NAME}_FOUND) - set(STM32Cryptographic_INCLUDE_DIRS ${STM32Cryptographic_INCLUDE_DIR}) - set(STM32Cryptographic_LIBRARIES ${STM32Cryptographic_LIBRARY}) + set(${PACKAGE_NAME}_INCLUDE_DIRS ${${PACKAGE_NAME}_INCLUDE_DIR}) + set(${PACKAGE_NAME}_LIBRARIES ${${PACKAGE_NAME}_LIBRARY}) else() - set(STM32Cryptographic_INCLUDE_DIRS "") - set(STM32Cryptographic_LIBRARIES "") + set(${PACKAGE_NAME}_INCLUDE_DIRS "") + set(${PACKAGE_NAME}_LIBRARIES "") endif() mark_as_advanced( - STM32Cryptographic_INCLUDE_DIR - STM32Cryptographic_LIBRARY + ${PACKAGE_NAME}_INCLUDE_DIR + ${PACKAGE_NAME}_LIBRARY ) -if (STM32Cryptographic_FOUND) +if (${PACKAGE_NAME}_FOUND) foreach(STM32_CORTEX ${${PACKAGE_NAME}_FIND_COMPONENTS}) if(NOT TARGET ${PACKAGE_NAME}::${STM32_CORTEX} AND EXISTS "${${PACKAGE_NAME}_LIBRARY}") add_library(${PACKAGE_NAME}::${STM32_CORTEX} UNKNOWN IMPORTED) diff --git a/firmware/ui/dependencies/cmox/LICENSE.txt b/firmware/ui/dependencies/cmox/LICENSE.txt new file mode 100644 index 00000000..a8900afd --- /dev/null +++ b/firmware/ui/dependencies/cmox/LICENSE.txt @@ -0,0 +1,86 @@ +This software component is provided to you as part of a software package and +applicable license terms are in the Package_license file. If you received this +software component outside of a package or without applicable license terms, +the terms of the SLA0044 license shall apply and are fully reproduced below: + +SLA0044 Rev5/February 2018 + +Software license agreement + +ULTIMATE LIBERTY SOFTWARE LICENSE AGREEMENT + +BY INSTALLING, COPYING, DOWNLOADING, ACCESSING OR OTHERWISE USING THIS SOFTWARE +OR ANY PART THEREOF (AND THE RELATED DOCUMENTATION) FROM STMICROELECTRONICS +INTERNATIONAL N.V, SWISS BRANCH AND/OR ITS AFFILIATED COMPANIES +(STMICROELECTRONICS), THE RECIPIENT, ON BEHALF OF HIMSELF OR HERSELF, OR ON +BEHALF OF ANY ENTITY BY WHICH SUCH RECIPIENT IS EMPLOYED AND/OR ENGAGED AGREES +TO BE BOUND BY THIS SOFTWARE LICENSE AGREEMENT. + +Under STMicroelectronics’ intellectual property rights, the redistribution, +reproduction and use in source and binary forms of the software or any part +thereof, with or without modification, are permitted provided that the following +conditions are met: + +1. Redistribution of source code (modified or not) must retain any copyright +notice, this list of conditions and the disclaimer set forth below as items 10 +and 11. + +2. Redistributions in binary form, except as embedded into microcontroller or +microprocessor device manufactured by or for STMicroelectronics or a software +update for such device, must reproduce any copyright notice provided with the +binary code, this list of conditions, and the disclaimer set forth below as +items 10 and 11, in documentation and/or other materials provided with the +distribution. + +3. Neither the name of STMicroelectronics nor the names of other contributors to +this software may be used to endorse or promote products derived from this +software or part thereof without specific written permission. + +4. This software or any part thereof, including modifications and/or derivative +works of this software, must be used and execute solely and exclusively on or in +combination with a microcontroller or microprocessor device manufactured by or +for STMicroelectronics. + +5. No use, reproduction or redistribution of this software partially or totally +may be done in any manner that would subject this software to any Open Source +Terms. “Open Source Terms” shall mean any open source license which requires as +part of distribution of software that the source code of such software is +distributed therewith or otherwise made available, or open source license that +substantially complies with the Open Source definition specified at +www.opensource.org and any other comparable open source license such as for +example GNU General Public License (GPL), Eclipse Public License (EPL), Apache +Software License, BSD license or MIT license. + +6. STMicroelectronics has no obligation to provide any maintenance, support or +updates for the software. + +7. The software is and will remain the exclusive property of STMicroelectronics +and its licensors. The recipient will not take any action that jeopardizes +STMicroelectronics and its licensors' proprietary rights or acquire any rights +in the software, except the limited rights specified hereunder. + +8. The recipient shall comply with all applicable laws and regulations affecting +the use of the software or any part thereof including any applicable export +control law or regulation. + +9. Redistribution and use of this software or any part thereof other than as +permitted under this license is void and will automatically terminate your +rights under this license. + +10. THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS, WHICH ARE +DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT SHALL +STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +11. EXCEPT AS EXPRESSLY PERMITTED HEREUNDER, NO LICENSE OR OTHER RIGHTS, WHETHER +EXPRESS OR IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY +RIGHTS OF STMICROELECTRONICS OR ANY THIRD PARTY. + diff --git a/firmware/ui/dependencies/cmox/ReadMe.txt b/firmware/ui/dependencies/cmox/ReadMe.txt new file mode 100644 index 00000000..71695239 --- /dev/null +++ b/firmware/ui/dependencies/cmox/ReadMe.txt @@ -0,0 +1,36 @@ +/************************************************************************************************* +* +* Software implementation of STM32 Cryptographic libraries: High Level API +* +************************************************************************************************** +* +* Copyright (c) 2021 STMicroelectronics. +* All rights reserved. +* +* This software is licensed under terms that can be found in the LICENSE file +* in the root directory of this software component. +************************************************************************************************** +* +* This directory contains the header files of the Cryptographic services exposed by the +* STM32 Cryptographic libraries. +* The Cryptographic services are the followings: +* * AES-128/192/256 Encryption/Decryption in ECB/CBC/CFB/CTR/OFB/XTS/KeyWrap modes +* * AES-128/192/256 CCM/GCM Authenticated Encryption/Decryption +* * SM4 Encryption/Decryption in ECB/CBC/CFB/CTR/OFB modes +* * ChaCha20-Poly1305 Authenticated Encryption/Decryption +* * CTR-DRBG based on AES-128/256 +* * SHA1/SHA2/SHA3/SHAKE/SM3 Hash functions +* * HMAC/CMAC/KMAC Message Authentication Code functions +* * RSA PKCS#1 v1.5/v2.2 Signature Creation/Verification and Encryption/Decryption functions +* * ECDSA/EdDSA/SM2 Key Generation and Signature Creation/Verification functions +* * ECDH Key Exchange functions +* +* Some parts of the STM32 Cryptographic libraries has been inspired from third-party SW components +* from: +* * muNaCl, by Michael Hutter, Peter Schwabe, Bjrn Haase and Ana Helena Snchez +* * libtomcrypt, by T. St-Denis +* * eXtended Keccak Code Package, by Guido Bertoni, Joan Daemen, Seth Hoffert, Michal Peeters, +* Gilles Van Assche and Ronny Van Keer +* * poly1305-donna, by Andrew Moon +* * chacha-ref.c, by D. J. Bernstein +***************************************************************************************************/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_blockcipher.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_blockcipher.h new file mode 100644 index 00000000..be759108 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_blockcipher.h @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @file cmox_blockcipher.h + * @author MCD Application Team + * @brief Header file for the block cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_BLOCKCIPHER_H +#define CMOX_BLOCKCIPHER_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include + +#include "cmox_cipher_retvals.h" +#include "cmox_cipher.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_BLOCKCIPHER Block cipher definitions + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_BLOCKCIPHER_MACROS Block cipher macros + * @{ + */ + +#define CMOX_CIPHER_BLOCK_SIZE 4U /*!< Block size, in words, of a block cipher (AES and SM4) */ + +#define CMOX_SM4_EXPKEY_SIZE 32U /*!< Size, in words, of the expanded SM4 key */ +#define CMOX_AES128_EXPKEY_SIZE 44U /*!< Size, in words, of the expanded AES128 key */ +#define CMOX_AES192_EXPKEY_SIZE 52U /*!< Size, in words, of the expanded AES192 key */ +#define CMOX_AES256_EXPKEY_SIZE 60U /*!< Size, in words, of the expanded AES256 key */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_BLOCKCIPHER_PUBLIC_TYPES Block cipher public types + * @{ + */ + +/** + * @brief Block cipher algorithm type + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific algorithm, defined in the library internally + */ +typedef const struct cmox_blockcipher_vtableStruct_st *cmox_blockcipher_vtable_t; + +/** + * @brief Block cipher context handle + */ +typedef struct +{ + cmox_blockcipher_vtable_t table; /*!< Used block cipher algorithm */ + + cmox_cipher_keyLen_t keyLen; /*!< Size, in bytes, of the block cipher's key */ + uint32_t internalState; /*!< Internal state of the block cipher */ + uint32_t expandedKey[CMOX_AES256_EXPKEY_SIZE]; /*!< Buffer containing the expanded key */ +} cmox_blockcipher_handle_t; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_BLOCKCIPHER_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_cbc.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_cbc.h new file mode 100644 index 00000000..d0f6c838 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_cbc.h @@ -0,0 +1,219 @@ +/** + ****************************************************************************** + * @file cmox_cbc.h + * @author MCD Application Team + * @brief Header file for the CBC cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CBC_H +#define CMOX_CBC_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_default_defs.h" +#include "cmox_check_default_aes.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CBC CBC cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CBC_PUBLIC_TYPES CBC public types + * @{ + */ + +/** + * @brief CBC mode implementation + * + * This type specifies the used block cipher for the CBC construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_cbc_implStruct_st *cmox_cbc_impl_t; + +/** + * @brief CBC handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ +} cmox_cbc_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CBC_PUBLIC_CONSTANTS CBC public constants + * @{ + */ + +/** @defgroup CMOX_CBC_IMPL CBC implementations + * @{ + */ + +/** + * @brief Implementation of CBC encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_AESFAST_CBC_ENC; + +/** + * @brief Implementation of CBC decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_AESFAST_CBC_DEC; + +/** + * @brief Implementation of CBC encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_AESSMALL_CBC_ENC; + +/** + * @brief Implementation of CBC decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_AESSMALL_CBC_DEC; + +/** + * @brief Implementation of CBC encryption using SM4 (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_SM4_CBC_ENC; + +/** + * @brief Implementation of CBC decryption using SM4 (Defined internally) + */ +extern const cmox_cbc_impl_t CMOX_SM4_CBC_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_CBC_ALGO CBC single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the CBC encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CBC_ENC_ALGO; + +/** + * @brief Identifier of the CBC decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CBC_DEC_ALGO; + +/** + * @brief Identifier of the CBC encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CBC_ENC_ALGO; + +/** + * @brief Identifier of the CBC decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CBC_DEC_ALGO; + +/** + * @brief Identifier of the CBC encryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CBC_ENC_ALGO; + +/** + * @brief Identifier of the CBC decryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CBC_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public method prototypes --------------------------------------------------*/ + +/** @defgroup CMOX_CBC_PUBLIC_METHODS CBC public method prototypes + * @{ + */ + +/** + * @brief CBC constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CBC algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the CBC handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_CBC_ENC + * @arg CMOX_AESFAST_CBC_DEC + * @arg CMOX_AESSMALL_CBC_ENC + * @arg CMOX_AESSMALL_CBC_DEC + * @arg CMOX_SM4_CBC_ENC + * @arg CMOX_SM4_CBC_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_cbc_construct(cmox_cbc_handle_t *P_pThis, + cmox_cbc_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CBC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_ccm.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_ccm.h new file mode 100644 index 00000000..a430c2ce --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_ccm.h @@ -0,0 +1,204 @@ +/** + ****************************************************************************** + * @file cmox_ccm.h + * @author MCD Application Team + * @brief Header file for the CCM AEAD cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CCM_H +#define CMOX_CCM_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CCM CCM cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ + + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CCM_PUBLIC_TYPES CCM public types + * @{ + */ + +/** + * @brief CCM mode implementation + * + * This type specifies the used block cipher for the CCM construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_ccm_implStruct_st *cmox_ccm_impl_t; + +/** + * @brief CCM handle structure + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t ivCtr[4]; /*!< Current IV value for encryption.*/ + uint32_t ivCbc[4]; /*!< Current IV value for authentication.*/ + size_t tagLen; /*!< Size of the tag to return. Possible values are values are {4,6,8,10,12,14,16} */ + size_t AdLen; /*!< Len of the associated data to be processed */ + size_t payloadLen; /*!< Size of the total payload data to be processed */ + size_t nonceLen; /*!< Size of the Nonce in bytes. Possible values are {7,8,9,10,11,12,13} */ + uint32_t tmpBuf[4]; /*!< Temporary buffer used for internal computations */ + uint32_t tmpBufUse; /*!< Number of bytes in use for internal computations */ +} cmox_ccm_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CCM_PUBLIC_CONSTANTS CCM public constants + * @{ + */ + +/** @defgroup CMOX_CCM_IMPL CCM implementations + * @{ + */ + +/** + * @brief Implementation of CCM encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ccm_impl_t CMOX_AESFAST_CCM_ENC; + +/** + * @brief Implementation of CCM decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ccm_impl_t CMOX_AESFAST_CCM_DEC; + +/** + * @brief Implementation of CCM encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ccm_impl_t CMOX_AESSMALL_CCM_ENC; + +/** + * @brief Implementation of CCM decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ccm_impl_t CMOX_AESSMALL_CCM_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_CCM_ALGO CCM single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the CCM encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_CCM_ENC_ALGO; + +/** + * @brief Identifier of the CCM decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_CCM_DEC_ALGO; + +/** + * @brief Identifier of the CCM encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_CCM_ENC_ALGO; + +/** + * @brief Identifier of the CCM decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_CCM_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CCM_PUBLIC_METHODS CCM public method prototypes + * @{ + */ + +/** + * @brief CCM constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CCM algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the CCM handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_CCM_ENC + * @arg CMOX_AESFAST_CCM_DEC + * @arg CMOX_AESSMALL_CCM_ENC + * @arg CMOX_AESSMALL_CCM_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_ccm_construct(cmox_ccm_handle_t *P_pThis, + cmox_ccm_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CCM_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_cfb.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_cfb.h new file mode 100644 index 00000000..7fe1caa4 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_cfb.h @@ -0,0 +1,221 @@ +/** + ****************************************************************************** + * @file cmox_cfb.h + * @author MCD Application Team + * @brief Header file for the CFB cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CFB_H +#define CMOX_CFB_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_default_defs.h" +#include "cmox_check_default_aes.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CFB CFB cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CFB_PUBLIC_TYPES CFB public types + * @{ + */ + +/** + * @brief CFB mode implementation + * + * This type specifies the used block cipher for the CFB construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_cfb_implStruct_st *cmox_cfb_impl_t; + +/** + * @brief CFB handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ + size_t cfb_blockLen; /*!< Size of the CFB block. Currently only 16 bytes block supported */ +} cmox_cfb_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CFB_PUBLIC_CONSTANTS CFB public constants + * @{ + */ + +/** @defgroup CMOX_CFB_IMPL CFB implementations + * @{ + */ + +/** + * @brief Implementation of CFB encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_AESFAST_CFB_ENC; + +/** + * @brief Implementation of CFB decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_AESFAST_CFB_DEC; + +/** + * @brief Implementation of CFB encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_AESSMALL_CFB_ENC; + +/** + * @brief Implementation of CFB decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_AESSMALL_CFB_DEC; + +/** + * @brief Implementation of CFB encryption using SM4 (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_SM4_CFB_ENC; + +/** + * @brief Implementation of CFB decryption using SM4 (Defined internally) + */ +extern const cmox_cfb_impl_t CMOX_SM4_CFB_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_CFB_ALGO CFB single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the CFB encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CFB_ENC_ALGO; + +/** + * @brief Identifier of the CFB decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CFB_DEC_ALGO; + +/** + * @brief Identifier of the CFB encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CFB_ENC_ALGO; + +/** + * @brief Identifier of the CFB decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CFB_DEC_ALG; + +/** + * @brief Identifier of the CFB encryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CFB_ENC_ALGO; + +/** + * @brief Identifier of the CFB decryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CFB_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CFB_PUBLIC_METHODS CFB public method prototypes + * @{ + */ + +/** + * @brief CFB constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CFB algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the CFB handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_CFB_ENC + * @arg CMOX_AESFAST_CFB_DEC + * @arg CMOX_AESSMALL_CFB_ENC + * @arg CMOX_AESSMALL_CFB_DEC + * @arg CMOX_SM4_CFB_ENC + * @arg CMOX_SM4_CFB_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_cfb_construct(cmox_cfb_handle_t *P_pThis, + cmox_cfb_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CFB_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_chachapoly.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_chachapoly.h new file mode 100644 index 00000000..65f78359 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_chachapoly.h @@ -0,0 +1,151 @@ +/** + ****************************************************************************** + * @file cmox_chachapoly.h + * @author MCD Application Team + * @brief Header file for the ChaCha20-Poly1305 AEAD cipher functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CHACHA20_POLY1305_H +#define CMOX_CHACHA20_POLY1305_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CHACHAPOLY ChaCha20-Poly1305 cipher + * @{ + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CHACHAPOLY_PUBLIC_TYPES ChaCha20-Poly1305 public types + * @{ + */ + +/** + * @brief ChaCha20-Poly1305 mode implementation + * + * This type specifies if the algorithm will be used for encryption or + * decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_chachapoly_implStruct_st *cmox_chachapoly_impl_t; + +/** + * @brief ChaCha20-Poly1305 handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + size_t mAadLen; /*!< Size of the processed AAD */ + size_t mCipherLen; /*!< Size of the processed CipherText */ + uint32_t rValue[5]; /*!< Internal: value of r */ + uint32_t hValue[5]; /*!< Internal: value of h */ + uint32_t pad[4]; /*!< Internal: value of Poly nonce */ + uint32_t internalState[16]; /*!< Internal: ChaCha Internal State */ +} cmox_chachapoly_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CHACHAPOLY_PUBLIC_CONSTANTS ChaCha20-Poly1305 public + * constants + * @{ + */ + +/** + * @brief Implementation of ChaCha20-Poly1305 encryption (Defined internally) + */ +extern const cmox_chachapoly_impl_t CMOX_CHACHAPOLY_ENC; + +/** + * @brief Implementation of ChaCha20-Poly1305 decryption (Defined internally) + */ +extern const cmox_chachapoly_impl_t CMOX_CHACHAPOLY_DEC; + +/** + * @} + */ + +/** + * @brief Identifier of the ChaCha20-Poly1305 encryption for single-call function + * (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_CHACHAPOLY_ENC_ALGO; + +/** + * @brief Identifier of the ChaCha20-Poly1305 decryption for single-call function + * (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_CHACHAPOLY_DEC_ALGO; + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CHACHAPOLY_PUBLIC_METHODS ChaCha20-Poly1305 public method + * prototypes + * @{ + */ + +/** + * @brief ChaCha20-Poly1305 constructor + * + * The function is used for specifying if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the ChaCha20-Poly1305 handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_CHACHAPOLY_ENC + * @arg CMOX_CHACHAPOLY_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_chachapoly_construct(cmox_chachapoly_handle_t *P_pThis, + cmox_chachapoly_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CHACHA20_POLY1305_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_aes.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_aes.h new file mode 100644 index 00000000..53b5010e --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_aes.h @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * @file cmox_check_default_aes.h + * @author MCD Application Team + * @brief Header file for checking that the default values for AES are + * correctly set + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CHECK_DEFAULT_AES_H +#define CMOX_CHECK_DEFAULT_AES_H + +#if !defined(CMOX_DEFAULT_FILE) +#include "cmox_default_config.h" +#else +#include CMOX_DEFAULT_FILE +#endif /* CMOX_DEFAULT_FILE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef CMOX_AES_IMPLEMENTATION +#error CMOX_AES_IMPLEMENTATION must be defined for using AES +#endif /* CMOX_AES_IMPLEMENTATION */ + +#ifndef CMOX_AES_FAST +#error CMOX_AES_FAST must be defined for using AES +#endif /* CMOX_AES_FAST */ + +#ifndef CMOX_AES_SMALL +#error CMOX_AES_SMALL must be defined for using AES +#endif /* CMOX_AES_SMALL */ + +#if ((CMOX_AES_IMPLEMENTATION != CMOX_AES_FAST) && (CMOX_AES_IMPLEMENTATION != CMOX_AES_SMALL)) +#error CMOX_AES_IMPLEMENTATION value must be CMOX_AES_FAST or CMOX_AES_SMALL +#endif /* ((CMOX_AES_IMPLEMENTATION != CMOX_AES_FAST) && (CMOX_AES_IMPLEMENTATION != CMOX_AES_SMALL)) */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_CHECK_DEFAULT_AES_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_gcm.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_gcm.h new file mode 100644 index 00000000..7735c50e --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_check_default_gcm.h @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * @file cmox_check_default_gcm.h + * @author MCD Application Team + * @brief Header file for checking that the default values for AES are + * correctly set + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CHECK_DEFAULT_GCM_H +#define CMOX_CHECK_DEFAULT_GCM_H + +#if !defined(CMOX_DEFAULT_FILE) +#include "cmox_default_config.h" +#else +#include CMOX_DEFAULT_FILE +#endif /* CMOX_DEFAULT_FILE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef CMOX_GCM_IMPLEMENTATION +#error CMOX_GCM_IMPLEMENTATION must be defined for using GCM +#endif /* CMOX_GCM_IMPLEMENTATION */ + +#ifndef CMOX_GCM_FAST +#error CMOX_GCM_FAST must be defined for using GCM +#endif /* CMOX_GCM_FAST */ + +#ifndef CMOX_GCM_SMALL +#error CMOX_GCM_SMALL must be defined for using GCM +#endif /* CMOX_GCM_SMALL */ + +#if ((CMOX_GCM_IMPLEMENTATION != CMOX_GCM_FAST) && (CMOX_GCM_IMPLEMENTATION != CMOX_GCM_SMALL)) +#error CMOX_GCM_IMPLEMENTATION value must be CMOX_GCM_FAST or CMOX_GCM_SMALL +#endif /* ((CMOX_GCM_IMPLEMENTATION != CMOX_GCM_FAST) && (CMOX_GCM_IMPLEMENTATION != CMOX_GCM_SMALL)) */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_CHECK_DEFAULT_GCM_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher.h new file mode 100644 index 00000000..41f63827 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher.h @@ -0,0 +1,496 @@ +/** + ****************************************************************************** + * @file cmox_cipher.h + * @author MCD Application Team + * @brief Header file for the Cipher module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CIPHER_H +#define CMOX_CIPHER_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include +#include +#include "cmox_cipher_retvals.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_CIPHER_KEYSIZE Key sizes for the cipher module + * @{ + */ + +/** + * @brief Size in bytes of AES128 and SM4 keys + */ +#define CMOX_CIPHER_128_BIT_KEY ((cmox_cipher_keyLen_t)16U) + +/** + * @brief Size in bytes of AES192 keys + */ +#define CMOX_CIPHER_192_BIT_KEY ((cmox_cipher_keyLen_t)24U) + +/** + * @brief Size in bytes of AES256 keys + */ +#define CMOX_CIPHER_256_BIT_KEY ((cmox_cipher_keyLen_t)32U) + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CIPHER_PUBLIC_TYPES Cipher module public types + * @{ + */ + +/** + * @brief Type for specifying the key size for the cipher + */ +typedef size_t cmox_cipher_keyLen_t; + +/** + * @brief Cipher Virtual Table + * + * This type specifies a pointer to the virtual table containing the methods + * for a particular algorithm (e.g. CBC or CHACHA20-POLY1305) + */ +typedef const struct cmox_cipher_vtableStruct_st *cmox_cipher_vtable_t; + +/** + * @brief Cipher algorithm type + * + * This type specifies the algorithm to use with the cipher module (e.g. CBC). + * The type is defined as a pointer to a structure, that + * contains the functions for the specific algorithm, defined in the library + * internally + */ +typedef const struct cmox_cipher_algoStruct_st *cmox_cipher_algo_t; + +/** + * @brief AEAD algorithm type + * + * This type specifies the AEAD algorithm to use with the cipher module + * (e.g. CCM or CHACHA20-POLY1305). + * The type is defined as a pointer to a structure, that + * contains the functions for the specific algorithm, defined in the library + * internally + */ +typedef const struct cmox_aead_algoStruct_st *cmox_aead_algo_t; + +/** + * @brief Cipher handle structure definition + */ +typedef struct +{ + cmox_cipher_vtable_t table; /*!< Cipher virtual table */ + uint32_t internalState; /*!< internal state of the cipher handle */ +} cmox_cipher_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CIPHER_PUBLIC_METHODS Cipher public method prototypes + * @{ + */ + +/** + * @brief Cleanup the cipher handle + * + * @param P_pThis Cipher handle to cleanup + * @return cmox_cipher_retval_t Cipher return value + */ +cmox_cipher_retval_t cmox_cipher_cleanup(cmox_cipher_handle_t *P_pThis); + +/** + * @brief Initialize the cipher handle for performing the specified algorithm + * + * @param P_pThis Cipher handle to initialize + * @return cmox_cipher_retval_t Cipher return value + * @note The cipher handle must be derived from an algorithm-specific handle + * using the correct constructor + */ +cmox_cipher_retval_t cmox_cipher_init(cmox_cipher_handle_t *P_pThis); + +/** + * @brief Se the key to be used with the cipher algorithm + * + * @param P_pThis Cipher handle to set + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Len in bytes of the key + * @return cmox_cipher_retval_t Cipher return value + * @note The XTS mode of operation requires a key with size double than the + * normal one (i.e. AES128-XTS will require a 32 bytes key, AES256-XTS + * will require a 64 bytes key and so on) + */ +cmox_cipher_retval_t cmox_cipher_setKey(cmox_cipher_handle_t *P_pThis, + const uint8_t *P_pKey, + cmox_cipher_keyLen_t P_keyLen); + +/** + * @brief Set the initialization vector/nonce to be used with the cipher + * algorithm + * + * @param P_pThis Cipher handle to set + * @param P_pIv Buffer of bytes containing the IV/nonce + * @param P_ivLen Size in bytes of the key + * @return cmox_cipher_retval_t Cipher return value + */ +cmox_cipher_retval_t cmox_cipher_setIV(cmox_cipher_handle_t *P_pThis, + const uint8_t *P_pIv, + size_t P_ivLen); + +/** + * @brief Set the size of the tag for AEAD cipher + * + * @param P_pThis Cipher handle to set + * @param P_tagLen Size in bytes of the tag + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used only for AEAD ciphers. If used with other + * cipher, it won't have any effects + * @note For ChaCha20-Poly1305 the tag size is fixed to 16 bytes, and this + * function has no effects + */ +cmox_cipher_retval_t cmox_cipher_setTagLen(cmox_cipher_handle_t *P_pThis, + size_t P_tagLen); + +/** + * @brief Set the total payload size (only for CCM AEAD cipher) + * + * @param P_pThis Cipher handle to set + * @param P_totalPayloadLen Size in bytes of the total payload + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used for CCM ciphers. If used with other + * cipher, it won't have any effects + */ +cmox_cipher_retval_t cmox_cipher_setPayloadLen(cmox_cipher_handle_t *P_pThis, + size_t P_totalPayloadLen); + +/** + * @brief Set the total authenticated data size (only for CCM AEAD cipher) + * + * @param P_pThis Cipher handle to set + * @param P_totalADLen Size in bytes of the total authenticated data + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used for CCM ciphers. If used with other + * cipher, it won't have any effects + */ +cmox_cipher_retval_t cmox_cipher_setADLen(cmox_cipher_handle_t *P_pThis, + size_t P_totalADLen); + +/** + * @brief Append additional authenticated data to the cipher handle + * + * @param P_pThis Cipher handle where the authenticated data will be appended + * @param P_pInput Buffer of bytes containing the data to append + * @param P_inputLen Size in bytes of the data to append + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used only for AEAD ciphers. If used with other + * cipher, it won't have any effects + */ +cmox_cipher_retval_t cmox_cipher_appendAD(cmox_cipher_handle_t *P_pThis, + const uint8_t *P_pInput, + size_t P_inputLen); + +/** + * @brief Append part or the totality of the plaintext/ciphertext and return the + * corresponding ciphertext/plaintext + * + * @param P_pThis Cipher handle to use for ciphering the data + * @param P_pInput Buffer of bytes containing the data to append + * @param P_inputLen Size in bytes of the data to append + * @param P_pOutput Buffer of bytes where there will be stored the encrypted or + * decrypted data + * @param P_pOutputLen Number of bytes that have been generated by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t Cipher return value + * @note ECB and CFB modes of operation for AES and SM4 require that the input + * length for each append is multiple of the block size (i.e. 16 bytes) + * @note CBC mode of operation will apply CS2 ciphertext stealing + * NIST SP 800-38A Addendum + * in case the input length is greater than 16 bytes and not multiple of + * 16 bytes. After CS2 is applied, no more appends are allowed. + * @note CTR, OFB, GCM and CCM modes of operation permits to have input not + * multiple of the block size (i.e. 16 bytes for AES and SM4), but after + * this no more further appends are allowed. + * @note For ChaCha20-Poly1305, this function can be called multiple times with + * P_inputLen multiple of 64 bytes. A single, last, call can be made + * with any value for P_inputLen. + * @note With the exception of KEYWRAP algorithm, the minimum size of P_pOutput + * buffer must be P_inputLen. + * @note For KEYWRAP mode, this function must be used to append the key to wrap, + * and must be done in a single call (no partial append of the key is + * supported). The P_pOutput buffer will contain the encrypted key AND the + * 8 bytes authentication tag. So the minimum size of this buffer must be + * P_inputLen + 8. + */ +cmox_cipher_retval_t cmox_cipher_append(cmox_cipher_handle_t *P_pThis, + const uint8_t *P_pInput, + size_t P_inputLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Generate the authenticated tag in case the AEAD operation is an + * encryption + * + * @param P_pThis Cipher handle used for encrypting the data + * @param P_pTag Buffer of bytes where there will be stored the generated tag + * @param P_pTagLen Number of bytes that have been processed by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used only for AEAD ciphers in encryption mode. If + * used with other cipher, it won't have any effects. If used with AEAD + * cipher in decryption mode, it will raise an error. + */ +cmox_cipher_retval_t cmox_cipher_generateTag(cmox_cipher_handle_t *P_pThis, + uint8_t *P_pTag, + size_t *P_pTagLen); + +/** + * @brief Authenticate the processed data with the given tag + * + * @param P_pThis Cipher used for decrypting the data + * @param P_pTag Buffer of bytes containing the tag to use for the verification + * @param P_pFaultCheck Optional value to check, together with the retval, + * to verify if some fault happened + * @return cmox_cipher_retval_t Cipher return value + * @note This function must be used only for AEAD ciphers in decryption mode. If + * used with other cipher, it won't have any effects. If used with AEAD + * cipher in encryption mode, it will raise an error. + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must + * be done against the success value, and not comparing the value with the + * failure value. Indeed, in presence of faults, especially P_pFaultCheck, + * could be a dirty value. + */ +cmox_cipher_retval_t cmox_cipher_verifyTag(cmox_cipher_handle_t *P_pThis, + const uint8_t *P_pTag, + uint32_t *P_pFaultCheck); + +/** + * @brief Encrypt or decrypt a message using a symmetric cipher + * + * @param P_algo Identifier of the cipher algorithm to use for the computation. + * This parameter can be one of the following: + * @arg CMOX_AESFAST_ECB_ENC_ALGO + * @arg CMOX_AESFAST_CBC_ENC_ALGO + * @arg CMOX_AESFAST_CTR_ENC_ALGO + * @arg CMOX_AESFAST_CFB_ENC_ALGO + * @arg CMOX_AESFAST_OFB_ENC_ALGO + * @arg CMOX_AESFAST_XTS_ENC_ALGO + * @arg CMOX_AESSMALL_ECB_ENC_ALGO + * @arg CMOX_AESSMALL_CBC_ENC_ALGO + * @arg CMOX_AESSMALL_CTR_ENC_ALGO + * @arg CMOX_AESSMALL_CFB_ENC_ALGO + * @arg CMOX_AESSMALL_OFB_ENC_ALGO + * @arg CMOX_AESSMALL_XTS_ENC_ALGO + * @arg CMOX_AESSMALL_KEYWRAP_ENC_ALGO + * @arg CMOX_SM4_ECB_ENC_ALGO + * @arg CMOX_SM4_CBC_ENC_ALGO + * @arg CMOX_SM4_CTR_ENC_ALGO + * @arg CMOX_SM4_CFB_ENC_ALGO + * @arg CMOX_SM4_OFB_ENC_ALGO + * @param P_pInput Buffer of bytes containing the data to encrypt or decrypt + * @param P_inputLen Length in bytes of the data to encrypt or decrypt + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Length in bytes of the key + * @param P_pIv Buffer of bytes containing the IV/nonce + * @param P_ivLen Length in bytes of the key + * @param P_pOutput Buffer of bytes where there will be stored the encrypted or + * decrypted data + * @param P_pOutputLen Number of bytes that have been processed by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t Cipher return value + * @note This single call function cannot be used for AEAD ciphers + */ +cmox_cipher_retval_t cmox_cipher_encrypt(cmox_cipher_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + const uint8_t *P_pKey, + cmox_cipher_keyLen_t P_keyLen, + const uint8_t *P_pIv, + size_t P_ivLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Decrypt a message using a symmetric cipher + * + * @param P_algo Identifier of the cipher algorithm to use for the computation. + * This parameter can be one of the following: + * @arg CMOX_AESFAST_ECB_DEC_ALGO + * @arg CMOX_AESFAST_CBC_DEC_ALGO + * @arg CMOX_AESFAST_CTR_DEC_ALGO + * @arg CMOX_AESFAST_CFB_DEC_ALGO + * @arg CMOX_AESFAST_OFB_DEC_ALGO + * @arg CMOX_AESFAST_XTS_DEC_ALGO + * @arg CMOX_AESFAST_KEYWRAP_DEC_ALGO + * @arg CMOX_AESSMALL_ECB_DEC_ALGO + * @arg CMOX_AESSMALL_CBC_DEC_ALGO + * @arg CMOX_AESSMALL_CTR_DEC_ALGO + * @arg CMOX_AESSMALL_CFB_DEC_ALGO + * @arg CMOX_AESSMALL_OFB_DEC_ALGO + * @arg CMOX_AESSMALL_XTS_DEC_ALGO + * @arg CMOX_AESSMALL_KEYWRAP_DEC_ALGO + * @arg CMOX_SM4_ECB_DEC_ALGO + * @arg CMOX_SM4_CBC_DEC_ALGO + * @arg CMOX_SM4_CTR_DEC_ALGO + * @arg CMOX_SM4_CFB_DEC_ALGO + * @arg CMOX_SM4_OFB_DEC_ALGO + * @param P_pInput Buffer of bytes containing the data to encrypt or decrypt + * @param P_inputLen Length in bytes of the data to encrypt or decrypt + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Length in bytes of the key + * @param P_pIv Buffer of bytes containing the IV/nonce + * @param P_ivLen Length in bytes of the key + * @param P_pOutput Buffer of bytes where there will be stored the decrypted + * data. + * @param P_pOutputLen Number of bytes that have been processed by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t Cipher return value + * @note This single call function cannot be used for AEAD ciphers + */ +cmox_cipher_retval_t cmox_cipher_decrypt(cmox_cipher_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + const uint8_t *P_pKey, + cmox_cipher_keyLen_t P_keyLen, + const uint8_t *P_pIv, + size_t P_ivLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Encrypt a message using AEAD cipher + * + * @param P_algo Identifier of the AEAD cipher algorithm to use for the + * computation. This parameter can be one of the following: + * @arg CMOX_AESFAST_GCMFAST_ENC_ALGO + * @arg CMOX_AESFAST_GCMSMALL_ENC_ALGO + * @arg CMOX_AESSMALL_GCMFAST_ENC_ALGO + * @arg CMOX_AESSMALL_GCMSMALL_ENC_ALGO + * @arg CMOX_AESFAST_CCM_ENC_ALGO + * @arg CMOX_AESSMALL_CCM_ENC_ALGO + * @arg CMOX_CHACHAPOLY_ENC_ALGO + * @param P_pInput Buffer of bytes containing the data to encrypt + * @param P_inputLen Length in bytes of the data to encrypt + * @param P_tagLen Length in bytes of the authentication tag to append to the + * ciphertext + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Length in bytes of the key + * @param P_pIv Buffer of bytes containing the IV/nonce + * @param P_ivLen Length in bytes of the key + * @param P_pAddData Buffer of bytes containing the additional data to be used + * for authentication + * @param P_addDataLen Length in bytes of the Additional data + * @param P_pOutput Buffer of bytes where there will be stored the encrypted and + * authenticated data (i.e. ciphertext + tag) + * @param P_pOutputLen Number of bytes that have been generated by the function. + * If correct, it will be the size of the encrypted and authenticated + * data (i.e. ciphertext + tag). + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t + * @note This single call function can be used for AEAD ciphers only + */ +cmox_cipher_retval_t cmox_aead_encrypt(cmox_aead_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + size_t P_tagLen, + const uint8_t *P_pKey, + cmox_cipher_keyLen_t P_keyLen, + const uint8_t *P_pIv, + size_t P_ivLen, + const uint8_t *P_pAddData, + size_t P_addDataLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Decrypt a message using AEAD cipher + * + * @param P_algo Identifier of the AEAD cipher algorithm to use for the + * computation. This parameter can be one of the following: + * @arg CMOX_AESFAST_GCMFAST_DEC_ALGO + * @arg CMOX_AESFAST_GCMSMALL_DEC_ALGO + * @arg CMOX_AESSMALL_GCMFAST_DEC_ALGO + * @arg CMOX_AESSMALL_GCMSMALL_DEC_ALGO + * @arg CMOX_AESFAST_CCM_DEC_ALGO + * @arg CMOX_AESSMALL_CCM_DEC_ALGO + * @arg CMOX_CHACHAPOLY_DEC_ALGO + * @param P_pInput Buffer of bytes containing the authenticated and encrypted + * data (i.e. ciphertext + tag) + * @param P_inputLen Length in bytes of the the authenticated and encrypted + * data (i.e. ciphertext + tag) + * @param P_tagLen Length in bytes of the tag + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Length in bytes of the key + * @param P_pIv Buffer of bytes containing the IV/nonce + * @param P_ivLen Length in bytes of the key + * @param P_pAddData Buffer of bytes containing the additional data to be used + * for authentication + * @param P_addDataLen Length in bytes of the Additional data + * @param P_pOutput Buffer of bytes where there will be stored the decrypted + * data + * @param P_pOutputLen Number of bytes that have been generated by the function. + * If correct, it will be the plaintext size. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_cipher_retval_t + * @note This single call function can be used for AEAD ciphers only + */ +cmox_cipher_retval_t cmox_aead_decrypt(cmox_aead_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + size_t P_tagLen, + const uint8_t *P_pKey, + cmox_cipher_keyLen_t P_keyLen, + const uint8_t *P_pIv, + size_t P_ivLen, + const uint8_t *P_pAddData, + size_t P_addDataLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CIPHER_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher_retvals.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher_retvals.h new file mode 100644 index 00000000..6d38b3aa --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_cipher_retvals.h @@ -0,0 +1,105 @@ +/** + ****************************************************************************** + * @file cmox_cipher_retvals.h + * @author MCD Application Team + * @brief Header file containing the return values for the cipher module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CIPHER_RETVALS_H +#define CMOX_CIPHER_RETVALS_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CIPHER_RETVALS Cipher return values + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** + * @brief Cipher operation successfully performed + */ +#define CMOX_CIPHER_SUCCESS ((cmox_cipher_retval_t)0x00010000U) + +/** + * @brief Some error happens internally in the cipher module + */ +#define CMOX_CIPHER_ERR_INTERNAL ((cmox_cipher_retval_t)0x00010001U) + +/** + * @brief The function is not implemented for the current algorithm + */ +#define CMOX_CIPHER_ERR_NOT_IMPLEMENTED ((cmox_cipher_retval_t)0x00010002U) + +/** + * @brief One or more parameter has been wrongly passed to the function + * (e.g. pointer to NULL) + */ +#define CMOX_CIPHER_ERR_BAD_PARAMETER ((cmox_cipher_retval_t)0x00010003U) + +/** + * @brief Error on performing the operation + * (e.g. an operation has been called before initializing the handle) + */ +#define CMOX_CIPHER_ERR_BAD_OPERATION ((cmox_cipher_retval_t)0x00010004U) + +/** + * @brief A buffer with a wrong size has been passed to the function + */ +#define CMOX_CIPHER_ERR_BAD_INPUT_SIZE ((cmox_cipher_retval_t)0x00010005U) + +/** + * @brief Authentication of the tag has been successful + */ +#define CMOX_CIPHER_AUTH_SUCCESS ((cmox_cipher_retval_t)0x0001C726U) + +/** + * @brief Authentication of the tag failed + */ +#define CMOX_CIPHER_AUTH_FAIL ((cmox_cipher_retval_t)0x00016E93U) + +/* Public types --------------------------------------------------------------*/ + +/** + * @brief Cipher module return value type + */ +typedef uint32_t cmox_cipher_retval_t; + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CIPHER_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_ctr.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_ctr.h new file mode 100644 index 00000000..f89e9822 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_ctr.h @@ -0,0 +1,219 @@ +/** + ****************************************************************************** + * @file cmox_ctr.h + * @author MCD Application Team + * @brief Header file for the CTR cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CTR_H +#define CMOX_CTR_H + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_CTR CTR cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CTR_PUBLIC_TYPES CTR public types + * @{ + */ + +/** + * @brief CTR mode implementation + * + * This type specifies the used block cipher for the CTR construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_ctr_implStruct_st *cmox_ctr_impl_t; + +/** + * @brief CTR handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ +} cmox_ctr_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CTR_PUBLIC_CONSTANTS CTR public constants + * @{ + */ + +/** @defgroup CMOX_CTR_IMPL CTR implementations + * @{ + */ + +/** + * @brief Implementation of CTR encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_AESFAST_CTR_ENC; + +/** + * @brief Implementation of CTR decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_AESFAST_CTR_DEC; + +/** + * @brief Implementation of CTR encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_AESSMALL_CTR_ENC; + +/** + * @brief Implementation of CTR decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_AESSMALL_CTR_DEC; + +/** + * @brief Implementation of CTR encryption using SM4 (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_SM4_CTR_ENC; + +/** + * @brief Implementation of CTR decryption using SM4 (Defined internally) + */ +extern const cmox_ctr_impl_t CMOX_SM4_CTR_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_CTR_ALGO CTR single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the CTR encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CTR_ENC_ALGO; + +/** + * @brief Identifier of the CTR decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_CTR_DEC_ALGO; + +/** + * @brief Identifier of the CTR encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CTR_ENC_ALGO; + +/** + * @brief Identifier of the CTR decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_CTR_DEC_ALGO; + +/** + * @brief Identifier of the CTR encryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CTR_ENC_ALGO; + +/** + * @brief Identifier of the CTR decryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_CTR_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CTR_PUBLIC_METHODS CTR public method prototypes + * @{ + */ + +/** + * @brief CTR constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CTR algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the CTR handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_CTR_ENC + * @arg CMOX_AESFAST_CTR_DEC + * @arg CMOX_AESSMALL_CTR_ENC + * @arg CMOX_AESSMALL_CTR_DEC + * @arg CMOX_SM4_CTR_ENC + * @arg CMOX_SM4_CTR_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_ctr_construct(cmox_ctr_handle_t *P_pThis, + cmox_ctr_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CTR_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_ecb.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_ecb.h new file mode 100644 index 00000000..4c592196 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_ecb.h @@ -0,0 +1,218 @@ +/** + ****************************************************************************** + * @file cmox_ecb.h + * @author MCD Application Team + * @brief Header file for the ECB cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_ECB_H +#define CMOX_ECB_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_ECB ECB cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_ECB_PUBLIC_TYPES ECB public types + * @{ + */ + +/** + * @brief ECB mode implementation + * + * This type specifies the used block cipher for the ECB construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_ecb_implStruct_st *cmox_ecb_impl_t; + +/** + * @brief ECB handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ +} cmox_ecb_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_ECB_PUBLIC_CONSTANTS ECB public constants + * @{ + */ + +/** @defgroup CMOX_ECB_IMPL ECB implementations + * @{ + */ + +/** + * @brief Implementation of ECB encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_AESFAST_ECB_ENC; + +/** + * @brief Implementation of ECB decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_AESFAST_ECB_DEC; + +/** + * @brief Implementation of ECB encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_AESSMALL_ECB_ENC; + +/** + * @brief Implementation of ECB decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_AESSMALL_ECB_DEC; + +/** + * @brief Implementation of ECB encryption using SM4 (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_SM4_ECB_ENC; + +/** + * @brief Implementation of ECB decryption using SM4 (Defined internally) + */ +extern const cmox_ecb_impl_t CMOX_SM4_ECB_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_ECB_ALGO ECB single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the ECB encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_ECB_ENC_ALGO; + +/** + * @brief Identifier of the ECB decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_ECB_DEC_ALGO; + +/** + * @brief Identifier of the ECB encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_ECB_ENC_ALGO; + +/** + * @brief Identifier of the ECB decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_ECB_DEC_ALGO; + +/** + * @brief Identifier of the ECB encryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_ECB_ENC_ALGO; + +/** + * @brief Identifier of the ECB decryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_ECB_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_ECB_PUBLIC_METHODS ECB public method prototypes + * @{ + */ + +/** + * @brief ECB constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the ECB algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the ECB handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_ECB_ENC + * @arg CMOX_AESFAST_ECB_DEC + * @arg CMOX_AESSMALL_ECB_ENC + * @arg CMOX_AESSMALL_ECB_DEC + * @arg CMOX_SM4_ECB_ENC + * @arg CMOX_SM4_ECB_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_ecb_construct(cmox_ecb_handle_t *P_pThis, + cmox_ecb_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_ECB_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_gcm.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_gcm.h new file mode 100644 index 00000000..bf1c7d02 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_gcm.h @@ -0,0 +1,414 @@ +/** + ****************************************************************************** + * @file cmox_gcm.h + * @author MCD Application Team + * @brief Header file for the GCM AEAD cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_GCM_H +#define CMOX_GCM_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_gcm.h" +#include "cmox_check_default_aes.h" + +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_GCM GCM cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_GCM_PUBLIC_TYPES GCM public types + * @{ + */ + +/** + * @brief Type for specifying the GFMUL operation to use (internally used) + */ +typedef const struct cmox_gcm_gfmulTable_st *cmox_gcm_gfmul_t; + +/** + * @brief GCM SMALL mode implementation + * + * This type specifies the used block cipher for the GCM construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_gcmSmall_implStruct_st *cmox_gcmSmall_impl_t; + + +/** + * @brief GCM FAST mode implementation + * + * This type specifies the used block cipher for the GCM construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_gcmFast_implStruct_st *cmox_gcmFast_impl_t; + +/** + * @brief Polynomial type used internally by GCM + */ +typedef uint32_t cmox_gcm_poly_t[4]; + +/** + * @brief Polynomial table type used by GCM SMALL implementation + */ +typedef cmox_gcm_poly_t cmox_gcm_table16_t[16]; + +/** + * @brief Polynomial table type used by GCM FAST implementation + */ +typedef cmox_gcm_poly_t cmox_gcm_table8x16_t[8][16]; + + +/** + * @brief Common fields for both GCM FAST and GCM SMALL handles + */ +typedef struct +{ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the IV */ + size_t tagLen; /*!< Size in bytes of the aithentication tag */ + size_t AdLen; /*!< Size in bytes of the Additional Data */ + size_t payloadLen; /*!< Processed payload size in bytes */ + cmox_gcm_poly_t partialAuth; /*!< Partial authentication value */ + cmox_gcm_gfmul_t gfmul; /*!< GF mul implementation */ +} cmox_gcm_common_t; + +/** + * @brief GCM SMALL handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_gcm_common_t common; /*!< Common values with the GCM FAST handle type */ + cmox_gcm_table16_t precomputedValues; /*!< Precomputation of polynomial according to Shoup's 4-bit table */ +} cmox_gcmSmall_handle_t; + +/** + * @brief GCM fast context + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_gcm_common_t common; /*!< Common values with the GCM SMALL handle type */ + cmox_gcm_table8x16_t precomputedValues; /*!< Precomputation of polynomial according to Shoup's 8-bit table */ +} cmox_gcmFast_handle_t; + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief Default GCM handle definition + */ +typedef cmox_gcmFast_handle_t cmox_gcm_handle_t; + +/** + * @brief Default GCM implementation definition + */ +typedef cmox_gcmFast_impl_t cmox_gcm_impl_t; + +#elif (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL) +/** + * @brief Default GCM handle definition + */ +typedef cmox_gcmSmall_handle_t cmox_gcm_handle_t; + +/** + * @brief Default GCM implementation definition + */ +typedef cmox_gcmSmall_impl_t cmox_gcm_impl_t; + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_GCM_PUBLIC_CONSTANTS GCM public constants + * @{ + */ + +/** @defgroup CMOX_GCM_IMPL GCM implementations + * @{ + */ + +/** + * @brief Implementation of GCMSMALL encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_gcmSmall_impl_t CMOX_AESFAST_GCMSMALL_ENC; + +/** + * @brief Implementation of GCMSMALL decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_gcmSmall_impl_t CMOX_AESFAST_GCMSMALL_DEC; + +/** + * @brief Implementation of GCMSMALL encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_gcmSmall_impl_t CMOX_AESSMALL_GCMSMALL_ENC; + +/** + * @brief Implementation of GCMSMALL decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_gcmSmall_impl_t CMOX_AESSMALL_GCMSMALL_DEC; + +/** + * @brief Implementation of GCMFAST encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_gcmFast_impl_t CMOX_AESFAST_GCMFAST_ENC; + +/** + * @brief Implementation of GCMFAST decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_gcmFast_impl_t CMOX_AESFAST_GCMFAST_DEC; + +/** + * @brief Implementation of GCMFAST encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_gcmFast_impl_t CMOX_AESSMALL_GCMFAST_ENC; + +/** + * @brief Implementation of GCMFAST decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_gcmFast_impl_t CMOX_AESSMALL_GCMFAST_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_GCM_ALGO GCM single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the GCM (fast implementation) encryption using AES + * (small implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_GCMFAST_ENC_ALGO; + +/** + * @brief Identifier of the GCM (fast implementation) decryption using AES + * (small implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_GCMFAST_DEC_ALGO; + +/** + * @brief Identifier of the GCM (fast implementation) encryption using AES + * (fast implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_GCMFAST_ENC_ALGO; + +/** + * @brief Identifier of the GCM (fast implementation) decryption using AES + * (fast implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_GCMFAST_DEC_ALGO; + +/** + * @brief Identifier of the GCM (small implementation) encryption using AES + * (small implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_GCMSMALL_ENC_ALGO; + +/** + * @brief Identifier of the GCM (small implementation) decryption using AES + * (small implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESSMALL_GCMSMALL_DEC_ALGO; + +/** + * @brief Identifier of the GCM (small implementation) encryption using AES + * (fast implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_GCMSMALL_ENC_ALGO; + +/** + * @brief Identifier of the GCM (small implementation) decryption using AES + * (fast implementation) for single-call function (Defined internally) + */ +extern const cmox_aead_algo_t CMOX_AESFAST_GCMSMALL_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_GCM_PUBLIC_METHODS GCM public method prototypes + * @{ + */ + +/** + * @brief GCMSMALL constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the GCM algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the GCM handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_GCMSMALL_ENC + * @arg CMOX_AESFAST_GCMSMALL_DEC + * @arg CMOX_AESSMALL_GCMSMALL_ENC + * @arg CMOX_AESSMALL_GCMSMALL_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + * @note If CMOX_GCM_IMPLEMENTATION macro has been set to CMOX_GCM_SMALL, this + * constructor can be called also through the wrapper cmox_gcm_construct + */ +cmox_cipher_handle_t *cmox_gcmSmall_construct(cmox_gcmSmall_handle_t *P_pThis, + cmox_gcmSmall_impl_t P_impl); + +/** + * @brief GCMFAST constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the GCM algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the GCM handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_GCMFAST_ENC + * @arg CMOX_AESFAST_GCMFAST_DEC + * @arg CMOX_AESSMALL_GCMFAST_ENC + * @arg CMOX_AESSMALL_GCMFAST_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + * @note If CMOX_GCM_IMPLEMENTATION macro has been set to CMOX_GCM_FAST, this + * constructor can be called also through the wrapper cmox_gcm_construct + */ +cmox_cipher_handle_t *cmox_gcmFast_construct(cmox_gcmFast_handle_t *P_pThis, + cmox_gcmFast_impl_t P_impl); + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief GCM default constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the GCM algorithm (default implementation) and if the + * algorithm will be used for encryption or decryption. + * + * @param P_pThis Pointer to the GCM handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AES_GCM_ENC + * @arg CMOX_AES_GCM_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + * @note This function is just a wrapper of the default implementation of the + * GCM algorithm. It is possible to select the preferred GCM + * implementation from the cmox_default_config.h header file or using a custom + * default configuration header file, to be specified by the + * CMOX_DEFAULT_FILE macro + */ +static inline +cmox_cipher_handle_t *cmox_gcm_construct(cmox_gcm_handle_t *P_pThis, + cmox_gcm_impl_t P_impl) +{ + return cmox_gcmFast_construct(P_pThis, P_impl); +} + +#elif (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL) + +/** + * @brief GCM default constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the GCM algorithm (default implementation) and if the + * algorithm will be used for encryption or decryption. + * + * @param P_pThis Pointer to the GCM handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AES_GCM_ENC + * @arg CMOX_AES_GCM_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + * @note This function is just a wrapper of the default implementation of the + * GCM algorithm. It is possible to select the preferred GCM + * implementation from the cmox_default_config.h header file or using a custom + * default configuration header file, to be specified by the + * CMOX_DEFAULT_FILE macro + */ +static inline +cmox_cipher_handle_t *cmox_gcm_construct(cmox_gcm_handle_t *P_pThis, + cmox_gcm_impl_t P_impl) +{ + return cmox_gcmSmall_construct(P_pThis, P_impl); +} + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_GCM_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_keywrap.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_keywrap.h new file mode 100644 index 00000000..9b20f8e5 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_keywrap.h @@ -0,0 +1,209 @@ +/** + ****************************************************************************** + * @file cmox_keywrap.h + * @author MCD Application Team + * @brief Header file for the KEYWRAP cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_KEYWRAP_H +#define CMOX_KEYWRAP_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_KEYWRAP KEYWRAP cipher + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_KEYWRAP_PUBLIC_MACROS KEYWRAP public macros + * @{ + */ + +/** + * @brief Size in bytes of the keywrap tag + */ +#define CMOX_KEYWRAP_TAG_LEN 8U + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_KEYWRAP_PUBLIC_TYPES KEYWRAP public types + * @{ + */ + +/** + * @brief KEYWRAP mode implementation + * + * This type specifies the used block cipher for the KEYWRAP construct and if + * the algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_keywrap_implStruct_st *cmox_keywrap_impl_t; + +/** + * @brief KEYWRAP handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ +} cmox_keywrap_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_KEYWRAP_PUBLIC_CONSTANTS KEYWRAP public constants + * @{ + */ + +/** @defgroup CMOX_KEYWRAP_IMPL KEYWRAP implementations + * @{ + */ + +/** + * @brief Implementation of KEYWRAP encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_keywrap_impl_t CMOX_AESFAST_KEYWRAP_ENC; + +/** + * @brief Implementation of KEYWRAP decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_keywrap_impl_t CMOX_AESFAST_KEYWRAP_DEC; + +/** + * @brief Implementation of KEYWRAP encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_keywrap_impl_t CMOX_AESSMALL_KEYWRAP_ENC; + +/** + * @brief Implementation of KEYWRAP decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_keywrap_impl_t CMOX_AESSMALL_KEYWRAP_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_KEYWRAP_ALGO KEYWRAP single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the KEYWRAP encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_KEYWRAP_ENC_ALGO; + +/** + * @brief Identifier of the KEYWRAP decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_KEYWRAP_DEC_ALGO; + +/** + * @brief Identifier of the KEYWRAP encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_KEYWRAP_ENC_ALGO; + +/** + * @brief Identifier of the KEYWRAP decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_KEYWRAP_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_KEYWRAP_PUBLIC_METHODS KEYWRAP public method prototypes + * @{ + */ + +/** + * @brief KEYWRAP constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the KEYWRAP algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the KEYWRAP handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_KEYWRAP_ENC + * @arg CMOX_AESFAST_KEYWRAP_DEC + * @arg CMOX_AESSMALL_KEYWRAP_ENC + * @arg CMOX_AESSMALL_KEYWRAP_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_keywrap_construct(cmox_keywrap_handle_t *P_pThis, + cmox_keywrap_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_KEYWRAP_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_ofb.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_ofb.h new file mode 100644 index 00000000..4a3e2aed --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_ofb.h @@ -0,0 +1,219 @@ +/** + ****************************************************************************** + * @file cmox_ofb.h + * @author MCD Application Team + * @brief Header file for the OFB cipher definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_OFB_H +#define CMOX_OFB_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_OFB OFB cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_OFB_PUBLIC_TYPES OFB public types + * @{ + */ + +/** + * @brief OFB mode implementation + * + * This type specifies the used block cipher for the OFB construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_ofb_implStruct_st *cmox_ofb_impl_t; + +/** + * @brief OFB handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ +} cmox_ofb_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_OFB_PUBLIC_CONSTANTS OFB public constants + * @{ + */ + +/** @defgroup CMOX_OFB_IMPL OFB implementations + * @{ + */ + +/** + * @brief Implementation of OFB encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_AESFAST_OFB_ENC; + +/** + * @brief Implementation of OFB decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_AESFAST_OFB_DEC; + +/** + * @brief Implementation of OFB encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_AESSMALL_OFB_ENC; + +/** + * @brief Implementation of OFB decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_AESSMALL_OFB_DEC; + +/** + * @brief Implementation of OFB encryption using SM4 (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_SM4_OFB_ENC; + +/** + * @brief Implementation of OFB decryption using SM4 (Defined internally) + */ +extern const cmox_ofb_impl_t CMOX_SM4_OFB_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_OFB_ALGO OFB single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the OFB encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_OFB_ENC_ALGO; + +/** + * @brief Identifier of the OFB decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_OFB_DEC_ALGO; + +/** + * @brief Identifier of the OFB encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_OFB_ENC_ALGO; + +/** + * @brief Identifier of the OFB decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_OFB_DEC_ALGO; + +/** + * @brief Identifier of the OFB encryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_OFB_ENC_ALGO; + +/** + * @brief Identifier of the OFB decryption using SM4 + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_SM4_OFB_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_OFB_PUBLIC_METHODS OFB public method prototypes + * @{ + */ + +/** + * @brief OFB constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the OFB algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the OFB handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_OFB_ENC + * @arg CMOX_AESFAST_OFB_DEC + * @arg CMOX_AESSMALL_OFB_ENC + * @arg CMOX_AESSMALL_OFB_DEC + * @arg CMOX_SM4_OFB_ENC + * @arg CMOX_SM4_OFB_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_ofb_construct(cmox_ofb_handle_t *P_pThis, + cmox_ofb_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_OFB_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cipher/cmox_xts.h b/firmware/ui/dependencies/cmox/include/cipher/cmox_xts.h new file mode 100644 index 00000000..5cdb9980 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cipher/cmox_xts.h @@ -0,0 +1,196 @@ +/** + ****************************************************************************** + * @file cmox_xts.h + * @author MCD Application Team + * @brief Header file for the XTS cipher + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_XTS_H +#define CMOX_XTS_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_cipher.h" +#include "cmox_blockcipher.h" + +#include "cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +/** @addtogroup CMOX_CIPHER + * @{ + */ + +/** @defgroup CMOX_XTS XTS cipher + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_XTS_PUBLIC_TYPES XTS public types + * @{ + */ + +/** + * @brief XTS mode implementation + * + * This type specifies the used block cipher for the XTS construct and if the + * algorithm will be used for encryption or decryption. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_xts_implStruct_st *cmox_xts_impl_t; + +/** + * @brief XTS handle structure definition + */ +typedef struct +{ + cmox_cipher_handle_t super; /*!< General cipher handle */ + cmox_blockcipher_handle_t blockCipher1; /*!< Block cipher handle */ + cmox_blockcipher_handle_t blockCipher2; /*!< Block cipher handle */ + uint32_t tweak[CMOX_CIPHER_BLOCK_SIZE]; /*!< Temporary result/tweak */ +} cmox_xts_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_XTS_PUBLIC_CONSTANTS XTS public constants + * @{ + */ + +/** @defgroup CMOX_XTS_IMPL XTS implementations + * @{ + */ + +/** + * @brief Implementation of XTS encryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_xts_impl_t CMOX_AESFAST_XTS_ENC; + +/** + * @brief Implementation of XTS decryption using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_xts_impl_t CMOX_AESFAST_XTS_DEC; + +/** + * @brief Implementation of XTS encryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_xts_impl_t CMOX_AESSMALL_XTS_ENC; + +/** + * @brief Implementation of XTS decryption using AES (small implementation) + * (Defined internally) + */ +extern const cmox_xts_impl_t CMOX_AESSMALL_XTS_DEC; + +/** + * @} + */ + +/** @defgroup CMOX_XTS_ALGO XTS single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the XTS encryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_XTS_ENC_ALGO; + +/** + * @brief Identifier of the XTS decryption using AES (small implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESSMALL_XTS_DEC_ALGO; + +/** + * @brief Identifier of the XTS encryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_XTS_ENC_ALGO; + +/** + * @brief Identifier of the XTS decryption using AES (fast implementation) + for single-call function (Defined internally) + */ +extern const cmox_cipher_algo_t CMOX_AESFAST_XTS_DEC_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public method prototypes --------------------------------------------------*/ + +/** @defgroup CMOX_XTS_PUBLIC_METHODS XTS public method prototypes + * @{ + */ + +/** + * @brief XTS constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the XTS algorithm and if the algorithm will be used for + * encryption or decryption. + * + * @param P_pThis Pointer to the XTS handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_AESFAST_XTS_ENC + * @arg CMOX_AESFAST_XTS_DEC + * @arg CMOX_AESSMALL_XTS_ENC + * @arg CMOX_AESSMALL_XTS_DEC + * @return cmox_cipher_handle_t* Pointer to a general cipher handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_cipher_handle_t *cmox_xts_construct(cmox_xts_handle_t *P_pThis, + cmox_xts_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_XTS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_common.h b/firmware/ui/dependencies/cmox/include/cmox_common.h new file mode 100644 index 00000000..53886970 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_common.h @@ -0,0 +1,75 @@ +/** + ****************************************************************************** + * @file cmox_common.h + * @author MCD Application Team + * @brief This file provides the types used within the RSA module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_COMMON_H +#define CMOX_COMMON_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @brief Structure to store information on the static memory + */ +typedef struct +{ + uint8_t *MemBuf; /*!< Pointer to the pre-allocated memory buffer */ + size_t MemBufSize; /*!< Total size of the pre-allocated memory buffer */ + size_t MemBufUsed; /*!< Currently used portion of the buffer */ + size_t MaxMemUsed; /*!< Max memory used */ +} cmox_membuf_handle_st; + + +/** + * @brief Mathematical functions customizations for RSA and ECC + */ +typedef const struct cmox_math_funcsStruct_st *cmox_math_funcs_t; + +extern const cmox_math_funcs_t CMOX_MATH_FUNCS_SMALL; /*!< Smaller footprint and slower performance */ +extern const cmox_math_funcs_t CMOX_MATH_FUNCS_FAST; /*!< Bigger footprint and faster performance */ +extern const cmox_math_funcs_t CMOX_MATH_FUNCS_SUPERFAST256; /*!< Bigger footprint and faster performance, + speed up those ECC curves whose length is in the + range [225, 256] bits, e.g. Curve25519, Secp256, + Bpp256, Ed25519, Frp256, SM2. */ + + +/** + * @brief Modular exponentiation functions customizations for RSA + */ +typedef const struct cmox_modexp_funcStruct_st *cmox_modexp_func_t; + +extern const cmox_modexp_func_t CMOX_MODEXP_PUBLIC; /*!< Suggested Modexp value for the target device public operations */ + +extern const cmox_modexp_func_t CMOX_MODEXP_PRIVATE_LOWMEM; /*!< Constant-time (for Private operations) using Low Memory */ +extern const cmox_modexp_func_t CMOX_MODEXP_PRIVATE_MIDMEM; /*!< Constant-time (for Private operations) using Mid Memory */ +extern const cmox_modexp_func_t CMOX_MODEXP_PRIVATE_HIGHMEM; /*!< Constant-time (for Private operations) using High Memory */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_COMMON_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_crypto.h b/firmware/ui/dependencies/cmox/include/cmox_crypto.h new file mode 100644 index 00000000..325f1494 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_crypto.h @@ -0,0 +1,142 @@ +/** + ****************************************************************************** + * @file cmox_crypto.h + * @author MCD Application Team + * @brief Header file including all the supported cryptographic algorithms + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_CRYPTO_H +#define CMOX_CRYPTO_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @defgroup CMOX_CRYPTO Cortex-M Optimized Crypto Stack + * @{ + */ + +/** @defgroup CMOX_HASH Hash module + * @{ + */ + +#include "hash/cmox_sha1.h" +#include "hash/cmox_sha224.h" +#include "hash/cmox_sha256.h" +#include "hash/cmox_sha384.h" +#include "hash/cmox_sha512.h" +#include "hash/cmox_sha3.h" +#include "hash/cmox_sm3.h" + +/** + * @} + */ + +/** @defgroup CMOX_CIPHER Cipher module + * @{ + */ + +#include "cipher/cmox_cbc.h" +#include "cipher/cmox_ccm.h" +#include "cipher/cmox_cfb.h" +#include "cipher/cmox_chachapoly.h" +#include "cipher/cmox_ctr.h" +#include "cipher/cmox_ecb.h" +#include "cipher/cmox_gcm.h" +#include "cipher/cmox_keywrap.h" +#include "cipher/cmox_ofb.h" +#include "cipher/cmox_xts.h" + +/** + * @} + */ + +/** @defgroup CMOX_MAC MAC module + * @{ + */ + +#include "mac/cmox_cmac.h" +#include "mac/cmox_hmac.h" +#include "mac/cmox_kmac.h" + +/** + * @} + */ + +/** @defgroup CMOX_RSA RSA module + * @{ + */ +#include "rsa/cmox_rsa_pkcs1v15.h" +#include "rsa/cmox_rsa_pkcs1v22.h" +/** + * @} + */ + +/** @defgroup CMOX_ECC ECC module + * @{ + */ +#include "ecc/cmox_ecdsa.h" +#include "ecc/cmox_eddsa.h" +#include "ecc/cmox_sm2.h" +#include "ecc/cmox_ecdh.h" +/** + * @} + */ + +/** @defgroup CMOX_DRBG DRBG module + * @{ + */ +#include "drbg/cmox_ctr_drbg.h" +/** + * @} + */ + +/** @defgroup CMOX_UTILS Utils module + * @{ + */ +#include "utils/cmox_utils_compare.h" +/** + * @} + */ + +/** @defgroup CMOX_INFO Information module + * @{ + */ +#include "cmox_info.h" +/** + * @} + */ + +/** @defgroup CMOX_INIT Initialization module + * @{ + */ +#include "cmox_init.h" +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_CRYPTO_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_cta.h b/firmware/ui/dependencies/cmox/include/cmox_cta.h new file mode 100644 index 00000000..54cba399 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_cta.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * @file cmox_cta.h + * @author MCD Application Team + * @brief CTA specific features + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CTA_H +#define CMOX_CTA_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @brief Provides a label in order to move tables into RAM/CCM/TCM and being + * protected against Cache Timing Attacks (CTA) + * @note This macro uses extended GCC preprocessor features, that can be used + * with ARMCC compiler and EWARM compiler with GCC extension enabled. + * If not supported by the user toolchain configuration, it is possible + * to replace the macro with the following: + * + * \code + * #define CMOX_CTA_RESISTANT _Pragma("location=\"CMOX_CTA_PROTECTED_DATA\"") + * \endcode + */ +#define CMOX_CTA_RESISTANT __attribute__((section("CMOX_CTA_PROTECTED_DATA"))) + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CTA_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_default_config.h b/firmware/ui/dependencies/cmox/include/cmox_default_config.h new file mode 100644 index 00000000..c07e3d07 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_default_config.h @@ -0,0 +1,363 @@ +/** + ****************************************************************************** + * @file cmox_default_config.h + * @author MCD Application Team + * @brief Header file for default configuration of some algorithms + * @note It is possible to replace this header file with a custom one with + * desired configuration. In this case it must be set the macro + * CMOX_DEFAULT_FILE with the name of the custom file. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_DEFAULT_CONFIG_H +#define CMOX_DEFAULT_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_CRYPTO + * @{ + */ + +/** + * @defgroup CMOX_DEFAULT CMOX default configurations + * @{ + */ + +/** + * @defgroup CMOX_AES_DEFAULT Default AES configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of AES + */ +#define CMOX_AES_FAST 0x01U + +/** + * @brief Flag indicating the small implementation of AES + */ +#define CMOX_AES_SMALL 0x02U + +/** + * @brief Flag indicating the default implementation of AES + * @note Value can be + * - @ref CMOX_AES_SMALL + * - @ref CMOX_AES_FAST + */ +#define CMOX_AES_IMPLEMENTATION CMOX_AES_FAST + +/** + * @} + */ + +/** + * @defgroup CMOX_GCM_DEFAULT Default GCM configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of GCM + */ +#define CMOX_GCM_FAST 0x0AU + +/** + * @brief Flag indicating the small implementation of GCM + */ +#define CMOX_GCM_SMALL 0x0BU + +/** + * @brief Flag indicating the default implementation of GCM + * @note Value can be + * - @ref CMOX_GCM_SMALL + * - @ref CMOX_GCM_FAST + */ +#define CMOX_GCM_IMPLEMENTATION CMOX_GCM_FAST + +/** + * @} + */ + +/** + * @defgroup CMOX_MATH_DEFAULT Default Math customizations + * @{ + */ + +/** + * @brief Flag indicating the default implementation for RSA low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_RSA_MATH_FUNCS CMOX_MATH_FUNCS_FAST + +/** + * @brief Flag indicating the default implementation for ECC 256 bits curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * - @ref CMOX_MATH_FUNCS_SUPERFAST256 + */ +#define CMOX_ECC256_MATH_FUNCS CMOX_MATH_FUNCS_SUPERFAST256 + +/** + * @brief Flag indicating the default implementation for ECC 128 bits multiple curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_ECC128MULT_MATH_FUNCS CMOX_MATH_FUNCS_FAST + +/** + * @brief Flag indicating the default implementation for ECC curves not defined by the above + * low level mathematical functions + * @note Value can be + * * for Cortex-M0/Cortex-M0+ devices + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * * Others + * - @ref CMOX_MATH_FUNCS_SMALL + */ +#if defined(__TARGET_ARCH_6M) +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_FAST +#else /* __TARGET_ARCH_6M */ +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_SMALL +#endif /* __TARGET_ARCH_6M */ + +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_DEFAULT Default ECC customizations + * @{ + */ + +/** + * @brief Flag indicating the default implementation for EDWARDS Ed25519 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED25519_OPT_LOWMEM + * - @ref CMOX_ECC_ED25519_HIGHMEM + * - @ref CMOX_ECC_ED25519_OPT_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED25519 CMOX_ECC_ED25519_OPT_HIGHMEM +/** + * @brief Flag indicating the default implementation for EDWARDS Ed448 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED448_LOWMEM + * - @ref CMOX_ECC_ED448_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED448 CMOX_ECC_ED448_HIGHMEM + +/** + * @brief Flag indicating the default implementation for NIST-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP224R1_LOWMEM + * - @ref CMOX_ECC_SECP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP224R1 CMOX_ECC_SECP224R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for NIST-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256R1_LOWMEM + * - @ref CMOX_ECC_SECP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256R1 CMOX_ECC_SECP256R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for NIST-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP384R1_LOWMEM + * - @ref CMOX_ECC_SECP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP384R1 CMOX_ECC_SECP384R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for NIST-R P-521 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP521R1_LOWMEM + * - @ref CMOX_ECC_SECP521R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP521R1 CMOX_ECC_SECP521R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for NIST-K P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256K1_LOWMEM + * - @ref CMOX_ECC_SECP256K1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256K1 CMOX_ECC_SECP256K1_HIGHMEM + +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160R1_LOWMEM + * - @ref CMOX_ECC_BPP160R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160R1 CMOX_ECC_BPP160R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192R1_LOWMEM + * - @ref CMOX_ECC_BPP192R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192R1 CMOX_ECC_BPP192R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224R1_LOWMEM + * - @ref CMOX_ECC_BPP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224R1 CMOX_ECC_BPP224R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256R1_LOWMEM + * - @ref CMOX_ECC_BPP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256R1 CMOX_ECC_BPP256R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320R1_LOWMEM + * - @ref CMOX_ECC_BPP320R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320R1 CMOX_ECC_BPP320R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384R1_LOWMEM + * - @ref CMOX_ECC_BPP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384R1 CMOX_ECC_BPP384R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-R P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512R1_LOWMEM + * - @ref CMOX_ECC_BPP512R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512R1 CMOX_ECC_BPP512R1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160T1_LOWMEM + * - @ref CMOX_ECC_BPP160T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160T1 CMOX_ECC_BPP160T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192T1_LOWMEM + * - @ref CMOX_ECC_BPP192T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192T1 CMOX_ECC_BPP192T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224T1_LOWMEM + * - @ref CMOX_ECC_BPP224T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224T1 CMOX_ECC_BPP224T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256T1_LOWMEM + * - @ref CMOX_ECC_BPP256T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256T1 CMOX_ECC_BPP256T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320T1_LOWMEM + * - @ref CMOX_ECC_BPP320T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320T1 CMOX_ECC_BPP320T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384T1_LOWMEM + * - @ref CMOX_ECC_BPP384T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384T1 CMOX_ECC_BPP384T1_HIGHMEM +/** + * @brief Flag indicating the default implementation for BRAINPOOL-T P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512T1_LOWMEM + * - @ref CMOX_ECC_BPP512T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512T1 CMOX_ECC_BPP512T1_HIGHMEM + +/** + * @brief Flag indicating the default implementation for ANSSI P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_FRP256V1_LOWMEM + * - @ref CMOX_ECC_FRP256V1_HIGHMEM + */ +#define CMOX_ECC_CURVE_FRP256V1 CMOX_ECC_FRP256V1_HIGHMEM + +/** + * @brief Flag indicating the default implementation for OSCCA 256 bit ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2_LOWMEM + * - @ref CMOX_ECC_SM2_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2 CMOX_ECC_SM2_HIGHMEM + +/** + * @brief Flag indicating the default implementation for OSCCA 256 bit test ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2TEST_LOWMEM + * - @ref CMOX_ECC_SM2TEST_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2TEST CMOX_ECC_SM2TEST_HIGHMEM + +/** + * @} + */ + +/** + * @defgroup CMOX_RSA_DEFAULT Default RSA customizations + * @{ + */ + +/** + * @brief Flag indicating the default private modular exponentiation implementation + * @note Value can be + * - @ref CMOX_MODEXP_PRIVATE_LOWMEM + * - @ref CMOX_MODEXP_PRIVATE_MIDMEM + * - @ref CMOX_MODEXP_PRIVATE_HIGHMEM + */ +#define CMOX_MODEXP_PRIVATE CMOX_MODEXP_PRIVATE_HIGHMEM + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_DEFAULT_CONFIG_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_default_defs.h b/firmware/ui/dependencies/cmox/include/cmox_default_defs.h new file mode 100644 index 00000000..3f083f4e --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_default_defs.h @@ -0,0 +1,551 @@ +/** + ******************************************************************************* + * @file cmox_default_defs.h + * @author MCD Application Team + * @brief Header file that defines the macros for default algorithms + * optimizations + * @note Do not modify the content of this file for changing the default + * algorithm optimizations. Instead, modify the content of + * cmox_default_config.h or use a custom header file with desired + * configuration. In this case it must be set the macro + * CMOX_DEFAULT_FILE with the name of the custom file. + ******************************************************************************* + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ******************************************************************************* + */ + +#ifndef CMOX_DEFAULT_DEFS_H +#define CMOX_DEFAULT_DEFS_H + + +#if !defined(CMOX_DEFAULT_FILE) +#include "cmox_default_config.h" +#else +#include CMOX_DEFAULT_FILE +#endif /* CMOX_DEFAULT_FILE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @defgroup CMOX_DEFAULT_MACROS Default algorithms optimizations + * @{ + */ + +/** @defgroup CMOX_DEFAULT_IMPL Default implementations + * @{ + */ + +#if (CMOX_AES_IMPLEMENTATION == CMOX_AES_FAST) + +/** + * @brief Implementation of CBC Encryption using AES + */ +#define CMOX_AES_CBC_ENC CMOX_AESFAST_CBC_ENC + +/** + * @brief Implementation of CBC Decryption using AES + */ +#define CMOX_AES_CBC_DEC CMOX_AESFAST_CBC_DEC + +/** + * @brief Implementation of CCM Encryption using AES + */ +#define CMOX_AES_CCM_ENC CMOX_AESFAST_CCM_ENC + +/** + * @brief Implementation of CCM Decryption using AES + */ +#define CMOX_AES_CCM_DEC CMOX_AESFAST_CCM_DEC + +/** + * @brief Implementation of CFB Encryption using AES + */ +#define CMOX_AES_CFB_ENC CMOX_AESFAST_CFB_ENC + +/** + * @brief Implementation of CFB Decryption using AES + */ +#define CMOX_AES_CFB_DEC CMOX_AESFAST_CFB_DEC + +/** + * @brief Implementation of CTR Encryption using AES + */ +#define CMOX_AES_CTR_ENC CMOX_AESFAST_CTR_ENC + +/** + * @brief Implementation of CTR Decryption using AES + */ +#define CMOX_AES_CTR_DEC CMOX_AESFAST_CTR_DEC + +/** + * @brief Implementation of ECB Encryption using AES + */ +#define CMOX_AES_ECB_ENC CMOX_AESFAST_ECB_ENC + +/** + * @brief Implementation of ECB Decryption using AES + */ +#define CMOX_AES_ECB_DEC CMOX_AESFAST_ECB_DEC + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC CMOX_AESFAST_GCMFAST_ENC + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC CMOX_AESFAST_GCMFAST_DEC + + +#else /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL */ + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC CMOX_AESFAST_GCMSMALL_ENC + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC CMOX_AESFAST_GCMSMALL_DEC + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @brief Implementation of KEYWRAP Encryption using AES + */ +#define CMOX_AES_KEYWRAP_ENC CMOX_AESFAST_KEYWRAP_ENC + +/** + * @brief Implementation of KEYWRAP Decryption using AES + */ +#define CMOX_AES_KEYWRAP_DEC CMOX_AESFAST_KEYWRAP_DEC + +/** + * @brief Implementation of OFB Encryption using AES + */ +#define CMOX_AES_OFB_ENC CMOX_AESFAST_OFB_ENC + +/** + * @brief Implementation of OFB Decryption using AES + */ +#define CMOX_AES_OFB_DEC CMOX_AESFAST_OFB_DEC + +/** + * @brief Implementation of XTS Encryption using AES + */ +#define CMOX_AES_XTS_ENC CMOX_AESFAST_XTS_ENC + +/** + * @brief Implementation of XTS Decryption using AES + */ +#define CMOX_AES_XTS_DEC CMOX_AESFAST_XTS_DEC + +/** + * @brief Implementation of CTR-DRBG Encryption using AES128 with derivation + * function and no prediction resistance + */ +#define CMOX_CTR_DRBG_AES128 CMOX_CTR_DRBG_AES128_FAST + +/** + * @brief Implementation of CTR-DRBG Encryption using AES256 with derivation + * function and no prediction resistance + */ +#define CMOX_CTR_DRBG_AES256 CMOX_CTR_DRBG_AES256_FAST + +/** + * @brief Implementation of AES-CMAC + */ +#define CMOX_CMAC_AES CMOX_CMAC_AESFAST + +#else /* CMOX_AES_IMPLEMENTATION == CMOX_AES_SMALL */ + +/** + * @brief Implementation of CBC Encryption using AES + */ +#define CMOX_AES_CBC_ENC CMOX_AESSMALL_CBC_ENC + +/** + * @brief Implementation of CBC Decryption using AES + */ +#define CMOX_AES_CBC_DEC CMOX_AESSMALL_CBC_DEC + +/** + * @brief Implementation of CCM Encryption using AES + */ +#define CMOX_AES_CCM_ENC CMOX_AESSMALL_CCM_ENC + +/** + * @brief Implementation of CCM Decryption using AES + */ +#define CMOX_AES_CCM_DEC CMOX_AESSMALL_CCM_DEC + +/** + * @brief Implementation of CFB Encryption using AES + */ +#define CMOX_AES_CFB_ENC CMOX_AESSMALL_CFB_ENC + +/** + * @brief Implementation of CFB Decryption using AES + */ +#define CMOX_AES_CFB_DEC CMOX_AESSMALL_CFB_DEC + +/** + * @brief Implementation of CTR Encryption using AES + */ +#define CMOX_AES_CTR_ENC CMOX_AESSMALL_CTR_ENC + +/** + * @brief Implementation of CTR Decryption using AES + */ +#define CMOX_AES_CTR_DEC CMOX_AESSMALL_CTR_DEC + +/** + * @brief Implementation of ECB Encryption using AES + */ +#define CMOX_AES_ECB_ENC CMOX_AESSMALL_ECB_ENC + +/** + * @brief Implementation of ECB Decryption using AES + */ +#define CMOX_AES_ECB_DEC CMOX_AESSMALL_ECB_DEC + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC CMOX_AESSMALL_GCMFAST_ENC + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC CMOX_AESSMALL_GCMFAST_DEC + +#else /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL */ + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC CMOX_AESSMALL_GCMSMALL_ENC + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC CMOX_AESSMALL_GCMSMALL_DEC + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @brief Implementation of KEYWRAP Encryption using AES + */ +#define CMOX_AES_KEYWRAP_ENC CMOX_AESSMALL_KEYWRAP_ENC + +/** + * @brief Implementation of KEYWRAP Decryption using AES + */ +#define CMOX_AES_KEYWRAP_DEC CMOX_AESSMALL_KEYWRAP_DEC + +/** + * @brief Implementation of OFB Encryption using AES + */ +#define CMOX_AES_OFB_ENC CMOX_AESSMALL_OFB_ENC + +/** + * @brief Implementation of OFB Decryption using AES + */ +#define CMOX_AES_OFB_DEC CMOX_AESSMALL_OFB_DEC + +/** + * @brief Implementation of XTS Encryption using AES + */ +#define CMOX_AES_XTS_ENC CMOX_AESSMALL_XTS_ENC + +/** + * @brief Implementation of XTS Decryption using AES + */ +#define CMOX_AES_XTS_DEC CMOX_AESSMALL_XTS_DEC + +/** + * @brief Implementation of CTR-DRBG Encryption using AES128 with derivation + * function and no prediction resistance + */ +#define CMOX_CTR_DRBG_AES128 CMOX_CTR_DRBG_AES128_SMALL + +/** + * @brief Implementation of CTR-DRBG Encryption using AES256 with derivation + * function and no prediction resistance + */ +#define CMOX_CTR_DRBG_AES256 CMOX_CTR_DRBG_AES256_SMALL + +/* + * @brief Implementation of AES-CMAC + */ +#define CMOX_CMAC_AES CMOX_CMAC_AESSMALL + +#endif /* CMOX_AES_IMPLEMENTATION == CMOX_AES_FAST */ + +/** + * @} + */ + +/** @defgroup CMOX_DEFAULT_ALGO Default single-call algorithms + * @{ + */ + +#if (CMOX_AES_IMPLEMENTATION == CMOX_AES_FAST) + +/** + * @brief Implementation of CBC Encryption using AES + */ +#define CMOX_AES_CBC_ENC_ALGO CMOX_AESFAST_CBC_ENC_ALGO + +/** + * @brief Implementation of CBC Decryption using AES + */ +#define CMOX_AES_CBC_DEC_ALGO CMOX_AESFAST_CBC_DEC_ALGO + +/** + * @brief Implementation of CCM Encryption using AES + */ +#define CMOX_AES_CCM_ENC_ALGO CMOX_AESFAST_CCM_ENC_ALGO + +/** + * @brief Implementation of CCM Decryption using AES + */ +#define CMOX_AES_CCM_DEC_ALGO CMOX_AESFAST_CCM_DEC_ALGO + +/** + * @brief Implementation of CFB Encryption using AES + */ +#define CMOX_AES_CFB_ENC_ALGO CMOX_AESFAST_CFB_ENC_ALGO + +/** + * @brief Implementation of CFB Decryption using AES + */ +#define CMOX_AES_CFB_DEC_ALGO CMOX_AESFAST_CFB_DEC_ALG + +/** + * @brief Implementation of CTR Encryption using AES + */ +#define CMOX_AES_CTR_ENC_ALGO CMOX_AESFAST_CTR_ENC_ALGO + +/** + * @brief Implementation of CTR Decryption using AES + */ +#define CMOX_AES_CTR_DEC_ALGO CMOX_AESFAST_CTR_DEC_ALGO + +/** + * @brief Implementation of ECB Encryption using AES + */ +#define CMOX_AES_ECB_ENC_ALGO CMOX_AESFAST_ECB_ENC_ALGO + +/** + * @brief Implementation of ECB Decryption using AES + */ +#define CMOX_AES_ECB_DEC_ALGO CMOX_AESFAST_ECB_DEC_ALGO + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC_ALGO CMOX_AESFAST_GCMFAST_ENC_ALGO + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC_ALGO CMOX_AESFAST_GCMFAST_DEC_ALGO + +#else /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL */ + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC_ALGO CMOX_AESFAST_GCMSMALL_ENC_ALGO + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC_ALGO CMOX_AESFAST_GCMSMALL_DEC_ALGO + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @brief Implementation of KEYWRAP Encryption using AES + */ +#define CMOX_AES_KEYWRAP_ENC_ALGO CMOX_AESFAST_KEYWRAP_ENC_ALGO + +/** + * @brief Implementation of KEYWRAP Decryption using AES + */ +#define CMOX_AES_KEYWRAP_DEC_ALGO CMOX_AESFAST_KEYWRAP_DEC_ALGO + +/** + * @brief Implementation of OFB Encryption using AES + */ +#define CMOX_AES_OFB_ENC_ALGO CMOX_AESFAST_OFB_ENC_ALGO + +/** + * @brief Implementation of OFB Decryption using AES + */ +#define CMOX_AES_OFB_DEC_ALGO CMOX_AESFAST_OFB_DEC_ALGO + +/** + * @brief Implementation of XTS Encryption using AES + */ +#define CMOX_AES_XTS_ENC_ALGO CMOX_AESFAST_XTS_ENC_ALGO + +/** + * @brief Implementation of XTS Decryption using AES + */ +#define CMOX_AES_XTS_DEC_ALGO CMOX_AESFAST_XTS_DEC_ALGO + +/** + * @brief Implementation of AES-CMAC algorithm + */ +#define CMOX_CMAC_AES_ALGO CMOX_CMAC_AESFAST_ALGO + +#else /* CMOX_AES_IMPLEMENTATION == CMOX_AES_SMALL */ + +/** + * @brief Implementation of CBC Encryption using AES + */ +#define CMOX_AES_CBC_ENC_ALGO CMOX_AESSMALL_CBC_ENC_ALGO + +/** + * @brief Implementation of CBC Decryption using AES + */ +#define CMOX_AES_CBC_DEC_ALGO CMOX_AESSMALL_CBC_DEC_ALGO + +/** + * @brief Implementation of CCM Encryption using AES + */ +#define CMOX_AES_CCM_ENC_ALGO CMOX_AESSMALL_CCM_ENC_ALGO + +/** + * @brief Implementation of CCM Decryption using AES + */ +#define CMOX_AES_CCM_DEC_ALGO CMOX_AESSMALL_CCM_DEC_ALGO + +/** + * @brief Implementation of CFB Encryption using AES + */ +#define CMOX_AES_CFB_ENC_ALGO CMOX_AESSMALL_CFB_ENC_ALGO + +/** + * @brief Implementation of CFB Decryption using AES + */ +#define CMOX_AES_CFB_DEC_ALGO CMOX_AESSMALL_CFB_DEC_ALGO + +/** + * @brief Implementation of CTR Encryption using AES + */ +#define CMOX_AES_CTR_ENC_ALGO CMOX_AESSMALL_CTR_ENC_ALGO + +/** + * @brief Implementation of CTR Decryption using AES + */ +#define CMOX_AES_CTR_DEC_ALGO CMOX_AESSMALL_CTR_DEC_ALGO + +/** + * @brief Implementation of ECB Encryption using AES + */ +#define CMOX_AES_ECB_ENC_ALGO CMOX_AESSMALL_ECB_ENC_ALGO + +/** + * @brief Implementation of ECB Decryption using AES + */ +#define CMOX_AES_ECB_DEC_ALGO CMOX_AESSMALL_ECB_DEC_ALGO + +#if (CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST) + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC_ALGO CMOX_AESSMALL_GCMFAST_ENC_ALGO + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC_ALGO CMOX_AESSMALL_GCMFAST_DEC_ALGO + +#else /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_SMALL */ + +/** + * @brief Implementation of GCM Encryption using AES + */ +#define CMOX_AES_GCM_ENC_ALGO CMOX_AESSMALL_GCMSMALL_ENC_ALGO + +/** + * @brief Implementation of GCM Decryption using AES + */ +#define CMOX_AES_GCM_DEC_ALGO CMOX_AESSMALL_GCMSMALL_DEC_ALGO + +#endif /* CMOX_GCM_IMPLEMENTATION == CMOX_GCM_FAST */ + +/** + * @brief Implementation of KEYWRAP Encryption using AES + */ +#define CMOX_AES_KEYWRAP_ENC_ALGO CMOX_AESSMALL_KEYWRAP_ENC_ALGO + +/** + * @brief Implementation of KEYWRAP Decryption using AES + */ +#define CMOX_AES_KEYWRAP_DEC_ALGO CMOX_AESSMALL_KEYWRAP_DEC_ALGO + +/** + * @brief Implementation of OFB Encryption using AES + */ +#define CMOX_AES_OFB_ENC_ALGO CMOX_AESSMALL_OFB_ENC_ALGO + +/** + * @brief Implementation of OFB Decryption using AES + */ +#define CMOX_AES_OFB_DEC_ALGO CMOX_AESSMALL_OFB_DEC_ALGO + +/** + * @brief Implementation of XTS Encryption using AES + */ +#define CMOX_AES_XTS_ENC_ALGO CMOX_AESSMALL_XTS_ENC_ALGO + +/** + * @brief Implementation of XTS Decryption using AES + */ +#define CMOX_AES_XTS_DEC_ALGO CMOX_AESSMALL_XTS_DEC_ALGO + +/** + * @brief Implementation of AES-CMAC algorithm + */ +#define CMOX_CMAC_AES_ALGO CMOX_CMAC_AESSMALL_ALGO + +#endif /* CMOX_AES_IMPLEMENTATION == CMOX_AES_FAST */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_DEFAULT_DEFS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_fast_config.h b/firmware/ui/dependencies/cmox/include/cmox_fast_config.h new file mode 100644 index 00000000..d434232d --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_fast_config.h @@ -0,0 +1,360 @@ +/** + ****************************************************************************** + * @file cmox_fast_config.h + * @author MCD Application Team + * @brief Header file for fastest configuration of some algorithms + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_FAST_CONFIG_H +#define CMOX_FAST_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_CRYPTO + * @{ + */ + +/** + * @defgroup CMOX_FAST CMOX fast configurations + * @{ + */ + +/** + * @defgroup CMOX_AES_FAST Fast AES configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of AES + */ +#define CMOX_AES_FAST 0x01U + +/** + * @brief Flag indicating the small implementation of AES + */ +#define CMOX_AES_SMALL 0x02U + +/** + * @brief Flag indicating the fast implementation of AES + * @note Value can be + * - @ref CMOX_AES_SMALL + * - @ref CMOX_AES_FAST + */ +#define CMOX_AES_IMPLEMENTATION CMOX_AES_FAST + +/** + * @} + */ + +/** + * @defgroup CMOX_GCM_FAST Fast GCM configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of GCM + */ +#define CMOX_GCM_FAST 0x0AU + +/** + * @brief Flag indicating the small implementation of GCM + */ +#define CMOX_GCM_SMALL 0x0BU + +/** + * @brief Flag indicating the fast implementation of GCM + * @note Value can be + * - @ref CMOX_GCM_SMALL + * - @ref CMOX_GCM_FAST + */ +#define CMOX_GCM_IMPLEMENTATION CMOX_GCM_FAST + +/** + * @} + */ + +/** + * @defgroup CMOX_MATH_FAST Fast Math customizations + * @{ + */ + +/** + * @brief Flag indicating the fast implementation for RSA low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_RSA_MATH_FUNCS CMOX_MATH_FUNCS_FAST + +/** + * @brief Flag indicating the fast implementation for ECC 256 bits curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * - @ref CMOX_MATH_FUNCS_SUPERFAST256 + */ +#define CMOX_ECC256_MATH_FUNCS CMOX_MATH_FUNCS_SUPERFAST256 + +/** + * @brief Flag indicating the fast implementation for ECC 128 bits multiple curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_ECC128MULT_MATH_FUNCS CMOX_MATH_FUNCS_FAST + +/** + * @brief Flag indicating the fast implementation for ECC curves not defined by the above + * low level mathematical functions + * @note Value can be + * * for Cortex-M0/Cortex-M0+ devices + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * * Others + * - @ref CMOX_MATH_FUNCS_SMALL + */ +#if defined(__TARGET_ARCH_6M) +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_FAST +#else /* __TARGET_ARCH_6M */ +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_SMALL +#endif /* __TARGET_ARCH_6M */ + +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_FAST Fast ECC customizations + * @{ + */ + +/** + * @brief Flag indicating the fast implementation for EDWARDS Ed25519 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED25519_OPT_LOWMEM + * - @ref CMOX_ECC_ED25519_HIGHMEM + * - @ref CMOX_ECC_ED25519_OPT_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED25519 CMOX_ECC_ED25519_OPT_HIGHMEM +/** + * @brief Flag indicating the fast implementation for EDWARDS Ed448 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED448_LOWMEM + * - @ref CMOX_ECC_ED448_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED448 CMOX_ECC_ED448_HIGHMEM + +/** + * @brief Flag indicating the fast implementation for NIST-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP224R1_LOWMEM + * - @ref CMOX_ECC_SECP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP224R1 CMOX_ECC_SECP224R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for NIST-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256R1_LOWMEM + * - @ref CMOX_ECC_SECP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256R1 CMOX_ECC_SECP256R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for NIST-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP384R1_LOWMEM + * - @ref CMOX_ECC_SECP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP384R1 CMOX_ECC_SECP384R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for NIST-R P-521 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP521R1_LOWMEM + * - @ref CMOX_ECC_SECP521R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP521R1 CMOX_ECC_SECP521R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for NIST-K P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256K1_LOWMEM + * - @ref CMOX_ECC_SECP256K1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256K1 CMOX_ECC_SECP256K1_HIGHMEM + +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160R1_LOWMEM + * - @ref CMOX_ECC_BPP160R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160R1 CMOX_ECC_BPP160R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192R1_LOWMEM + * - @ref CMOX_ECC_BPP192R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192R1 CMOX_ECC_BPP192R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224R1_LOWMEM + * - @ref CMOX_ECC_BPP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224R1 CMOX_ECC_BPP224R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256R1_LOWMEM + * - @ref CMOX_ECC_BPP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256R1 CMOX_ECC_BPP256R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320R1_LOWMEM + * - @ref CMOX_ECC_BPP320R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320R1 CMOX_ECC_BPP320R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384R1_LOWMEM + * - @ref CMOX_ECC_BPP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384R1 CMOX_ECC_BPP384R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-R P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512R1_LOWMEM + * - @ref CMOX_ECC_BPP512R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512R1 CMOX_ECC_BPP512R1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160T1_LOWMEM + * - @ref CMOX_ECC_BPP160T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160T1 CMOX_ECC_BPP160T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192T1_LOWMEM + * - @ref CMOX_ECC_BPP192T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192T1 CMOX_ECC_BPP192T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224T1_LOWMEM + * - @ref CMOX_ECC_BPP224T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224T1 CMOX_ECC_BPP224T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256T1_LOWMEM + * - @ref CMOX_ECC_BPP256T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256T1 CMOX_ECC_BPP256T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320T1_LOWMEM + * - @ref CMOX_ECC_BPP320T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320T1 CMOX_ECC_BPP320T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384T1_LOWMEM + * - @ref CMOX_ECC_BPP384T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384T1 CMOX_ECC_BPP384T1_HIGHMEM +/** + * @brief Flag indicating the fast implementation for BRAINPOOL-T P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512T1_LOWMEM + * - @ref CMOX_ECC_BPP512T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512T1 CMOX_ECC_BPP512T1_HIGHMEM + +/** + * @brief Flag indicating the fast implementation for ANSSI P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_FRP256V1_LOWMEM + * - @ref CMOX_ECC_FRP256V1_HIGHMEM + */ +#define CMOX_ECC_CURVE_FRP256V1 CMOX_ECC_FRP256V1_HIGHMEM + +/** + * @brief Flag indicating the fast implementation for OSCCA 256 bit ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2_LOWMEM + * - @ref CMOX_ECC_SM2_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2 CMOX_ECC_SM2_HIGHMEM + +/** + * @brief Flag indicating the fast implementation for OSCCA 256 bit test ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2TEST_LOWMEM + * - @ref CMOX_ECC_SM2TEST_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2TEST CMOX_ECC_SM2TEST_HIGHMEM + +/** + * @} + */ + +/** + * @defgroup CMOX_RSA_FAST Fast RSA customizations + * @{ + */ + +/** + * @brief Flag indicating the fast private modular exponentiation implementation + * @note Value can be + * - @ref CMOX_MODEXP_PRIVATE_LOWMEM + * - @ref CMOX_MODEXP_PRIVATE_MIDMEM + * - @ref CMOX_MODEXP_PRIVATE_HIGHMEM + */ +#define CMOX_MODEXP_PRIVATE CMOX_MODEXP_PRIVATE_HIGHMEM + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_FAST_CONFIG_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_info.h b/firmware/ui/dependencies/cmox/include/cmox_info.h new file mode 100644 index 00000000..f87d8639 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_info.h @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * @file cmox_info.h + * @author MCD Application Team + * @brief This file exports symbols needed to use information module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_INFO_H +#define CMOX_INFO_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** @addtogroup CMOX_CRYPTO + * @{ + */ + +/** @addtogroup CMOX_INFO Information module + * @{ + */ + +/** + * @brief Structure to store information + */ +typedef struct +{ + uint32_t version; /*!< Library version */ + uint32_t build[7]; /*!< Build info */ +} cmox_info_st; + +/** + * @brief Get library information + * @param pInfo Library information + * @retval None + */ +void cmox_getInfos(cmox_info_st *pInfo); + +/** + * @} + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_INFO_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_init.h b/firmware/ui/dependencies/cmox/include/cmox_init.h new file mode 100644 index 00000000..da9fce99 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_init.h @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file cmox_init.h + * @author MCD Application Team + * @brief This file exports symbols needed to use init module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_INIT_H +#define CMOX_INIT_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** @addtogroup CMOX_CRYPTO + * @{ + */ + +/** @addtogroup CMOX_INIT Initialization module + * @{ + */ + +/** + * @brief Initialization target type + */ +typedef uint32_t cmox_init_target_t; + +#define CMOX_INIT_TARGET_AUTO ((cmox_init_target_t)0x00000000) /*!< Let the cryptographic library auto-detect running STM32 target Series */ +#define CMOX_INIT_TARGET_F0 ((cmox_init_target_t)0x46300000) /*!< Select a STM32F0 Series target */ +#define CMOX_INIT_TARGET_F1 ((cmox_init_target_t)0x46310000) /*!< Select a STM32F1 Series target */ +#define CMOX_INIT_TARGET_F2 ((cmox_init_target_t)0x46320000) /*!< Select a STM32F2 Series target */ +#define CMOX_INIT_TARGET_F3 ((cmox_init_target_t)0x46330000) /*!< Select a STM32F3 Series target */ +#define CMOX_INIT_TARGET_F4 ((cmox_init_target_t)0x46340000) /*!< Select a STM32F4 Series target */ +#define CMOX_INIT_TARGET_F7 ((cmox_init_target_t)0x46370000) /*!< Select a STM32F7 Series target */ +#define CMOX_INIT_TARGET_H5 ((cmox_init_target_t)0x48350000) /*!< Select a STM32H5 Series target */ +#define CMOX_INIT_TARGET_H7 ((cmox_init_target_t)0x48370000) /*!< Select a STM32H72x/STM32H73x/STM32H74x/STM32H75x Series target */ +#define CMOX_INIT_TARGET_H7AB ((cmox_init_target_t)0x48378000) /*!< Select a STM32H7Ax/STM32H7Bx Series target */ +#define CMOX_INIT_TARGET_H7RS ((cmox_init_target_t)0x48370000) /*!< Select a STM32H7Rx/STM32H7Sx Series target */ +#define CMOX_INIT_TARGET_G0 ((cmox_init_target_t)0x47300000) /*!< Select a STM32G0 Series target */ +#define CMOX_INIT_TARGET_G4 ((cmox_init_target_t)0x47340000) /*!< Select a STM32G4 Series target */ +#define CMOX_INIT_TARGET_L0 ((cmox_init_target_t)0x4C300000) /*!< Select a STM32L0 Series target */ +#define CMOX_INIT_TARGET_L1 ((cmox_init_target_t)0x4C310000) /*!< Select a STM32L1 Series target */ +#define CMOX_INIT_TARGET_L4 ((cmox_init_target_t)0x4C340000) /*!< Select a STM32L4/4+ Series target */ +#define CMOX_INIT_TARGET_L5 ((cmox_init_target_t)0x4C350000) /*!< Select a STM32L5 Series target */ +#define CMOX_INIT_TARGET_U0 ((cmox_init_target_t)0x55300000) /*!< Select a STM32U0 Series target */ +#define CMOX_INIT_TARGET_WB ((cmox_init_target_t)0x57420000) /*!< Select a STM32WB Series target */ +#define CMOX_INIT_TARGET_WBA ((cmox_init_target_t)0x57424100) /*!< Select a STM32WBA Series target */ +#define CMOX_INIT_TARGET_WL ((cmox_init_target_t)0x574C0000) /*!< Select a STM32WL Series target */ + +/** @brief Initialization structure + */ +typedef struct +{ + cmox_init_target_t target; /*!< User target specification */ + void *pArg; /*!< User defined parameter that is transmitted to Low Level services */ +} cmox_init_arg_t; + +/** + * @brief Return value type for Initialization module + */ +typedef uint32_t cmox_init_retval_t; /*!< Initialization return value type */ + +#define CMOX_INIT_SUCCESS ((cmox_init_retval_t)0x00000000) /*!< Init operation successfully performed */ +#define CMOX_INIT_FAIL ((cmox_init_retval_t)0x00000001) /*!< Init operation failed */ + +/** + * @brief Initialize CMOX library + * @param pInitArg Initialization parameter see @ref cmox_init_arg_t + * @note pInitArg can be set to NULL: is equivalent to + * pInitArg->target = CMOX_INIT_TARGET_AUTO + * pInitArg->pArg = NULL + * @retval Initialization status: @ref CMOX_INIT_SUCCESS / @ref CMOX_INIT_FAIL + */ +cmox_init_retval_t cmox_initialize(cmox_init_arg_t *pInitArg); + +/** + * @brief Finalize CMOX library + * @param pArg User defined parameter that is transmitted to Low Level services + * @retval Finalization status: @ref CMOX_INIT_SUCCESS / @ref CMOX_INIT_FAIL + */ +cmox_init_retval_t cmox_finalize(void *pArg); + +/** + * @} + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_INIT_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/cmox_low_level.h b/firmware/ui/dependencies/cmox/include/cmox_low_level.h new file mode 100644 index 00000000..4a689317 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_low_level.h @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * @file cmox_low_level.h + * @brief This file exports symbols needed to use low level module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_LOW_LEVEL_H +#define CMOX_LOW_LEVEL_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** @addtogroup CMOX_CRYPTO + * @{ + */ + +/** @addtogroup CMOX_INIT Initialization module + * @{ + */ + +/** + * @brief CMOX library low level initialization + * @note Implements low level initialization required by cryptographic + * library to operate properly + * @param pArg User defined parameter that is transmitted from Initialize service + * @retval Initialization status: @ref CMOX_INIT_SUCCESS / @ref CMOX_INIT_FAIL + */ +cmox_init_retval_t cmox_ll_init(void *pArg); + +/** + * @brief CMOX library low level de-initialization + * @param pArg User defined parameter that is transmitted from Finalize service + * @retval De-initialization status: @ref CMOX_INIT_SUCCESS / @ref CMOX_INIT_FAIL + */ +cmox_init_retval_t cmox_ll_deInit(void *pArg); + +/** + * @} + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_LOW_LEVEL_H */ diff --git a/firmware/ui/dependencies/cmox/include/cmox_small_config.h b/firmware/ui/dependencies/cmox/include/cmox_small_config.h new file mode 100644 index 00000000..f8a1c0ab --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/cmox_small_config.h @@ -0,0 +1,360 @@ +/** + ****************************************************************************** + * @file cmox_small_config.h + * @author MCD Application Team + * @brief Header file for smallest configuration of some algorithms + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SMALL_CONFIG_H +#define CMOX_SMALL_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_CRYPTO + * @{ + */ + +/** + * @defgroup CMOX_SMALL CMOX small configurations + * @{ + */ + +/** + * @defgroup CMOX_AES_SMALL Small AES configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of AES + */ +#define CMOX_AES_FAST 0x01U + +/** + * @brief Flag indicating the small implementation of AES + */ +#define CMOX_AES_SMALL 0x02U + +/** + * @brief Flag indicating the small implementation of AES + * @note Value can be + * - @ref CMOX_AES_SMALL + * - @ref CMOX_AES_FAST + */ +#define CMOX_AES_IMPLEMENTATION CMOX_AES_SMALL + +/** + * @} + */ + +/** + * @defgroup CMOX_GCM_SMALL Small GCM configuration + * @{ + */ + +/** + * @brief Flag indicating the fast implementation of GCM + */ +#define CMOX_GCM_FAST 0x0AU + +/** + * @brief Flag indicating the small implementation of GCM + */ +#define CMOX_GCM_SMALL 0x0BU + +/** + * @brief Flag indicating the small implementation of GCM + * @note Value can be + * - @ref CMOX_GCM_SMALL + * - @ref CMOX_GCM_FAST + */ +#define CMOX_GCM_IMPLEMENTATION CMOX_GCM_SMALL + +/** + * @} + */ + +/** + * @defgroup CMOX_MATH_SMALL Small Math customizations + * @{ + */ + +/** + * @brief Flag indicating the small implementation for RSA low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_RSA_MATH_FUNCS CMOX_MATH_FUNCS_SMALL + +/** + * @brief Flag indicating the small implementation for ECC 256 bits curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * - @ref CMOX_MATH_FUNCS_SUPERFAST256 + */ +#define CMOX_ECC256_MATH_FUNCS CMOX_MATH_FUNCS_SMALL + +/** + * @brief Flag indicating the small implementation for ECC 128 bits multiple curves + * low level mathematical functions + * @note Value can be + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + */ +#define CMOX_ECC128MULT_MATH_FUNCS CMOX_MATH_FUNCS_SMALL + +/** + * @brief Flag indicating the small implementation for ECC curves not defined by the above + * low level mathematical functions + * @note Value can be + * * for Cortex-M0/Cortex-M0+ devices + * - @ref CMOX_MATH_FUNCS_SMALL + * - @ref CMOX_MATH_FUNCS_FAST + * * Others + * - @ref CMOX_MATH_FUNCS_SMALL + */ +#if defined(__TARGET_ARCH_6M) +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_SMALL +#else /* __TARGET_ARCH_6M */ +#define CMOX_ECC_MATH_FUNCS CMOX_MATH_FUNCS_SMALL +#endif /* __TARGET_ARCH_6M */ + +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_SMALL Small ECC customizations + * @{ + */ + +/** + * @brief Flag indicating the small implementation for EDWARDS Ed25519 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED25519_OPT_LOWMEM + * - @ref CMOX_ECC_ED25519_HIGHMEM + * - @ref CMOX_ECC_ED25519_OPT_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED25519 CMOX_ECC_ED25519_OPT_LOWMEM +/** + * @brief Flag indicating the small implementation for EDWARDS Ed448 ECC curves + * @note Value can be + * - @ref CMOX_ECC_ED448_LOWMEM + * - @ref CMOX_ECC_ED448_HIGHMEM + */ +#define CMOX_ECC_CURVE_ED448 CMOX_ECC_ED448_LOWMEM + +/** + * @brief Flag indicating the small implementation for NIST-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP224R1_LOWMEM + * - @ref CMOX_ECC_SECP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP224R1 CMOX_ECC_SECP224R1_LOWMEM +/** + * @brief Flag indicating the small implementation for NIST-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256R1_LOWMEM + * - @ref CMOX_ECC_SECP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256R1 CMOX_ECC_SECP256R1_LOWMEM +/** + * @brief Flag indicating the small implementation for NIST-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP384R1_LOWMEM + * - @ref CMOX_ECC_SECP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP384R1 CMOX_ECC_SECP384R1_LOWMEM +/** + * @brief Flag indicating the small implementation for NIST-R P-521 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP521R1_LOWMEM + * - @ref CMOX_ECC_SECP521R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP521R1 CMOX_ECC_SECP521R1_LOWMEM +/** + * @brief Flag indicating the small implementation for NIST-K P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_SECP256K1_LOWMEM + * - @ref CMOX_ECC_SECP256K1_HIGHMEM + */ +#define CMOX_ECC_CURVE_SECP256K1 CMOX_ECC_SECP256K1_LOWMEM + +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160R1_LOWMEM + * - @ref CMOX_ECC_BPP160R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160R1 CMOX_ECC_BPP160R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192R1_LOWMEM + * - @ref CMOX_ECC_BPP192R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192R1 CMOX_ECC_BPP192R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224R1_LOWMEM + * - @ref CMOX_ECC_BPP224R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224R1 CMOX_ECC_BPP224R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256R1_LOWMEM + * - @ref CMOX_ECC_BPP256R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256R1 CMOX_ECC_BPP256R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320R1_LOWMEM + * - @ref CMOX_ECC_BPP320R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320R1 CMOX_ECC_BPP320R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384R1_LOWMEM + * - @ref CMOX_ECC_BPP384R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384R1 CMOX_ECC_BPP384R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-R P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512R1_LOWMEM + * - @ref CMOX_ECC_BPP512R1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512R1 CMOX_ECC_BPP512R1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-160 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP160T1_LOWMEM + * - @ref CMOX_ECC_BPP160T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP160T1 CMOX_ECC_BPP160T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-192 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP192T1_LOWMEM + * - @ref CMOX_ECC_BPP192T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP192T1 CMOX_ECC_BPP192T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-224 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP224T1_LOWMEM + * - @ref CMOX_ECC_BPP224T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP224T1 CMOX_ECC_BPP224T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP256T1_LOWMEM + * - @ref CMOX_ECC_BPP256T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP256T1 CMOX_ECC_BPP256T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-320 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP320T1_LOWMEM + * - @ref CMOX_ECC_BPP320T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP320T1 CMOX_ECC_BPP320T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-384 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP384T1_LOWMEM + * - @ref CMOX_ECC_BPP384T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP384T1 CMOX_ECC_BPP384T1_LOWMEM +/** + * @brief Flag indicating the small implementation for BRAINPOOL-T P-512 ECC curves + * @note Value can be + * - @ref CMOX_ECC_BPP512T1_LOWMEM + * - @ref CMOX_ECC_BPP512T1_HIGHMEM + */ +#define CMOX_ECC_CURVE_BPP512T1 CMOX_ECC_BPP512T1_LOWMEM + +/** + * @brief Flag indicating the small implementation for ANSSI P-256 ECC curves + * @note Value can be + * - @ref CMOX_ECC_FRP256V1_LOWMEM + * - @ref CMOX_ECC_FRP256V1_HIGHMEM + */ +#define CMOX_ECC_CURVE_FRP256V1 CMOX_ECC_FRP256V1_LOWMEM + +/** + * @brief Flag indicating the small implementation for OSCCA 256 bit ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2_LOWMEM + * - @ref CMOX_ECC_SM2_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2 CMOX_ECC_SM2_LOWMEM + +/** + * @brief Flag indicating the small implementation for OSCCA 256 bit test ECC curves + * @note Value can be + * - @ref CMOX_ECC_SM2TEST_LOWMEM + * - @ref CMOX_ECC_SM2TEST_HIGHMEM + */ +#define CMOX_ECC_CURVE_SM2TEST CMOX_ECC_SM2TEST_LOWMEM + +/** + * @} + */ + +/** + * @defgroup CMOX_RSA_SMALL Small RSA customizations + * @{ + */ + +/** + * @brief Flag indicating the small private modular exponentiation implementation + * @note Value can be + * - @ref CMOX_MODEXP_PRIVATE_LOWMEM + * - @ref CMOX_MODEXP_PRIVATE_MIDMEM + * - @ref CMOX_MODEXP_PRIVATE_HIGHMEM + */ +#define CMOX_MODEXP_PRIVATE CMOX_MODEXP_PRIVATE_LOWMEM + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SMALL_CONFIG_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/drbg/cmox_ctr_drbg.h b/firmware/ui/dependencies/cmox/include/drbg/cmox_ctr_drbg.h new file mode 100644 index 00000000..85b3d65c --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/drbg/cmox_ctr_drbg.h @@ -0,0 +1,180 @@ +/** + ****************************************************************************** + * @file cmox_ctr_drbg.h + * @author MCD Application Team + * @brief Header file for the CTR-DRBG module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CTR_DRBG_H +#define CMOX_CTR_DRBG_H + +/* Include files -------------------------------------------------------------*/ +#include "cmox_drbg.h" +#include "cipher/cmox_blockcipher.h" + +#include "cipher/cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_DRBG + * @{ + */ + +/** @defgroup CMOX_CTR_DRBG CTR-DRBG + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CTR_DRBG_PUBLIC_TYPES CTR-DRBG public types + * @{ + */ + +/** + * @brief CTR-DRBG mode implementation + * + * This type specifies the used block cipher for the CTR-DRBG construct. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_ctr_drbg_implStruct_st *cmox_ctr_drbg_impl_t; + +/** + * @brief Structure to store the state/context of the CTR_DRBG + */ +typedef struct +{ + uint32_t value[4]; /*!< V value, a 128 bit value */ + uint32_t key[8]; /*!< K value, contains the block cipher key */ + uint64_t reseed_counter; /*!< Reseed counter 32-bit of data */ +} cmox_ctr_drbg_state_t; + +/** + * @brief CTR-DRBG handle structure definition + */ +typedef struct +{ + cmox_drbg_handle_t super; /*!< General DRBG handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + cmox_blockcipher_handle_t blockCipher_df; /*!< Block cipher handle for derivation function */ + cmox_ctr_drbg_state_t state; /*!< DRBG state */ + uint32_t flag; /*!< DRBG flag */ + cmox_cipher_keyLen_t keyLen; /*!< Length in bytes of the block cipher key */ + size_t expKeyLen; /*!< Length in bytes of the expanded key */ + size_t minEntropyLen; /*!< Minimum entropy length */ + size_t maxBytesPerRequest; /*!< Maximum number of random bytes per request */ + const uint32_t *exp_aes_0_key; /*!< Pointer to the expanded key */ + const uint32_t *exp_bcc_aes_key; /*!< Pointer to the expanded key for BCC */ +} cmox_ctr_drbg_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CTR_DRBG_PUBLIC_CONSTANTS CTR-DRBG public constants + * @{ + */ + +/** @defgroup CMOX_CTR_DRBG_IMPL CTR-DRBG implementations + * @{ + */ + +/** + * @brief Implementation of CTR-DRBG using AES-128 (small implementation) + * (Defined internally) + */ +extern const cmox_ctr_drbg_impl_t CMOX_CTR_DRBG_AES128_SMALL; + +/** + * @brief Implementation of CTR-DRBG using AES-128 (fast implementation) + * (Defined internally) + */ +extern const cmox_ctr_drbg_impl_t CMOX_CTR_DRBG_AES128_FAST; + +/** + * @brief Implementation of CTR-DRBG using AES-256 (small implementation) + * (Defined internally) + */ +extern const cmox_ctr_drbg_impl_t CMOX_CTR_DRBG_AES256_SMALL; + +/** + * @brief Implementation of CTR-DRBG using AES-256 (fast implementation) + * (Defined internally) + */ +extern const cmox_ctr_drbg_impl_t CMOX_CTR_DRBG_AES256_FAST; + +/** + * @} + */ + +/** + * @} + */ + +/* Public method prototypes --------------------------------------------------*/ + +/** @defgroup CMOX_CTR_DRBG_PUBLIC_METHODS CTR-DRBG public method prototypes + * @{ + */ + +/** + * @brief CTR-DRBG constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CTR-DRBG algorithm + * @param P_pThis Pointer to the CTR-DRBG handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_CTR_DRBG_AES128_FAST + * @arg CMOX_CTR_DRBG_AES192_FAST + * @arg CMOX_CTR_DRBG_AES256_FAST + * @arg CMOX_CTR_DRBG_AES128_SMALL + * @arg CMOX_CTR_DRBG_AES192_SMALL + * @arg CMOX_CTR_DRBG_AES256_SMALL + * @return cmox_drbg_handle_t* Pointer to a general DRBG handle. This will + * be used by the general purpose cipher functions in order to + * perform the algorithm + */ +cmox_drbg_handle_t *cmox_ctr_drbg_construct(cmox_ctr_drbg_handle_t *P_pThis, + cmox_ctr_drbg_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CTR_DRBG_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg.h b/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg.h new file mode 100644 index 00000000..007d96c9 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg.h @@ -0,0 +1,147 @@ +/** + ****************************************************************************** + * @file cmox_drbg.h + * @author MCD Application Team + * @brief Header file for the DRBG module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_DRBG_H +#define CMOX_DRBG_H + +/* Include files -------------------------------------------------------------*/ +#include +#include +#include "cmox_drbg_retvals.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_DRBG + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_DRBG_PUBLIC_TYPES DRBG module public types + * @{ + */ + +/** + * @brief DRBG Virtual Table + * + * This type specifies a pointer to the virtual table containing the methods + * for a particular algorithm (currently the only supported is CTR-DRBG) + */ +typedef const struct cmox_drbg_vtableStruct_st *cmox_drbg_vtable_t; + +/** + * @brief DRBG handle structure definition + */ +typedef struct +{ + cmox_drbg_vtable_t table; /*!< DRBG virtual table */ +} cmox_drbg_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_DRBG_PUBLIC_METHODS DRBG public method prototypes + * @{ + */ + +/** + * @brief Cleanup the DRBG handle + * + * @param P_pThis DRBG handle to cleanup + * @return cmox_drbg_retval_t DRBG return value + */ +cmox_drbg_retval_t cmox_drbg_cleanup(cmox_drbg_handle_t *P_pThis); + +/** + * @brief Initialize the DRBG engine + * + * @param P_pThis DRBG handler to initialize + * @param P_pEntropy Buffer of bytes containing the entropy bytes + * @param P_entropyLen Number of entropy bytes that will be used to seed the DRBG + * @param P_pPersonalString Buffer of bytes containing the personalization string + * @param P_personalStringLen Size in bytes of the personalization string + * @param P_pNonce Buffer of bytes containing nonce data + * @param P_nonceLen Size in bytes of the nonce + * @return cmox_drbg_retval_t DRBG return value + */ +cmox_drbg_retval_t cmox_drbg_init(cmox_drbg_handle_t *P_pThis, + const uint8_t *P_pEntropy, + size_t P_entropyLen, + const uint8_t *P_pPersonalString, + size_t P_personalStringLen, + const uint8_t *P_pNonce, + size_t P_nonceLen); + +/** + * @brief Reseed the DRBG + * + * @param P_pThis DRBG handler to initialize + * @param P_pEntropy Buffer of bytes containing the entropy bytes + * @param P_entropyLen Number of entropy bytes that will be used to seed the DRBG + * @param P_pAdditionalInput Buffer of bytes containing additional input + * @param P_additionalInputLen Size in bytes of the additional input + * @return cmox_drbg_retval_t DRBG return value + */ +cmox_drbg_retval_t cmox_drbg_reseed(cmox_drbg_handle_t *P_pThis, + const uint8_t *P_pEntropy, + size_t P_entropyLen, + const uint8_t *P_pAdditionalInput, + size_t P_additionalInputLen); + +/** + * @brief Generation of pseudorandom octets to a buffer + * + * @param P_pThis DRBG handler to initialize + * @param P_pAdditionalInput Buffer of bytes containing additional input + * @param P_additionalInputLen Size in bytes of the additional input + * @param P_pOutput Buffer of bytes where the generated bytes will be stored + * @param P_desiredOutputLen Desired number of random bytes to produce + * @return cmox_drbg_retval_t DRBG return value + */ +cmox_drbg_retval_t cmox_drbg_generate(cmox_drbg_handle_t *P_pThis, + const uint8_t *P_pAdditionalInput, + size_t P_additionalInputLen, + uint8_t *P_pOutput, + size_t P_desiredOutputLen); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_DRBG_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg_retvals.h b/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg_retvals.h new file mode 100644 index 00000000..16f5d6c0 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/drbg/cmox_drbg_retvals.h @@ -0,0 +1,119 @@ +/** + ****************************************************************************** + * @file cmox_drbg_retvals.h + * @author MCD Application Team + * @brief Header file for the DRBG return values + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_DRBG_RETVALS_H +#define CMOX_DRBG_RETVALS_H + +/* Include files -------------------------------------------------------------*/ +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_DRBG + * @{ + */ + +/** @defgroup CMOX_DRBG_RETVALS DRBG return values + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** + * @brief DRBG operation successfully performed + */ +#define CMOX_DRBG_SUCCESS ((cmox_drbg_retval_t)0x00040000U) + +/** + * @brief DRBG generic internal error + */ +#define CMOX_DRBG_ERR_INTERNAL ((cmox_drbg_retval_t)0x00040001U) + +/** + * @brief DRBG One of the expected function parameters is invalid + */ +#define CMOX_DRBG_ERR_BAD_PARAMETER ((cmox_drbg_retval_t)0x00040003U) + +/** + * @brief DRBG Invalid operation + */ +#define CMOX_DRBG_ERR_BAD_OPERATION ((cmox_drbg_retval_t)0x00040004U) + +/** + * @brief DRBG has not been correctly initialized + */ +#define CMOX_DRBG_ERR_UNINIT_STATE ((cmox_drbg_retval_t)0x0004000DU) + +/** + * @brief DRBG Reseed is needed + */ +#define CMOX_DRBG_ERR_RESEED_NEEDED ((cmox_drbg_retval_t)0x0004000EU) + +/** + * @brief DRBG Check the size of the entropy string + */ +#define CMOX_DRBG_ERR_BAD_ENTROPY_SIZE ((cmox_drbg_retval_t)0x0004000FU) + +/** + * @brief DRBG Check the size of the personalization string + */ +#define CMOX_DRBG_ERR_BAD_PERS_STR_LEN ((cmox_drbg_retval_t)0x00040010U) + +/** + * @brief DRBG Check the size of the additional input string + */ +#define CMOX_DRBG_ERR_BAD_ADD_INPUT_LEN ((cmox_drbg_retval_t)0x00040011U) + +/** + * @brief DRBG Check the size of the random request + */ +#define CMOX_DRBG_ERR_BAD_REQUEST ((cmox_drbg_retval_t)0x00040012U) + +/** + * @brief DRBG Check the size of the nonce + */ +#define CMOX_DRBG_ERR_BAD_NONCE_SIZE ((cmox_drbg_retval_t)0x00040013U) + +/* Public types --------------------------------------------------------------*/ + +/** + * @brief DRBG module return value type + */ +typedef uint32_t cmox_drbg_retval_t; + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_DRBG_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc.h new file mode 100644 index 00000000..d4f375bb --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file cmox_ecc.h + * @author MCD Application Team + * @brief This file provides common function for ECC module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECC_H +#define CMOX_ECC_H + +#include +#include + +#include "ecc/cmox_ecc_retvals.h" +#include "ecc/cmox_ecc_types.h" +#if !defined(CMOX_DEFAULT_FILE) +#include "cmox_default_config.h" +#else +#include CMOX_DEFAULT_FILE +#endif /* CMOX_DEFAULT_FILE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_CURVES Supported curves implementations + * @{ + */ +extern const cmox_ecc_impl_t CMOX_ECC_CURVE25519; /*!< Suggested Curve25519 implementation (for X25519) for the target device */ +extern const cmox_ecc_impl_t CMOX_ECC_CURVE448; /*!< Suggested Curve448 implementation (for X448) for the target device */ + +extern const cmox_ecc_impl_t CMOX_ECC_ED25519_HIGHMEM; /*!< EDWARDS Ed25519 with general Edwards functions, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_ED25519_OPT_LOWMEM; /*!< EDWARDS Ed25519 with Edwards functions optimized for a = -1, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_ED25519_OPT_HIGHMEM; /*!< EDWARDS Ed25519 with Edwards functions optimized for a = -1, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_ED448_LOWMEM; /*!< EDWARDS Ed448 with general Edwards functions, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_ED448_HIGHMEM; /*!< EDWARDS Ed448 with general Edwards functions, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_SECP224R1_LOWMEM; /*!< NIST-R P-224, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP224R1_HIGHMEM; /*!< NIST-R P-224, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP256R1_LOWMEM; /*!< NIST-R P-256, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP256R1_HIGHMEM; /*!< NIST-R P-256, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP384R1_LOWMEM; /*!< NIST-R P-384, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP384R1_HIGHMEM; /*!< NIST-R P-384, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP521R1_LOWMEM; /*!< NIST-R P-521, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP521R1_HIGHMEM; /*!< NIST-R P-521, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_SECP256K1_LOWMEM; /*!< NIST-K P-256, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SECP256K1_HIGHMEM; /*!< NIST-K P-256, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_BPP160R1_LOWMEM; /*!< BRAINPOOL-R P-160, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP160R1_HIGHMEM; /*!< BRAINPOOL-R P-160, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP192R1_LOWMEM; /*!< BRAINPOOL-R P-192, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP192R1_HIGHMEM; /*!< BRAINPOOL-R P-192, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP224R1_LOWMEM; /*!< BRAINPOOL-R P-224, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP224R1_HIGHMEM; /*!< BRAINPOOL-R P-224, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP256R1_LOWMEM; /*!< BRAINPOOL-R P-256, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP256R1_HIGHMEM; /*!< BRAINPOOL-R P-256, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP320R1_LOWMEM; /*!< BRAINPOOL-R P-320, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP320R1_HIGHMEM; /*!< BRAINPOOL-R P-320, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP384R1_LOWMEM; /*!< BRAINPOOL-R P-384, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP384R1_HIGHMEM; /*!< BRAINPOOL-R P-384, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP512R1_LOWMEM; /*!< BRAINPOOL-R P-512, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP512R1_HIGHMEM; /*!< BRAINPOOL-R P-512, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_BPP160T1_LOWMEM; /*!< BRAINPOOL-T P-160, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP160T1_HIGHMEM; /*!< BRAINPOOL-T P-160, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP192T1_LOWMEM; /*!< BRAINPOOL-T P-192, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP192T1_HIGHMEM; /*!< BRAINPOOL-T P-192, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP224T1_LOWMEM; /*!< BRAINPOOL-T P-224, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP224T1_HIGHMEM; /*!< BRAINPOOL-T P-224, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP256T1_LOWMEM; /*!< BRAINPOOL-T P-256, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP256T1_HIGHMEM; /*!< BRAINPOOL-T P-256, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP320T1_LOWMEM; /*!< BRAINPOOL-T P-320, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP320T1_HIGHMEM; /*!< BRAINPOOL-T P-320, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP384T1_LOWMEM; /*!< BRAINPOOL-T P-384, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP384T1_HIGHMEM; /*!< BRAINPOOL-T P-384, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP512T1_LOWMEM; /*!< BRAINPOOL-T P-512, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_BPP512T1_HIGHMEM; /*!< BRAINPOOL-T P-512, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_FRP256V1_LOWMEM; /*!< ANSSI P-256, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_FRP256V1_HIGHMEM; /*!< ANSSI P-256, high RAM usage */ + +extern const cmox_ecc_impl_t CMOX_ECC_SM2_LOWMEM; /*!< OSCCA 256 bit curve, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SM2_HIGHMEM; /*!< OSCCA 256 bit curve, high RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SM2TEST_LOWMEM; /*!< OSCCA 256 bit test curve, low RAM usage */ +extern const cmox_ecc_impl_t CMOX_ECC_SM2TEST_HIGHMEM; /*!< OSCCA 256 bit test curve, high RAM usage */ +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_OUTPUT_LENGTHS Macros for output buffers definitions + * @{ + */ +#define CMOX_ECC_CURVE25519_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a CURVE25519 private key */ +#define CMOX_ECC_CURVE25519_PUBKEY_LEN 32u /*!< Byte length for a byte buffer containing a CURVE25519 public key */ +#define CMOX_ECC_CURVE25519_SECRET_LEN 32u /*!< Byte length for a byte buffer containing a CURVE25519 ECDH secret */ +#define CMOX_ECC_CURVE448_PRIVKEY_LEN 56u /*!< Byte length for a byte buffer containing a CURVE448 private key */ +#define CMOX_ECC_CURVE448_PUBKEY_LEN 56u /*!< Byte length for a byte buffer containing a CURVE448 public key */ +#define CMOX_ECC_CURVE448_SECRET_LEN 56u /*!< Byte length for a byte buffer containing a CURVE448 ECDH secret */ +#define CMOX_ECC_ED25519_SIG_LEN 64u /*!< Byte length for a byte buffer containing a ED25519 signature */ +#define CMOX_ECC_ED25519_PRIVKEY_LEN 64u /*!< Byte length for a byte buffer containing a ED25519 private key */ +#define CMOX_ECC_ED25519_PUBKEY_LEN 32u /*!< Byte length for a byte buffer containing a ED25519 public key */ +#define CMOX_ECC_ED448_SIG_LEN 114u /*!< Byte length for a byte buffer containing a ED448 signature */ +#define CMOX_ECC_ED448_PRIVKEY_LEN 114u /*!< Byte length for a byte buffer containing a ED448 private key */ +#define CMOX_ECC_ED448_PUBKEY_LEN 57u /*!< Byte length for a byte buffer containing a ED448 public key */ +#define CMOX_ECC_SECP224R1_SIG_LEN 56u /*!< Byte length for a byte buffer containing a SECP224R1 signature */ +#define CMOX_ECC_SECP224R1_PRIVKEY_LEN 28u /*!< Byte length for a byte buffer containing a SECP224R1 private key */ +#define CMOX_ECC_SECP224R1_PUBKEY_LEN 56u /*!< Byte length for a byte buffer containing a SECP224R1 public key */ +#define CMOX_ECC_SECP224R1_SECRET_LEN 56u /*!< Byte length for a byte buffer containing a SECP224R1 ECDH secret */ +#define CMOX_ECC_SECP256R1_SIG_LEN 64u /*!< Byte length for a byte buffer containing a SECP256R1 signature */ +#define CMOX_ECC_SECP256R1_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a SECP256R1 private key */ +#define CMOX_ECC_SECP256R1_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a SECP256R1 public key */ +#define CMOX_ECC_SECP256R1_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a SECP256R1 ECDH secret */ +#define CMOX_ECC_SECP384R1_SIG_LEN 96u /*!< Byte length for a byte buffer containing a SECP384R1 signature */ +#define CMOX_ECC_SECP384R1_PRIVKEY_LEN 48u /*!< Byte length for a byte buffer containing a SECP384R1 private key */ +#define CMOX_ECC_SECP384R1_PUBKEY_LEN 96u /*!< Byte length for a byte buffer containing a SECP384R1 public key */ +#define CMOX_ECC_SECP384R1_SECRET_LEN 96u /*!< Byte length for a byte buffer containing a SECP384R1 ECDH secret */ +#define CMOX_ECC_SECP521R1_SIG_LEN 132u /*!< Byte length for a byte buffer containing a SECP521R1 signature */ +#define CMOX_ECC_SECP521R1_PRIVKEY_LEN 66u /*!< Byte length for a byte buffer containing a SECP521R1 private key */ +#define CMOX_ECC_SECP521R1_PUBKEY_LEN 132u /*!< Byte length for a byte buffer containing a SECP521R1 public key */ +#define CMOX_ECC_SECP521R1_SECRET_LEN 132u /*!< Byte length for a byte buffer containing a SECP521R1 ECDH secret */ +#define CMOX_ECC_SECP256K1_SIG_LEN 64u /*!< Byte length for a byte buffer containing a SECP256K1 signature */ +#define CMOX_ECC_SECP256K1_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a SECP256K1 private key */ +#define CMOX_ECC_SECP256K1_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a SECP256K1 public key */ +#define CMOX_ECC_SECP256K1_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a SECP256K1 ECDH secret */ +#define CMOX_ECC_BPP160R1_SIG_LEN 40u /*!< Byte length for a byte buffer containing a BPP160R1 signature */ +#define CMOX_ECC_BPP160R1_PRIVKEY_LEN 20u /*!< Byte length for a byte buffer containing a BPP160R1 private key */ +#define CMOX_ECC_BPP160R1_PUBKEY_LEN 40u /*!< Byte length for a byte buffer containing a BPP160R1 public key */ +#define CMOX_ECC_BPP160R1_SECRET_LEN 40u /*!< Byte length for a byte buffer containing a BPP160R1 ECDH secret */ +#define CMOX_ECC_BPP192R1_SIG_LEN 48u /*!< Byte length for a byte buffer containing a BPP192R1 signature */ +#define CMOX_ECC_BPP192R1_PRIVKEY_LEN 24u /*!< Byte length for a byte buffer containing a BPP192R1 private key */ +#define CMOX_ECC_BPP192R1_PUBKEY_LEN 48u /*!< Byte length for a byte buffer containing a BPP192R1 public key */ +#define CMOX_ECC_BPP192R1_SECRET_LEN 48u /*!< Byte length for a byte buffer containing a BPP192R1 ECDH secret */ +#define CMOX_ECC_BPP224R1_SIG_LEN 56u /*!< Byte length for a byte buffer containing a BPP224R1 signature */ +#define CMOX_ECC_BPP224R1_PRIVKEY_LEN 28u /*!< Byte length for a byte buffer containing a BPP224R1 private key */ +#define CMOX_ECC_BPP224R1_PUBKEY_LEN 56u /*!< Byte length for a byte buffer containing a BPP224R1 public key */ +#define CMOX_ECC_BPP224R1_SECRET_LEN 56u /*!< Byte length for a byte buffer containing a BPP224R1 ECDH secret */ +#define CMOX_ECC_BPP256R1_SIG_LEN 64u /*!< Byte length for a byte buffer containing a BPP256R1 signature */ +#define CMOX_ECC_BPP256R1_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a BPP256R1 private key */ +#define CMOX_ECC_BPP256R1_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a BPP256R1 public key */ +#define CMOX_ECC_BPP256R1_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a BPP256R1 ECDH secret */ +#define CMOX_ECC_BPP320R1_SIG_LEN 80u /*!< Byte length for a byte buffer containing a BPP320R1 signature */ +#define CMOX_ECC_BPP320R1_PRIVKEY_LEN 40u /*!< Byte length for a byte buffer containing a BPP320R1 private key */ +#define CMOX_ECC_BPP320R1_PUBKEY_LEN 80u /*!< Byte length for a byte buffer containing a BPP320R1 public key */ +#define CMOX_ECC_BPP320R1_SECRET_LEN 80u /*!< Byte length for a byte buffer containing a BPP320R1 ECDH secret */ +#define CMOX_ECC_BPP384R1_SIG_LEN 96u /*!< Byte length for a byte buffer containing a BPP384R1 signature */ +#define CMOX_ECC_BPP384R1_PRIVKEY_LEN 48u /*!< Byte length for a byte buffer containing a BPP384R1 private key */ +#define CMOX_ECC_BPP384R1_PUBKEY_LEN 96u /*!< Byte length for a byte buffer containing a BPP384R1 public key */ +#define CMOX_ECC_BPP384R1_SECRET_LEN 96u /*!< Byte length for a byte buffer containing a BPP384R1 ECDH secret */ +#define CMOX_ECC_BPP512R1_SIG_LEN 128u /*!< Byte length for a byte buffer containing a BPP512R1 signature */ +#define CMOX_ECC_BPP512R1_PRIVKEY_LEN 64u /*!< Byte length for a byte buffer containing a BPP512R1 private key */ +#define CMOX_ECC_BPP512R1_PUBKEY_LEN 128u /*!< Byte length for a byte buffer containing a BPP512R1 public key */ +#define CMOX_ECC_BPP512R1_SECRET_LEN 128u /*!< Byte length for a byte buffer containing a BPP512R1 ECDH secret */ +#define CMOX_ECC_BPP160T1_SIG_LEN 40u /*!< Byte length for a byte buffer containing a BPP160T1 signature */ +#define CMOX_ECC_BPP160T1_PRIVKEY_LEN 20u /*!< Byte length for a byte buffer containing a BPP160T1 private key */ +#define CMOX_ECC_BPP160T1_PUBKEY_LEN 40u /*!< Byte length for a byte buffer containing a BPP160T1 public key */ +#define CMOX_ECC_BPP160T1_SECRET_LEN 40u /*!< Byte length for a byte buffer containing a BPP160T1 ECDH secret */ +#define CMOX_ECC_BPP192T1_SIG_LEN 48u /*!< Byte length for a byte buffer containing a BPP192T1 signature */ +#define CMOX_ECC_BPP192T1_PRIVKEY_LEN 24u /*!< Byte length for a byte buffer containing a BPP192T1 private key */ +#define CMOX_ECC_BPP192T1_PUBKEY_LEN 48u /*!< Byte length for a byte buffer containing a BPP192T1 public key */ +#define CMOX_ECC_BPP192T1_SECRET_LEN 48u /*!< Byte length for a byte buffer containing a BPP192T1 ECDH secret */ +#define CMOX_ECC_BPP224T1_SIG_LEN 56u /*!< Byte length for a byte buffer containing a BPP224T1 signature */ +#define CMOX_ECC_BPP224T1_PRIVKEY_LEN 28u /*!< Byte length for a byte buffer containing a BPP224T1 private key */ +#define CMOX_ECC_BPP224T1_PUBKEY_LEN 56u /*!< Byte length for a byte buffer containing a BPP224T1 public key */ +#define CMOX_ECC_BPP224T1_SECRET_LEN 56u /*!< Byte length for a byte buffer containing a BPP224T1 ECDH secret */ +#define CMOX_ECC_BPP256T1_SIG_LEN 64u /*!< Byte length for a byte buffer containing a BPP256T1 signature */ +#define CMOX_ECC_BPP256T1_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a BPP256T1 private key */ +#define CMOX_ECC_BPP256T1_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a BPP256T1 public key */ +#define CMOX_ECC_BPP256T1_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a BPP256T1 ECDH secret */ +#define CMOX_ECC_BPP320T1_SIG_LEN 80u /*!< Byte length for a byte buffer containing a BPP320T1 signature */ +#define CMOX_ECC_BPP320T1_PRIVKEY_LEN 40u /*!< Byte length for a byte buffer containing a BPP320T1 private key */ +#define CMOX_ECC_BPP320T1_PUBKEY_LEN 80u /*!< Byte length for a byte buffer containing a BPP320T1 public key */ +#define CMOX_ECC_BPP320T1_SECRET_LEN 80u /*!< Byte length for a byte buffer containing a BPP320T1 ECDH secret */ +#define CMOX_ECC_BPP384T1_SIG_LEN 96u /*!< Byte length for a byte buffer containing a BPP384T1 signature */ +#define CMOX_ECC_BPP384T1_PRIVKEY_LEN 48u /*!< Byte length for a byte buffer containing a BPP384T1 private key */ +#define CMOX_ECC_BPP384T1_PUBKEY_LEN 96u /*!< Byte length for a byte buffer containing a BPP384T1 public key */ +#define CMOX_ECC_BPP384T1_SECRET_LEN 96u /*!< Byte length for a byte buffer containing a BPP384T1 ECDH secret */ +#define CMOX_ECC_BPP512T1_SIG_LEN 128u /*!< Byte length for a byte buffer containing a BPP512T1 signature */ +#define CMOX_ECC_BPP512T1_PRIVKEY_LEN 64u /*!< Byte length for a byte buffer containing a BPP512T1 private key */ +#define CMOX_ECC_BPP512T1_PUBKEY_LEN 128u /*!< Byte length for a byte buffer containing a BPP512T1 public key */ +#define CMOX_ECC_BPP512T1_SECRET_LEN 128u /*!< Byte length for a byte buffer containing a BPP512T1 ECDH secret */ +#define CMOX_ECC_FRP256V1_SIG_LEN 64u /*!< Byte length for a byte buffer containing a FRP256V1 signature */ +#define CMOX_ECC_FRP256V1_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a FRP256V1 private key */ +#define CMOX_ECC_FRP256V1_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a FRP256V1 public key */ +#define CMOX_ECC_FRP256V1_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a FRP256V1 ECDH secret */ +#define CMOX_ECC_SM2_SIG_LEN 64u /*!< Byte length for a byte buffer containing a SM2 signature */ +#define CMOX_ECC_SM2_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a SM2 private key */ +#define CMOX_ECC_SM2_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a SM2 public key */ +#define CMOX_ECC_SM2_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a SM2 ECDH secret */ +#define CMOX_ECC_SM2TEST_SIG_LEN 64u /*!< Byte length for a byte buffer containing a SM2TEST signature */ +#define CMOX_ECC_SM2TEST_PRIVKEY_LEN 32u /*!< Byte length for a byte buffer containing a SM2TEST private key */ +#define CMOX_ECC_SM2TEST_PUBKEY_LEN 64u /*!< Byte length for a byte buffer containing a SM2TEST public key */ +#define CMOX_ECC_SM2TEST_SECRET_LEN 64u /*!< Byte length for a byte buffer containing a SM2TEST ECDH secret */ +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_PUBLIC_METHODS ECC public method prototypes + * @{ + */ + +/** + * @brief Mandatory function to set Low Level Mathematical Functions, and working memory buffer, for ECC + * @param[in,out] P_pEccCtx Context for ECC operations + * @param[in] P_Math Structure pointer with the Low-level Mathematical functions + * This parameter can be one of the following: + * @arg CMOX_MATH_FUNCS_SMALL + * @arg CMOX_MATH_FUNCS_FAST + * @arg CMOX_MATH_FUNCS_SUPERFAST256 + * @param[in] P_pBuf The preallocated static buffer that will be used + * @param[in] P_BufLen The size in bytes of the P_pBuf buffer + */ +void cmox_ecc_construct(cmox_ecc_handle_t *P_pEccCtx, + const cmox_math_funcs_t P_Math, + uint8_t *P_pBuf, + size_t P_BufLen); + +/** + * @brief Clean the ECC context and the internal temporary buffer + * @param[in,out] P_pEccCtx Context for ECC operations + */ +void cmox_ecc_cleanup(cmox_ecc_handle_t *P_pEccCtx); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_ECC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_custom_curves.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_custom_curves.h new file mode 100644 index 00000000..f0b7b6b5 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_custom_curves.h @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * @file cmox_ecc_custom_curves.h + * @author MCD Application Team + * @brief This file provides everything to define custom ECC curves + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECC_CUSTOM_CURVES_H +#define CMOX_ECC_CUSTOM_CURVES_H + +#include +#include "cmox_common.h" +#include "ecc/cmox_ecc_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_CUSTOM_CURVES_OPT speed/RAM optimizations for custom curves implementations + * @{ + */ + +struct cmox_ecc_customCurve_optStr_st; /*!< struct for speed/RAM optimizations */ +typedef const struct cmox_ecc_customCurve_optStr_st *cmox_ecc_customCurve_opt_t; /*!< struct ptr for speed/RAM opt */ + +/** + * @brief Low RAM usage (slowest) + */ +extern const cmox_ecc_customCurve_opt_t cmox_ecc_customCurve_opt_low; +/** + * @brief Mid RAM usage + */ +extern const cmox_ecc_customCurve_opt_t cmox_ecc_customCurve_opt_mid; +/** + * @brief High RAM usage (fastest) + */ +extern const cmox_ecc_customCurve_opt_t cmox_ecc_customCurve_opt_high; + +/** + * @} + */ + +/** + * @defgroup CMOX_ECC_CUSTOM_CURVES_METHODS ECC public method prototypes to define custom curves + * @{ + */ + +/** + * @brief Function to create a custom Short-Weierstrass curve + * @param[in] P_pEccCtx Context for ECC operations + * @param[out] P_pCurve Pointer to a curve that will be built and filled + * @param[in] P_OptLevel Optimization level (speed vs. RAM usage) + * This parameter can be one of the following: + * @arg cmox_ecc_customCurve_opt_low + * @arg cmox_ecc_customCurve_opt_mid + * @arg cmox_ecc_customCurve_opt_high + * @param[in] P_pP Modulus of the curve + * @param[in] P_PLen Byte length of the modulus + * @param[in] P_pN Order of the curve + * @param[in] P_NLen Byte length of the order + * @param[in] P_pA Parameter A of the curve + * @param[in] P_ALen Byte length of the parameter A + * @param[in] P_pB Parameter B of the curve + * @param[in] P_BLen Byte length of the parameter B + * @param[in] P_pGx X coordinate of the Generator Point + * @param[in] P_GxLen Byte length of the X coordinate + * @param[in] P_pGy Y coordinate of the Generator Point + * @param[in] P_GyLen Byte length of the Y coordinate + * @note All the array parameters are big-endian arrays, where the first byte is the most significant one. + * @retval CMOX_ECC_SUCCESS + * @retval CMOX_ECC_ERR_BAD_PARAMETERS + * @retval CMOX_ECC_ERR_MEMORY_FAIL + * @warning This function does not check if the parameters effectively form an elliptic curve, + * so the user must be sure about the parameters that are passed to the function + */ +cmox_ecc_retval_t cmox_ecc_customCurveConstruct(cmox_ecc_handle_t *P_pEccCtx, + cmox_ecc_impl_t *P_pCurve, + cmox_ecc_customCurve_opt_t P_OptLevel, + const uint8_t *P_pP, size_t P_PLen, + const uint8_t *P_pN, size_t P_NLen, + const uint8_t *P_pA, size_t P_ALen, + const uint8_t *P_pB, size_t P_BLen, + const uint8_t *P_pGx, size_t P_GxLen, + const uint8_t *P_pGy, size_t P_GyLen); + +/** + * @brief Destroy (and release the allocated memory) a custom curve + * @param[in] P_pEccCtx Context for ECC operations + * @param[in,out] P_pCurve Pointer to the curve to destroy + */ +void cmox_ecc_customCurveCleanup(cmox_ecc_handle_t *P_pEccCtx, cmox_ecc_impl_t *P_pCurve); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_ECC_CUSTOM_CURVES_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_retvals.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_retvals.h new file mode 100644 index 00000000..acce0c36 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_retvals.h @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * @file cmox_ecc_retvals.h + * @author MCD Application Team + * @brief This file provides the error types and code for the ECC modules + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECC_RETVALS_H +#define CMOX_ECC_RETVALS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_RETVALS ECC return values + * @{ + */ + +/** + * @brief Return value type for ECC module + */ +typedef uint32_t cmox_ecc_retval_t; + +#define CMOX_ECC_SUCCESS ((cmox_ecc_retval_t)0x00060000) /*!< Success */ +#define CMOX_ECC_ERR_INTERNAL ((cmox_ecc_retval_t)0x00060001) /*!< Internal computat. error (e.g. hash) */ +#define CMOX_ECC_ERR_BAD_PARAMETERS ((cmox_ecc_retval_t)0x00060003) /*!< Bad input parameters */ +#define CMOX_ECC_ERR_INVALID_PUBKEY ((cmox_ecc_retval_t)0x00060008) /*!< Invalid Public Key value */ +#define CMOX_ECC_ERR_INVALID_SIGNATURE ((cmox_ecc_retval_t)0x00060009) /*!< Invalid Signature value */ +#define CMOX_ECC_ERR_WRONG_RANDOM ((cmox_ecc_retval_t)0x0006000B) /*!< Random not compliant with the API (Recall with other random material) */ +#define CMOX_ECC_ERR_MEMORY_FAIL ((cmox_ecc_retval_t)0x0006000C) /*!< Not enough memory */ +#define CMOX_ECC_ERR_MATHCURVE_MISMATCH ((cmox_ecc_retval_t)0x0006000E) /*!< Math customization not supported by current ECC curve */ +#define CMOX_ECC_ERR_ALGOCURVE_MISMATCH ((cmox_ecc_retval_t)0x0006000F) /*!< ECC curve not supported by current functionality */ +#define CMOX_ECC_AUTH_SUCCESS ((cmox_ecc_retval_t)0x0006C726) /*!< ECC signature successful verification */ +#define CMOX_ECC_AUTH_FAIL ((cmox_ecc_retval_t)0x00066E93) /*!< ECC signature not verified */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_ECC_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_types.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_types.h new file mode 100644 index 00000000..d04a6601 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecc_types.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file cmox_ecc_types.h + * @author MCD Application Team + * @brief This file provides the types used within the ECC module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECC_TYPES_H +#define CMOX_ECC_TYPES_H + +#include "cmox_common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @brief Structure for the ECC context + */ +typedef struct +{ + cmox_membuf_handle_st membuf_str; /*!< Memory buffer structure */ + cmox_math_funcs_t math_ptr; /*!< Math customization structure */ + uint32_t magic_num_check; /*!< Magic number for diagnostic checks */ +} cmox_ecc_handle_t; + +/** + * @brief Pointer type for the ECC curve function parameter + */ +typedef const struct cmox_ecc_implStruct_st *cmox_ecc_impl_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_ECC_TYPES_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdh.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdh.h new file mode 100644 index 00000000..3ff3e3c1 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdh.h @@ -0,0 +1,129 @@ +/** + ****************************************************************************** + * @file cmox_ecdh.h + * @author MCD Application Team + * @brief Header file for ECDH key exchange definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECDH_H +#define CMOX_ECDH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecc/cmox_ecc.h" + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_ECDH ECDH algorithm + * @{ + */ + +/** @defgroup CMOX_ECC_ECDH_PUBLIC_METHODS ECDH public method prototypes + * @{ + */ + +/** + * @brief Generate a shared secret from a private key and a public key + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_CURVE25519 + * @arg CMOX_ECC_CURVE448 + * @arg CMOX_ECC_SECP224R1_LOWMEM + * @arg CMOX_ECC_SECP224R1_HIGHMEM + * @arg CMOX_ECC_SECP256R1_LOWMEM + * @arg CMOX_ECC_SECP256R1_HIGHMEM + * @arg CMOX_ECC_SECP384R1_LOWMEM + * @arg CMOX_ECC_SECP384R1_HIGHMEM + * @arg CMOX_ECC_SECP521R1_LOWMEM + * @arg CMOX_ECC_SECP521R1_HIGHMEM + * @arg CMOX_ECC_SECP256K1_LOWMEM + * @arg CMOX_ECC_SECP256K1_HIGHMEM + * @arg CMOX_ECC_BPP160R1_LOWMEM + * @arg CMOX_ECC_BPP160R1_HIGHMEM + * @arg CMOX_ECC_BPP192R1_LOWMEM + * @arg CMOX_ECC_BPP192R1_HIGHMEM + * @arg CMOX_ECC_BPP224R1_LOWMEM + * @arg CMOX_ECC_BPP224R1_HIGHMEM + * @arg CMOX_ECC_BPP256R1_LOWMEM + * @arg CMOX_ECC_BPP256R1_HIGHMEM + * @arg CMOX_ECC_BPP320R1_LOWMEM + * @arg CMOX_ECC_BPP320R1_HIGHMEM + * @arg CMOX_ECC_BPP384R1_LOWMEM + * @arg CMOX_ECC_BPP384R1_HIGHMEM + * @arg CMOX_ECC_BPP512R1_LOWMEM + * @arg CMOX_ECC_BPP512R1_HIGHMEM + * @arg CMOX_ECC_BPP160T1_LOWMEM + * @arg CMOX_ECC_BPP160T1_HIGHMEM + * @arg CMOX_ECC_BPP192T1_LOWMEM + * @arg CMOX_ECC_BPP192T1_HIGHMEM + * @arg CMOX_ECC_BPP224T1_LOWMEM + * @arg CMOX_ECC_BPP224T1_HIGHMEM + * @arg CMOX_ECC_BPP256T1_LOWMEM + * @arg CMOX_ECC_BPP256T1_HIGHMEM + * @arg CMOX_ECC_BPP320T1_LOWMEM + * @arg CMOX_ECC_BPP320T1_HIGHMEM + * @arg CMOX_ECC_BPP384T1_LOWMEM + * @arg CMOX_ECC_BPP384T1_HIGHMEM + * @arg CMOX_ECC_BPP512T1_LOWMEM + * @arg CMOX_ECC_BPP512T1_HIGHMEM + * @arg CMOX_ECC_FRP256V1_LOWMEM + * @arg CMOX_ECC_FRP256V1_HIGHMEM + * @param[in] P_pPrivKey Buffer with the private key + * @param[in] P_PrivKeyLen Private key length + * @param[in] P_pPubKey Buffer with the public key + * @param[in] P_PubKeyLen Public key length + * @param[out] P_pSharedSecret Buffer for the shared secret + * @param[out] P_pSharedSecretLen Shared secret length + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INVALID_PUBKEY Public key not in a valid format + */ +cmox_ecc_retval_t cmox_ecdh(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pPrivKey, + size_t P_PrivKeyLen, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen, + uint8_t *P_pSharedSecret, + size_t *P_pSharedSecretLen); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CMOX_ECDH_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdsa.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdsa.h new file mode 100644 index 00000000..ac206c38 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_ecdsa.h @@ -0,0 +1,295 @@ +/** + ****************************************************************************** + * @file cmox_ecdsa.h + * @author MCD Application Team + * @brief Header file for ECDSA signature creation and verification + functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_ECDSA_H +#define CMOX_ECDSA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecc/cmox_ecc.h" + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_ECDSA ECDSA algorithm + * @{ + */ + +/** @defgroup CMOX_ECC_ECDSA_PUBLIC_METHODS ECDSA public method prototypes + * @{ + */ + +/** + * @brief Generate private and public keys to use with ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SECP224R1_LOWMEM + * @arg CMOX_ECC_SECP224R1_HIGHMEM + * @arg CMOX_ECC_SECP256R1_LOWMEM + * @arg CMOX_ECC_SECP256R1_HIGHMEM + * @arg CMOX_ECC_SECP384R1_LOWMEM + * @arg CMOX_ECC_SECP384R1_HIGHMEM + * @arg CMOX_ECC_SECP521R1_LOWMEM + * @arg CMOX_ECC_SECP521R1_HIGHMEM + * @arg CMOX_ECC_SECP256K1_LOWMEM + * @arg CMOX_ECC_SECP256K1_HIGHMEM + * @arg CMOX_ECC_BPP160R1_LOWMEM + * @arg CMOX_ECC_BPP160R1_HIGHMEM + * @arg CMOX_ECC_BPP192R1_LOWMEM + * @arg CMOX_ECC_BPP192R1_HIGHMEM + * @arg CMOX_ECC_BPP224R1_LOWMEM + * @arg CMOX_ECC_BPP224R1_HIGHMEM + * @arg CMOX_ECC_BPP256R1_LOWMEM + * @arg CMOX_ECC_BPP256R1_HIGHMEM + * @arg CMOX_ECC_BPP320R1_LOWMEM + * @arg CMOX_ECC_BPP320R1_HIGHMEM + * @arg CMOX_ECC_BPP384R1_LOWMEM + * @arg CMOX_ECC_BPP384R1_HIGHMEM + * @arg CMOX_ECC_BPP512R1_LOWMEM + * @arg CMOX_ECC_BPP512R1_HIGHMEM + * @arg CMOX_ECC_BPP160T1_LOWMEM + * @arg CMOX_ECC_BPP160T1_HIGHMEM + * @arg CMOX_ECC_BPP192T1_LOWMEM + * @arg CMOX_ECC_BPP192T1_HIGHMEM + * @arg CMOX_ECC_BPP224T1_LOWMEM + * @arg CMOX_ECC_BPP224T1_HIGHMEM + * @arg CMOX_ECC_BPP256T1_LOWMEM + * @arg CMOX_ECC_BPP256T1_HIGHMEM + * @arg CMOX_ECC_BPP320T1_LOWMEM + * @arg CMOX_ECC_BPP320T1_HIGHMEM + * @arg CMOX_ECC_BPP384T1_LOWMEM + * @arg CMOX_ECC_BPP384T1_HIGHMEM + * @arg CMOX_ECC_BPP512T1_LOWMEM + * @arg CMOX_ECC_BPP512T1_HIGHMEM + * @arg CMOX_ECC_FRP256V1_LOWMEM + * @arg CMOX_ECC_FRP256V1_HIGHMEM + * @param[in] P_pRandom Buffer of random bytes + * @param[in] P_RandomLen Byte length of the random buffer + * @param[out] P_pPrivKey Buffer with the private key (in range [1; N - 1]) + * @param[out] P_pPrivKeyLen Byte length of the private key + * @param[out] P_pPubKey Buffer with the public key + * @param[out] P_pPubKeyLen Byte length of the public key + * @note the private key is derived from the random in the + * following way: \verbatim privkey = (random >> ((WORD_NBIT - N_MSW_NBIT) & 7)) + 1 \endverbatim, + * where: random is the input random buffer (interpreted as a big-endian integer), + * WORD_NBIT is the bitsize of a cpu word, + * N_MSW_NBIT is the bitlength of the most significant word of the parameter N of the curve. + * @note If P_RandomLen is not enough, an error is returned and P_pPrivKeyLen + * contains the minimum number of bytes of random to provide (and is also + * the minimum length of P_pPrivKey), while P_pPubKeyLen contains the + * minimum length of P_pPubKey. + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + */ +cmox_ecc_retval_t cmox_ecdsa_keyGen(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pRandom, + size_t P_RandomLen, + uint8_t *P_pPrivKey, + size_t *P_pPrivKeyLen, + uint8_t *P_pPubKey, + size_t *P_pPubKeyLen); + +/** + * @brief Generate a signature, using ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SECP224R1_LOWMEM + * @arg CMOX_ECC_SECP224R1_HIGHMEM + * @arg CMOX_ECC_SECP256R1_LOWMEM + * @arg CMOX_ECC_SECP256R1_HIGHMEM + * @arg CMOX_ECC_SECP384R1_LOWMEM + * @arg CMOX_ECC_SECP384R1_HIGHMEM + * @arg CMOX_ECC_SECP521R1_LOWMEM + * @arg CMOX_ECC_SECP521R1_HIGHMEM + * @arg CMOX_ECC_SECP256K1_LOWMEM + * @arg CMOX_ECC_SECP256K1_HIGHMEM + * @arg CMOX_ECC_BPP160R1_LOWMEM + * @arg CMOX_ECC_BPP160R1_HIGHMEM + * @arg CMOX_ECC_BPP192R1_LOWMEM + * @arg CMOX_ECC_BPP192R1_HIGHMEM + * @arg CMOX_ECC_BPP224R1_LOWMEM + * @arg CMOX_ECC_BPP224R1_HIGHMEM + * @arg CMOX_ECC_BPP256R1_LOWMEM + * @arg CMOX_ECC_BPP256R1_HIGHMEM + * @arg CMOX_ECC_BPP320R1_LOWMEM + * @arg CMOX_ECC_BPP320R1_HIGHMEM + * @arg CMOX_ECC_BPP384R1_LOWMEM + * @arg CMOX_ECC_BPP384R1_HIGHMEM + * @arg CMOX_ECC_BPP512R1_LOWMEM + * @arg CMOX_ECC_BPP512R1_HIGHMEM + * @arg CMOX_ECC_BPP160T1_LOWMEM + * @arg CMOX_ECC_BPP160T1_HIGHMEM + * @arg CMOX_ECC_BPP192T1_LOWMEM + * @arg CMOX_ECC_BPP192T1_HIGHMEM + * @arg CMOX_ECC_BPP224T1_LOWMEM + * @arg CMOX_ECC_BPP224T1_HIGHMEM + * @arg CMOX_ECC_BPP256T1_LOWMEM + * @arg CMOX_ECC_BPP256T1_HIGHMEM + * @arg CMOX_ECC_BPP320T1_LOWMEM + * @arg CMOX_ECC_BPP320T1_HIGHMEM + * @arg CMOX_ECC_BPP384T1_LOWMEM + * @arg CMOX_ECC_BPP384T1_HIGHMEM + * @arg CMOX_ECC_BPP512T1_LOWMEM + * @arg CMOX_ECC_BPP512T1_HIGHMEM + * @arg CMOX_ECC_FRP256V1_LOWMEM + * @arg CMOX_ECC_FRP256V1_HIGHMEM + * @param[in] P_pRandom Buffer of random bytes + * @param[in] P_RandomLen Byte length of the random buffer + * @param[in] P_pPrivKey Buffer with the private key + * @param[in] P_PrivKeyLen Byte length of the private key + * @param[in] P_pDigest Buffer with the digest to sign + * @param[in] P_DigestLen Byte length of the digest + * @param[out] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[out] P_pSignatureLen Byte length of the signature + * @note the internal value k, used as scalar and multiplied by the base point, is derived from the random in the + * following way: \verbatim k = (random >> ((WORD_NBIT - N_MSW_NBIT) & 7)) + 1 \endverbatim, + * where: random is the input random buffer (interpreted as a big-endian integer), + * WORD_NBIT is the bitsize of a cpu word, + * N_MSW_NBIT is the bitlength of the most significant word of the parameter N of the curve. + * @note If P_RandomLen is not enough, an error is returned and + * P_pSignatureLen contains the minimum number of bytes of random + * to provide (and is also the minimum length of P_pPrivKey, and + * half the length of P_pSignature). + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + */ +cmox_ecc_retval_t cmox_ecdsa_sign(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pRandom, + size_t P_RandomLen, + const uint8_t *P_pPrivKey, + size_t P_PrivKeyLen, + const uint8_t *P_pDigest, + size_t P_DigestLen, + uint8_t *P_pSignature, + size_t *P_pSignatureLen); + +/** + * @brief Verify a signature, using ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SECP224R1_LOWMEM + * @arg CMOX_ECC_SECP224R1_HIGHMEM + * @arg CMOX_ECC_SECP256R1_LOWMEM + * @arg CMOX_ECC_SECP256R1_HIGHMEM + * @arg CMOX_ECC_SECP384R1_LOWMEM + * @arg CMOX_ECC_SECP384R1_HIGHMEM + * @arg CMOX_ECC_SECP521R1_LOWMEM + * @arg CMOX_ECC_SECP521R1_HIGHMEM + * @arg CMOX_ECC_SECP256K1_LOWMEM + * @arg CMOX_ECC_SECP256K1_HIGHMEM + * @arg CMOX_ECC_BPP160R1_LOWMEM + * @arg CMOX_ECC_BPP160R1_HIGHMEM + * @arg CMOX_ECC_BPP192R1_LOWMEM + * @arg CMOX_ECC_BPP192R1_HIGHMEM + * @arg CMOX_ECC_BPP224R1_LOWMEM + * @arg CMOX_ECC_BPP224R1_HIGHMEM + * @arg CMOX_ECC_BPP256R1_LOWMEM + * @arg CMOX_ECC_BPP256R1_HIGHMEM + * @arg CMOX_ECC_BPP320R1_LOWMEM + * @arg CMOX_ECC_BPP320R1_HIGHMEM + * @arg CMOX_ECC_BPP384R1_LOWMEM + * @arg CMOX_ECC_BPP384R1_HIGHMEM + * @arg CMOX_ECC_BPP512R1_LOWMEM + * @arg CMOX_ECC_BPP512R1_HIGHMEM + * @arg CMOX_ECC_BPP160T1_LOWMEM + * @arg CMOX_ECC_BPP160T1_HIGHMEM + * @arg CMOX_ECC_BPP192T1_LOWMEM + * @arg CMOX_ECC_BPP192T1_HIGHMEM + * @arg CMOX_ECC_BPP224T1_LOWMEM + * @arg CMOX_ECC_BPP224T1_HIGHMEM + * @arg CMOX_ECC_BPP256T1_LOWMEM + * @arg CMOX_ECC_BPP256T1_HIGHMEM + * @arg CMOX_ECC_BPP320T1_LOWMEM + * @arg CMOX_ECC_BPP320T1_HIGHMEM + * @arg CMOX_ECC_BPP384T1_LOWMEM + * @arg CMOX_ECC_BPP384T1_HIGHMEM + * @arg CMOX_ECC_BPP512T1_LOWMEM + * @arg CMOX_ECC_BPP512T1_HIGHMEM + * @arg CMOX_ECC_FRP256V1_LOWMEM + * @arg CMOX_ECC_FRP256V1_HIGHMEM + * @param[in] P_pPubKey Buffer with the public key + * @param[in] P_PubKeyLen Byte length of the public key + * @param[in] P_pDigest Buffer with the digest to sign + * @param[in] P_DigestLen Byte length of the digest + * @param[in] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[in] P_SignatureLen Byte length of the signature + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_ECC_AUTH_SUCCESS Signature verified + * @retval CMOX_ECC_AUTH_FAIL Signature NOT verified + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INVALID_SIGNATURE Input signature corrupted or not in the expected format + * @retval CMOX_ECC_ERR_INVALID_PUBKEY Public key not in a valid format + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_ecc_retval_t cmox_ecdsa_verify(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen, + const uint8_t *P_pDigest, + size_t P_DigestLen, + const uint8_t *P_pSignature, + size_t P_SignatureLen, + uint32_t *P_pFaultCheck); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CMOX_ECDSA_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_eddsa.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_eddsa.h new file mode 100644 index 00000000..8c224ebd --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_eddsa.h @@ -0,0 +1,175 @@ +/** + ****************************************************************************** + * @file cmox_eddsa.h + * @author MCD Application Team + * @brief Header file for EdDSA signature creation and verification + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_EDDSA_H +#define CMOX_EDDSA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecc/cmox_ecc.h" + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_EDDSA EDDSA algorithm + * @{ + */ + +/** @defgroup CMOX_ECC_EDDSA_PUBLIC_METHODS EDDSA public method prototypes + * @{ + */ + +/** + * @brief Generate private and public keys to use with EDDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_ED25519_HIGHMEM + * @arg CMOX_ECC_ED25519_OPT_LOWMEM + * @arg CMOX_ECC_ED25519_OPT_HIGHMEM + * @arg CMOX_ECC_ED448_LOWMEM + * @arg CMOX_ECC_ED448_HIGHMEM + * @param[in] P_pRandom Buffer of random bytes + * @param[in] P_RandomLen Byte length of the random buffer + * @param[out] P_pPrivKey Buffer with the private key, whose first half will be the secret value and the second + * half will contain the public key + * @param[out] P_pPrivKeyLen Byte length of the private key + * @param[out] P_pPubKey Buffer with the public key + * @param[out] P_pPubKeyLen Byte length of the public key + * @note If P_RandomLen is not enough, an error is returned and P_pPrivKeyLen + * contains the minimum number of bytes of random to provide (and is also + * half the minimum length of P_pPrivKey), while P_pPubKeyLen contains the + * minimum length of P_pPubKey. + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + */ +cmox_ecc_retval_t cmox_eddsa_keyGen(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pRandom, + size_t P_RandomLen, + uint8_t *P_pPrivKey, + size_t *P_pPrivKeyLen, + uint8_t *P_pPubKey, + size_t *P_pPubKeyLen); + +/** + * @brief Generate a signature, using EDDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_ED25519_HIGHMEM + * @arg CMOX_ECC_ED25519_OPT_LOWMEM + * @arg CMOX_ECC_ED25519_OPT_HIGHMEM + * @arg CMOX_ECC_ED448_LOWMEM + * @arg CMOX_ECC_ED448_HIGHMEM + * @param[in] P_pPrivKey Buffer with the private key, whose first half is the secret value and the second half + * contains the public key + * @param[in] P_PrivKeyLen Byte length of the private key + * @param[in] P_pMessage Buffer with the message to sign + * @param[in] P_MessageLen Byte length of the message + * @param[out] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[out] P_pSignatureLen Byte length of the signature + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + */ +cmox_ecc_retval_t cmox_eddsa_sign(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pPrivKey, + size_t P_PrivKeyLen, + const uint8_t *P_pMessage, + size_t P_MessageLen, + uint8_t *P_pSignature, + size_t *P_pSignatureLen); + +/** + * @brief Verify a signature, using EDDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_ED25519_HIGHMEM + * @arg CMOX_ECC_ED25519_OPT_LOWMEM + * @arg CMOX_ECC_ED25519_OPT_HIGHMEM + * @arg CMOX_ECC_ED448_LOWMEM + * @arg CMOX_ECC_ED448_HIGHMEM + * @param[in] P_pPubKey Buffer with the public key + * @param[in] P_PubKeyLen Byte length of the public key + * @param[in] P_pMessage Buffer with the message to verify + * @param[in] P_MessageLen Byte length of the message + * @param[in] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[in] P_SignatureLen Byte length of the signature + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_ECC_AUTH_SUCCESS Signature verified + * @retval CMOX_ECC_AUTH_FAIL Signature NOT verified + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + * @retval CMOX_ECC_ERR_INVALID_SIGNATURE Input signature corrupted or not in the expected format + * @retval CMOX_ECC_ERR_INVALID_PUBKEY Public key not in a valid format + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_ecc_retval_t cmox_eddsa_verify(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen, + const uint8_t *P_pMessage, + size_t P_MessageLen, + const uint8_t *P_pSignature, + size_t P_SignatureLen, + uint32_t *P_pFaultCheck); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CMOX_EDDSA_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/ecc/cmox_sm2.h b/firmware/ui/dependencies/cmox/include/ecc/cmox_sm2.h new file mode 100644 index 00000000..5f1a9776 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/ecc/cmox_sm2.h @@ -0,0 +1,218 @@ +/** + ****************************************************************************** + * @file cmox_sm2.h + * @author MCD Application Team + * @brief Header file for SM2 signature creation and verification functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_SM2_H +#define CMOX_SM2_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecc/cmox_ecc.h" + +/** @addtogroup CMOX_ECC + * @{ + */ + +/** + * @defgroup CMOX_ECC_SM2 SM2 algorithm + * @{ + */ + +/** @defgroup CMOX_ECC_SM2_PUBLIC_METHODS SM2 public method prototypes + * @{ + */ + +/** + * @brief Generate private and public keys to use with ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SM2_LOWMEM + * @arg CMOX_ECC_SM2_HIGHMEM + * @arg CMOX_ECC_SM2TEST_LOWMEM + * @arg CMOX_ECC_SM2TEST_HIGHMEM + * @param[in] P_pRandom Buffer of random bytes + * @param[in] P_RandomLen Byte length of the random buffer + * @param[out] P_pPrivKey Buffer with the private key (in range [1; N - 2]) + * @param[out] P_pPrivKeyLen Byte length of the private key + * @param[out] P_pPubKey Buffer with the public key + * @param[out] P_pPubKeyLen Byte length of the public key + * @note the private key is derived from the random in the + * following way: \verbatim privkey = (random >> ((WORD_NBIT - N_MSW_NBIT) & 7)) + 1 \endverbatim, + * where: random is the input random buffer (interpreted as a big-endian integer), + * WORD_NBIT is the bitsize of a cpu word, + * N_MSW_NBIT is the bitlength of the most significant word of the parameter N of the curve. + * @note If P_RandomLen is not enough, an error is returned and P_pPrivKeyLen + * contains the minimum number of bytes of random to provide (and is also + * the minimum length of P_pPrivKey), while P_pPubKeyLen contains the + * minimum length of P_pPubKey. + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + */ +cmox_ecc_retval_t cmox_sm2_keyGen(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pRandom, + size_t P_RandomLen, + uint8_t *P_pPrivKey, + size_t *P_pPrivKeyLen, + uint8_t *P_pPubKey, + size_t *P_pPubKeyLen); + +/** + * @brief Compute ZA = HASH(ENTLA || IDA || a || b || xG || yG || xA || yA), that is the value to hash, together + * with the message, to obtain the digest to provide to \ref cmox_sm2_sign and \ref cmox_sm2_verify + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SM2_LOWMEM + * @arg CMOX_ECC_SM2_HIGHMEM + * @arg CMOX_ECC_SM2TEST_LOWMEM + * @arg CMOX_ECC_SM2TEST_HIGHMEM + * @param[in] P_pIDA Buffer with ID (e.g. email "user@domain.com") of the user + * @param[in] P_ENTLA Bit length of the user ID (usually, multiple of 8) + * @param[in] P_pPubKey Buffer with the public key (both X and Y) + * @param[in] P_PubKeyLen Byte length of the public key + * @param[out] P_pZA Buffer with ZA + * @param[out] P_pZALen Byte length of ZA (optional parameter) + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + */ +cmox_ecc_retval_t cmox_sm2_computeZA(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pIDA, + uint16_t P_ENTLA, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen, + uint8_t *P_pZA, + size_t *P_pZALen); + +/** + * @brief Generate a signature, using ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SM2_LOWMEM + * @arg CMOX_ECC_SM2_HIGHMEM + * @arg CMOX_ECC_SM2TEST_LOWMEM + * @arg CMOX_ECC_SM2TEST_HIGHMEM + * @param[in] P_pRandom Buffer of random bytes + * @param[in] P_RandomLen Byte length of the random buffer + * @param[in] P_pPrivKey Buffer with the private key + * @param[in] P_PrivKeyLen Byte length of the private key + * @param[in] P_pDigest Buffer with the digest to sign + * @param[in] P_DigestLen Byte length of the digest + * @param[out] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[out] P_pSignatureLen Byte length of the signature + * @note the internal value k, used as scalar and multiplied by the base point, is derived from the random in the + * following way: \verbatim k = (random >> ((WORD_NBIT - N_MSW_NBIT) & 7)) + 1 \endverbatim, + * where: random is the input random buffer (interpreted as a big-endian integer), + * WORD_NBIT is the bitsize of a cpu word, + * N_MSW_NBIT is the bitlength of the most significant word of the parameter N of the curve. + * @note If P_RandomLen is not enough, an error is returned and + * P_pSignatureLen contains the minimum number of bytes of random + * to provide (and is also the minimum length of P_pPrivKey, and + * half the length of P_pSignature). + * @retval CMOX_ECC_SUCCESS Everything OK + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + */ +cmox_ecc_retval_t cmox_sm2_sign(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pRandom, + size_t P_RandomLen, + const uint8_t *P_pPrivKey, + size_t P_PrivKeyLen, + const uint8_t *P_pDigest, + size_t P_DigestLen, + uint8_t *P_pSignature, + size_t *P_pSignatureLen); + +/** + * @brief Verify a signature, using ECDSA + * @param[in] P_pEccCtx Context for ECC operations + * @param[in] P_CurveParams Curve Parameters and point functions + * This parameter can be one of the following: + * @arg CMOX_ECC_SM2_LOWMEM + * @arg CMOX_ECC_SM2_HIGHMEM + * @arg CMOX_ECC_SM2TEST_LOWMEM + * @arg CMOX_ECC_SM2TEST_HIGHMEM + * @param[in] P_pPubKey Buffer with the public key + * @param[in] P_PubKeyLen Byte length of the public key + * @param[in] P_pDigest Buffer with the digest to sign + * @param[in] P_DigestLen Byte length of the digest + * @param[in] P_pSignature Buffer with the signature (concatenation of R and S) + * @param[in] P_SignatureLen Byte length of the signature + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_ECC_AUTH_SUCCESS Signature verified + * @retval CMOX_ECC_AUTH_FAIL Signature NOT verified + * @retval CMOX_ECC_ERR_MATHCURVE_MISMATCH Mathematical function set is not compatible with current ECC curve + * @retval CMOX_ECC_ERR_ALGOCURVE_MISMATCH Curve is not compatible with current functionality + * @retval CMOX_ECC_ERR_BAD_PARAMETERS Some NULL/wrong/empty parameter or Construct API not called + * @retval CMOX_ECC_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_ECC_ERR_INVALID_SIGNATURE Input signature corrupted or not in the expected format + * @retval CMOX_ECC_ERR_INVALID_PUBKEY Public key not in a valid format + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_ecc_retval_t cmox_sm2_verify(cmox_ecc_handle_t *P_pEccCtx, + const cmox_ecc_impl_t P_CurveParams, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen, + const uint8_t *P_pDigest, + size_t P_DigestLen, + const uint8_t *P_pSignature, + size_t P_SignatureLen, + uint32_t *P_pFaultCheck); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CMOX_SM2_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_hash.h b/firmware/ui/dependencies/cmox/include/hash/cmox_hash.h new file mode 100644 index 00000000..4faad30e --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_hash.h @@ -0,0 +1,278 @@ +/** + ****************************************************************************** + * @file cmox_hash.h + * @author MCD Application Team + * @brief Header file for the Hash module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_HASH_H +#define CMOX_HASH_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include +#include +#include "cmox_hash_retvals.h" + +/** @addtogroup CMOX_HASH + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_HASH_PUBLIC_TYPES Hash module public types + * @{ + */ + +/** + * @brief Hash Virtual Table + * + * This type specifies a pointer to the virtual table containing the methods + * for a particular algorithm (e.g. SHA256 or SM3) + */ +typedef const struct cmox_hash_vtableStruct_st *cmox_hash_vtable_t; + +/** + * @brief Hash algorithm type + * + * This type specifies the algorithm to use with the hash module (e.g. SHA256). + * The type is defined as a pointer to a structure, that + * contains the functions for the specific algorithm, defined in the library + * internally + */ +typedef const struct cmox_hash_algoStruct_st *cmox_hash_algo_t; + + +/** + * @brief Hash handle structure definition + */ +typedef struct +{ + cmox_hash_vtable_t table; /*!< Hash virtual table */ + size_t tagLen; /*!< Size in bytes of the digest */ +} cmox_hash_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_HASH_PUBLIC_CONSTANTS Hash public constants + * @{ + */ + +/** + * @brief Identifier of the SHA1 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA1_ALGO; + +/** + * @brief Identifier of the SHA224 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA224_ALGO; + +/** + * @brief Identifier of the SHA256 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA256_ALGO; + +/** + * @brief Identifier of the SHA384 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA384_ALGO; + +/** + * @brief Identifier of the SHA512 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA512_ALGO; + +/** + * @brief Identifier of the SHA512/224 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA512_224_ALGO; + +/** + * @brief Identifier of the SHA512/256 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA512_256_ALGO; + +/** + * @brief Identifier of the SHA3-224 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA3_224_ALGO; + +/** + * @brief Identifier of the SHA3-256 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA3_256_ALGO; + +/** + * @brief Identifier of the SHA3-384 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA3_384_ALGO; + +/** + * @brief Identifier of the SHA3-512 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHA3_512_ALGO; + +/** + * @brief Identifier of the SHAKE128 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHAKE128_ALGO; + +/** + * @brief Identifier of the SHAKE256 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SHAKE256_ALGO; + +/** + * @brief Identifier of the SM3 hash function for single-call function + * (Defined internally) + */ +extern const cmox_hash_algo_t CMOX_SM3_ALGO; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_HASH_PUBLIC_METHODS Hash public method prototypes + * @{ + */ + +/** + * @brief Cleanup the hash handler + * + * @param P_pThis Hash handler to cleanup + * @return cmox_hash_retval_t Hash return value + */ +cmox_hash_retval_t cmox_hash_cleanup(cmox_hash_handle_t *P_pThis); + +/** + * @brief Initialize the hash handle based on the selected algorithm + * + * @param P_pThis Hash handle to initialize + * @return cmox_hash_retval_t Hash return value + * @note The hash handle must be derived from an algorithm-specific handle + * using the correct construct + */ +cmox_hash_retval_t cmox_hash_init(cmox_hash_handle_t *P_pThis); + +/** + * @brief Set the size of the digest + * + * @param P_pThis Hash handle to set + * @param P_tagLen Size in bytes of the tag + * @return cmox_hash_retval_t Hash return value + */ +cmox_hash_retval_t cmox_hash_setTagLen(cmox_hash_handle_t *P_pThis, + size_t P_tagLen); + +/** + * @brief Append part or the totality of the plaintext to the hash handle + * + * @param P_pThis Hash handle to use for hashing the data + * @param P_pInput Buffer of bytes containing the data to hash + * @param P_inputLen Size in bytes of the data to hash + * @return cmox_hash_retval_t Hash return value + */ +cmox_hash_retval_t cmox_hash_append(cmox_hash_handle_t *P_pThis, + const uint8_t *P_pInput, + size_t P_inputLen); + +/** + * @brief Generate the digest of the already appended data + * + * @param P_pThis Hash handle used for appending the data to hash + * @param P_pDigest Buffer of bytes where the digest will be stored + * @param P_pDigestLen Number of bytes generated by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_hash_retval_t Hash return value + */ +cmox_hash_retval_t cmox_hash_generateTag(cmox_hash_handle_t *P_pThis, + uint8_t *P_pDigest, + size_t *P_pDigestLen); + +/** + * @brief Compute the digest of a message using a hash algorithm + * + * @param P_algo Identifier of the hash algorithm to use for the computation. + * This parameter can be one of the following: + * @arg CMOX_SHA1_ALGO + * @arg CMOX_SHA224_ALGO + * @arg CMOX_SHA256_ALGO + * @arg CMOX_SHA384_ALGO + * @arg CMOX_SHA512_ALGO + * @arg CMOX_SHA512_224_ALGO + * @arg CMOX_SHA512_256_ALGO + * @arg CMOX_SHA3_224_ALGO + * @arg CMOX_SHA3_256_ALGO + * @arg CMOX_SHA3_384_ALGO + * @arg CMOX_SHA3_512_ALGO + * @arg CMOX_SHAKE128_ALGO + * @arg CMOX_SHAKE256_ALGO + * @arg CMOX_SM3_ALGO + * @param P_pPlaintext Buffer of bytes containing the message to hash + * @param P_plaintextLen Size in bytes of the message to hash + * @param P_pDigest Buffer of bytes that will contain the computed digest + * @param P_expectedDigestLen Desired size in bytes of the digest to compute + * @param P_pComputedDigestLen Number of bytes generated by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_hash_retval_t + */ +cmox_hash_retval_t cmox_hash_compute(cmox_hash_algo_t P_algo, + const uint8_t *P_pPlaintext, + size_t P_plaintextLen, + uint8_t *P_pDigest, + const size_t P_expectedDigestLen, + size_t *P_pComputedDigestLen); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_HASH_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_hash_retvals.h b/firmware/ui/dependencies/cmox/include/hash/cmox_hash_retvals.h new file mode 100644 index 00000000..efae74d4 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_hash_retvals.h @@ -0,0 +1,90 @@ +/** + ****************************************************************************** + * @file cmox_hash_retvals.h + * @author MCD Application Team + * @brief Header file containing the return values for the hash module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_HASH_RETVALS_H +#define CMOX_HASH_RETVALS_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include + +/** @addtogroup CMOX_HASH + * @{ + */ + +/** @defgroup CMOX_HASH_RETVALS Hash return values + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** + * @brief Hash operation successfully performed + */ +#define CMOX_HASH_SUCCESS ((cmox_hash_retval_t)0x00020000U) + +/** + * @brief Some error happens internally in the hash module + */ +#define CMOX_HASH_ERR_INTERNAL ((cmox_hash_retval_t)0x00020001U) + +/** + * @brief One or more parameter has been wrongly passed to the function + * (e.g. pointer to NULL) + */ +#define CMOX_HASH_ERR_BAD_PARAMETER ((cmox_hash_retval_t)0x00020003U) + +/** + * @brief Error on performing the operation + * (e.g. an operation has been called before initializing the handle) + */ +#define CMOX_HASH_ERR_BAD_OPERATION ((cmox_hash_retval_t)0x00020004U) + +/** + * @brief The desired digest size is not supported by the hash alforithm + */ +#define CMOX_HASH_ERR_BAD_TAG_SIZE ((cmox_hash_retval_t)0x00020006U) + +/* Public types --------------------------------------------------------------*/ + +/** + * @brief Hash module return value type + */ +typedef uint32_t cmox_hash_retval_t; + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_HASH_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_md.h b/firmware/ui/dependencies/cmox/include/hash/cmox_md.h new file mode 100644 index 00000000..cf62e1b3 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_md.h @@ -0,0 +1,127 @@ +/** + ****************************************************************************** + * @file cmox_md.h + * @author MCD Application Team + * @brief Header file containing the definitions for MD hash functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_MD_H +#define CMOX_MD_H + +#include "cmox_hash.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_HASH + * @{ + */ + +/** + * @defgroup CMOX_MD MD hash module + * @{ + */ + +/* Public types --------------------------------------------------------------*/ + +/** + * @defgroup CMOX_MD_PUBLIC_TYPES MD public types + * @{ + */ + +/** + * @brief MD Virtual Table + * + * This type specifies a pointer to the virtual table containing the methods + * for the particular MD algorithm + */ +typedef const struct cmox_md_vtableStruct_st *cmox_md_vtable_t; + +/** + * @brief MD engine common structure definition + */ +typedef struct +{ + cmox_md_vtable_t table; /*!< MD virtual table */ + uint32_t flags; /*!< 32 bit flags, used to perform keyschedule */ + size_t tagLen; /*!< Size of the required Digest */ + size_t blockLen; /*!< Internal: Size of processed blocks */ + size_t labelLen; /*!< Internal: Size of the final label of the MD padding scheme */ + uint32_t bitCount[2]; /*!< Internal: Keeps the count of processed bits */ +} cmox_md_engineCommon_t; + +/** + * @brief MD small engine structure definition + * (Used by SHA1, SHA224, SHA256, SM3) + */ +typedef struct +{ + cmox_md_engineCommon_t engine; /*!< Engine of the MD function */ + uint8_t internalBuffer[64]; /*!< Internal: It's a buffer with the data to be hashed */ + uint32_t internalState[8]; /*!< Internal: Keeps the internal state */ +} cmox_mdSmall_engine_t; + +/** + * @brief MD large engine structure definition (Used by SHA384, SHA512) + */ +typedef struct +{ + cmox_md_engineCommon_t engine; /*!< Engine of the MD function */ + uint8_t internalBuffer[128]; /*!< Internal: It's a buffer with the data to be hashed */ + uint64_t internalState[8]; /*!< Internal: Keeps the internal state */ +} cmox_mdLarge_engine_t; + +/** + * @brief Generic MD small handle structure + */ +typedef struct +{ + cmox_hash_handle_t super; /*!< General hash module */ + cmox_mdSmall_engine_t md; /*!< MD small engine */ +} cmox_mdSmall_handle_t; + +/** + * @brief Generic MD large handle structure + */ +typedef struct +{ + cmox_hash_handle_t super; /*!< General hash module */ + cmox_mdLarge_engine_t md; /*!< MD large engine */ +} cmox_mdLarge_handle_t; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_MD_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha1.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha1.h new file mode 100644 index 00000000..25a18ead --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha1.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * @file cmox_sha1.h + * @author MCD Application Team + * @brief Header file for the SHA1 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA1_H +#define CMOX_SHA1_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SHA1 SHA1 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA1_MACROS SHA1 macros + * @{ + */ + +#define CMOX_SHA1_SIZE 20U /*!< Maximum size in bytes of a SHA1 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA1_PUBLIC_TYPES SHA1 module public types + * @{ + */ + +/** + * @brief SHA1 handle type definition + */ +typedef cmox_mdSmall_handle_t cmox_sha1_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA1_PUBLIC_METHODS SHA1 module public method prototypes + * @{ + */ + +/** + * @brief SHA1 constructor + * + * @param P_pThis Pointer to the SHA1 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha1_construct(cmox_sha1_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA1_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha224.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha224.h new file mode 100644 index 00000000..2ef1d1e2 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha224.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * @file cmox_sha224.h + * @author MCD Application Team + * @brief Header file for the SHA224 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA224_H +#define CMOX_SHA224_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SHA224 SHA224 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA224_MACROS SHA224 macros + * @{ + */ + +#define CMOX_SHA224_SIZE 28U /*!< Maximum size in bytes of a SHA224 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA224_PUBLIC_TYPES SHA224 module public types + * @{ + */ + +/** + * @brief SHA224 handle type definition + */ +typedef cmox_mdSmall_handle_t cmox_sha224_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA224_PUBLIC_METHODS SHA224 module public method prototypes + * @{ + */ + +/** + * @brief SHA224 constructor + * + * @param P_pThis Pointer to the SHA224 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha224_construct(cmox_sha224_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA224_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha256.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha256.h new file mode 100644 index 00000000..b36b49d1 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha256.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * @file cmox_sha256.h + * @author MCD Application Team + * @brief Header file for the SHA256 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA256_H +#define CMOX_SHA256_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SHA256 SHA256 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA256_MACROS SHA256 macros + * @{ + */ + +#define CMOX_SHA256_SIZE 32U /*!< Maximum size in bytes of a SHA256 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA256_PUBLIC_TYPES SHA256 module public types + * @{ + */ + +/** + * @brief SHA256 handle type definition + */ +typedef cmox_mdSmall_handle_t cmox_sha256_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA256_PUBLIC_METHODS SHA256 module public method prototypes + * @{ + */ + +/** + * @brief SHA256 constructor + * + * @param P_pThis Pointer to the SHA256 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha256_construct(cmox_sha256_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA256_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha3.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha3.h new file mode 100644 index 00000000..7c055716 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha3.h @@ -0,0 +1,162 @@ +/** + ****************************************************************************** + * @file cmox_sha3.h + * @author MCD Application Team + * @brief Header file for SHA3 and SHAKE hash functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA3_H +#define CMOX_SHA3_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_sponge.h" + +/** + * @addtogroup CMOX_HASH + * @{ + */ + +/** + * @defgroup CMOX_SHA3 SHA3 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA3_MACROS SHA3 macros + * @{ + */ + +#define CMOX_SHA3_224_SIZE 28U /*!< Number of bytes (uint8_t) to store a SHA3-224 digest. */ +#define CMOX_SHA3_256_SIZE 32U /*!< Number of bytes (uint8_t) to store a SHA3-256 digest. */ +#define CMOX_SHA3_384_SIZE 48U /*!< Number of bytes (uint8_t) to store a SHA3-384 digest. */ +#define CMOX_SHA3_512_SIZE 64U /*!< Number of bytes (uint8_t) to store a SHA3-512 digest. */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA3_PUBLIC_TYPES SHA3 module public types + * @{ + */ + +/** + * @brief SHA3 handle type definition + */ +typedef struct +{ + cmox_hash_handle_t super; /*!< General hash module */ + uint32_t flags; /*!< Internal flag */ + cmox_sponge_handle_t keccak; /*!< Keccak P-1600 handler */ +} cmox_sha3_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA3_PUBLIC_METHODS SHA3 module public method prototypes + * @{ + */ + +/** + * @brief SHA3-224 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha3_224_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @brief SHA3-256 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha3_256_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @brief SHA3-384 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha3_384_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @brief SHA3-512 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha3_512_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @brief SHAKE128 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_shake128_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @brief SHAKE256 constructor + * + * @param P_pThis Pointer to the SHA3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_shake256_construct(cmox_sha3_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA3_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha384.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha384.h new file mode 100644 index 00000000..dc994085 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha384.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * @file cmox_sha384.h + * @author MCD Application Team + * @brief Header file for the SHA384 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA384_H +#define CMOX_SHA384_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SHA384 SHA384 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA384_MACROS SHA384 macros + * @{ + */ + +#define CMOX_SHA384_SIZE 48U /*!< Maximum size in bytes of a SHA384 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA384_PUBLIC_TYPES SHA384 module public types + * @{ + */ + +/** + * @brief SHA384 handle type definition + */ +typedef cmox_mdLarge_handle_t cmox_sha384_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA384_PUBLIC_METHODS SHA384 module public method prototypes + * @{ + */ + +/** + * @brief SHA384 constructor + * + * @param P_pThis Pointer to the SHA384 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha384_construct(cmox_sha384_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA384_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sha512.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sha512.h new file mode 100644 index 00000000..28e46b08 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sha512.h @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * @file cmox_sha512.h + * @author MCD Application Team + * @brief Header file for the SHA512 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SHA512_H +#define CMOX_SHA512_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SHA512 SHA512 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA512_MACROS SHA512 macros + * @{ + */ + +#define CMOX_SHA512_SIZE 64U /*!< Maximum size in bytes of a SHA512 digest */ +#define CMOX_SHA512_224_SIZE 28U /*!< Maximum size in bytes of a SHA512/224 digest */ +#define CMOX_SHA512_256_SIZE 32U /*!< Maximum size in bytes of a SHA512/256 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SHA512_PUBLIC_TYPES SHA512 module public types + * @{ + */ + +/** + * @brief SHA512 handle type definition + */ +typedef cmox_mdLarge_handle_t cmox_sha512_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SHA512_PUBLIC_METHODS SHA512 module public method prototypes + * @{ + */ + +/** + * @brief SHA512 constructor + * + * @param P_pThis Pointer to the SHA512 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha512_construct(cmox_sha512_handle_t *P_pThis); + +/** + * @brief SHA512/224 constructor + * + * @param P_pThis Pointer to the SHA512 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha512_224_construct(cmox_sha512_handle_t *P_pThis); + +/** + * @brief SHA512/256 constructor + * + * @param P_pThis Pointer to the SHA512 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sha512_256_construct(cmox_sha512_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SHA512_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sm3.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sm3.h new file mode 100644 index 00000000..fe0c3667 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sm3.h @@ -0,0 +1,105 @@ +/** + ****************************************************************************** + * @file cmox_sm3.h + * @author MCD Application Team + * @brief Header file for the SM3 hash definition and function + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_SM3_H +#define CMOX_SM3_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include "cmox_hash.h" +#include "cmox_md.h" + +/** + * @addtogroup CMOX_MD + * @{ + */ + +/** + * @defgroup CMOX_SM3 SM3 hash module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SM3_MACROS SM3 macros + * @{ + */ + +#define CMOX_SM3_SIZE 32U /*!< Maximum size in bytes of a SM3 digest */ + +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SM3_PUBLIC_TYPES SM3 module public types + * @{ + */ + +/** + * @brief SM3 handle type definition + */ +typedef cmox_mdSmall_handle_t cmox_sm3_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_SM3_PUBLIC_METHODS SM3 module public method prototypes + * @{ + */ + +/** + * @brief SM3 constructor + * + * @param P_pThis Pointer to the SM3 handle to initialize + * @return cmox_hash_handle_t* Pointer to a general hash handle. This will be + * used by the general purpose hash functions in order to perform + * the algorithm + */ +cmox_hash_handle_t *cmox_sm3_construct(cmox_sm3_handle_t *P_pThis); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_SM3_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/hash/cmox_sponge.h b/firmware/ui/dependencies/cmox/include/hash/cmox_sponge.h new file mode 100644 index 00000000..46580821 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/hash/cmox_sponge.h @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * @file cmox_sponge.h + * @author MCD Application Team + * @brief Header file for the Keccak sponge definitions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_SPONGE_H +#define CMOX_SPONGE_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_SHA3 + * @{ + */ + +/** + * @defgroup CMOX_SPONGE Sponge module + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** @defgroup CMOX_SPONGE_MACROS Sponge macros + * @{ + */ +#define CMOX_SHA3_STATE_SIZE 200U /*!< Keccak-P 1600 state size in bytes */ +/** + * @} + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_SPONGE_PUBLIC_TYPES Sponge module public types + * @{ + */ + +/** + * @brief Structure for Keccak-P 1600 sponge + */ +typedef struct +{ + uint8_t state[CMOX_SHA3_STATE_SIZE]; /*!< Internal state for Keccak P-1600 */ + uint32_t rate; /*!< Rate */ + uint32_t byteIOIndex; /*!< Index for the IO bytes */ + uint32_t squeezing; /*!< flag identifying if the operation is a squeezing */ +} cmox_sponge_handle_t; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_SPONGE_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/mac/cmox_cmac.h b/firmware/ui/dependencies/cmox/include/mac/cmox_cmac.h new file mode 100644 index 00000000..0aeb3565 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/mac/cmox_cmac.h @@ -0,0 +1,169 @@ +/** + ****************************************************************************** + * @file cmox_cmac.h + * @author MCD Application Team + * @brief Header file for the CMAC algorithm definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_CMAC_H +#define CMOX_CMAC_H + +/* Include files -------------------------------------------------------------*/ +#include "cmox_mac.h" +#include "cipher/cmox_blockcipher.h" + +#include "cipher/cmox_check_default_aes.h" +#include "cmox_default_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_MAC + * @{ + */ + +/** @defgroup CMOX_CMAC CMAC + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_CMAC_PUBLIC_TYPES CMAC public types + * @{ + */ + +/** + * @brief CMAC implementation + * + * This type specifies the used block cipher for the CMAC construct. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_cmac_implStruct_st *cmox_cmac_impl_t; + +/** + * @brief CMAC handle structure definition + */ +typedef struct +{ + cmox_mac_handle_t super; /*!< General MAC handle */ + cmox_blockcipher_handle_t blockCipher; /*!< Block cipher handle */ + uint32_t iv[CMOX_CIPHER_BLOCK_SIZE]; /*!< Buffer containing the Initialization Vector */ + uint8_t temp_buffer[16]; /*!< Temporary buffer to storing unprocessed data */ + uint32_t unprocessed_bytes; /*!< Number of bytes in the temporary buffer */ +} cmox_cmac_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_CMAC_PUBLIC_CONSTANTS CMAC public constants + * @{ + */ + +/** @defgroup CMOX_CMAC_IMPL CMAC implementations + * @{ + */ + +/** + * @brief Implementation of CMAC using AES (small implementation) + * (Defined internally) + */ +extern const cmox_cmac_impl_t CMOX_CMAC_AESSMALL; + +/** + * @brief Implementation of CMAC using AES (fast implementation) + * (Defined internally) + */ +extern const cmox_cmac_impl_t CMOX_CMAC_AESFAST; + +/** + * @} + */ + +/** @defgroup CMOX_CMAC_ALGO CMAC single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the CMAC using AES (fast implementation) + * for single-call function (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_CMAC_AESFAST_ALGO; + +/** + * @brief Identifier of the CMAC using AES (small implementation) + * for single-call function (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_CMAC_AESSMALL_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_CMAC_PUBLIC_METHODS CMAC public method prototypes + * @{ + */ + +/** + * @brief CMAC constructor + * + * The function is used for specifying which block cipher algorithm to use in + * order to implement the CMAC algorithm. + * + * @param P_pThis Pointer to the CMAC handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter shall be set with the following value: + * @arg CMOX_CMAC_AESFAST + * @arg CMOX_CMAC_AESSMALL + * @return cmox_mac_handle_t* Pointer to a general MAC handle. This will + * be used by the general purpose MAC functions in order to + * perform the algorithm + */ +cmox_mac_handle_t *cmox_cmac_construct(cmox_cmac_handle_t *P_pThis, + cmox_cmac_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_CMAC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/mac/cmox_hmac.h b/firmware/ui/dependencies/cmox/include/mac/cmox_hmac.h new file mode 100644 index 00000000..55c823ec --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/mac/cmox_hmac.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file cmox_hmac.h + * @author MCD Application Team + * @brief Header file for the HMAC algorithm + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_HMAC_H +#define CMOX_HMAC_H + +/* Include files -------------------------------------------------------------*/ +#include "cmox_mac.h" +#include "hash/cmox_md.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_MAC + * @{ + */ + +/** @defgroup CMOX_HMAC HMAC + * @{ + */ + +/* Public macros -------------------------------------------------------------*/ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_HMAC_PUBLIC_TYPES HMAC public types + * @{ + */ + +/** + * @brief HMAC implementation + * + * This type specifies the used hash function for the HMAC construct. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_hmac_implStruct_st *cmox_hmac_impl_t; + +/** + * @brief HMAC internal support functions + * + * This type specifies some functions used internally by the HMAC in order to + * correctly compute the MAC. The structure pointed by the type is defined + * in the library internally + */ +typedef const struct cmox_hmac_supportStruct_st *cmox_hmac_support_t; + +/** + * @brief HMAC handle structure definition + */ +typedef struct +{ + cmox_mac_handle_t super; /*!< General MAC handle */ + + /** + * @brief Hash function handle + * + * Depending on the chosen hash function, one of the two fields of the union + * will be used. + */ + union + { + cmox_mdSmall_handle_t md_small; /*!< Handle for SHA-224, SHA-256, SM3 */ + cmox_mdLarge_handle_t md_large; /*!< Handle for SHA-384, SHA-512 */ + } hash_context; + + cmox_hash_handle_t *hash; /*!< Pointer to general hash handle */ + uint8_t key[128]; /*!< Buffer of bytes containing the derivated key */ + cmox_hmac_support_t support; /*!< Support functions for HMAC computation */ +} cmox_hmac_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_HMAC_PUBLIC_CONSTANTS HMAC public constants + * @{ + */ + +/** @defgroup CMOX_HMAC_IMPL HMAC implementations + * @{ + */ + +/** + * @brief Implementation of HMAC using SHA-1 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA1; + +/** + * @brief Implementation of HMAC using SHA-224 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA224; + +/** + * @brief Implementation of HMAC using SHA-256 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA256; + +/** + * @brief Implementation of HMAC using SHA-384 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA384; + +/** + * @brief Implementation of HMAC using SHA-512 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA512; + +/** + * @brief Implementation of HMAC using SHA-512/224 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA512_224; + +/** + * @brief Implementation of HMAC using SHA-512/256 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SHA512_256; + +/** + * @brief Implementation of HMAC using SM3 (Defined internally) + */ +extern const cmox_hmac_impl_t CMOX_HMAC_SM3; + + +/** + * @} + */ + +/** @defgroup CMOX_HMAC_ALGO HMAC single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the HMAC-SHA1 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA1_ALGO; + +/** + * @brief Identifier of the HMAC-SHA224 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA224_ALGO; + +/** + * @brief Identifier of the HMAC-SHA256 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA256_ALGO; + +/** + * @brief Identifier of the HMAC-SHA384 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA384_ALGO; + +/** + * @brief Identifier of the HMAC-SHA512 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA512_ALGO; + +/** + * @brief Identifier of the HMAC-SHA512/224 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA512_224_ALGO; + +/** + * @brief Identifier of the HMAC-SHA512/256 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SHA512_256_ALGO; + +/** + * @brief Identifier of the HMAC-SM3 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_HMAC_SM3_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_HMAC_PUBLIC_METHODS HMAC public method prototypes + * @{ + */ + +/** + * @brief HMAC constructor + * + * The function is used for specifying which hash function to use in + * order to implement the HMAC algorithm. + * + * @param P_pThis Pointer to the HMAC handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_HMAC_SHA1 + * @arg CMOX_HMAC_SHA224 + * @arg CMOX_HMAC_SHA256 + * @arg CMOX_HMAC_SHA384 + * @arg CMOX_HMAC_SHA512 + * @arg CMOX_HMAC_SHA512_224 + * @arg CMOX_HMAC_SHA512_256 + * @arg CMOX_HMAC_SM3 + * @return cmox_mac_handle_t* Pointer to a general MAC handle. This will + * be used by the general purpose MAC functions in order to + * perform the algorithm + */ +cmox_mac_handle_t *cmox_hmac_construct(cmox_hmac_handle_t *P_pThis, + cmox_hmac_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_HMAC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/mac/cmox_kmac.h b/firmware/ui/dependencies/cmox/include/mac/cmox_kmac.h new file mode 100644 index 00000000..1f952444 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/mac/cmox_kmac.h @@ -0,0 +1,190 @@ +/** + ****************************************************************************** + * @file cmox_kmac.h + * @author MCD Application Team + * @brief Header file for the KMAC algorithm definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_KMAC_H +#define CMOX_KMAC_H + +/* Include files -------------------------------------------------------------*/ +#include "cmox_mac.h" +#include "hash/cmox_sponge.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_MAC + * @{ + */ + +/** @defgroup CMOX_KMAC KMAC + * @{ + */ + +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_KMAC_PUBLIC_TYPES KMAC public types + * @{ + */ + +/** + * @brief KMAC implementation + * + * This type specifies the implementation to use for the KMAC construct. + * This type is defined as a pointer to a structure, that contains the + * functions needed for the specific implementation, defined in the library + * internally + */ +typedef const struct cmox_kmac_implStruct_st *cmox_kmac_impl_t; + +/** + * @brief Keccak-P phases + */ +typedef uint32_t cmox_keccak_phase_t; + +/** + * @brief Structure defining the cSHAKE context + */ +typedef struct +{ + cmox_sponge_handle_t sponge; /*!< Sponge context */ + uint32_t fixedOutputLength; /*!< Fixed output length in bits */ + uint32_t lastByteBitLen; /*!< Last byte bit length */ + uint8_t lastByteValue; /*!< Last byte value */ + cmox_keccak_phase_t phase; /*!< Phase */ +} cmox_cshake_handle_t; + +/** + * @brief Structure defining the KMAC inner context + */ +typedef struct +{ + cmox_cshake_handle_t csi; /*!< cSHAKE context */ + size_t outputBitLen; /*!< Output length in bits */ +} cmox_kmac_inner_t; + + +/** + * @brief KMAC handle structure definition + */ +typedef struct +{ + cmox_mac_handle_t super; /*!< General MAC handle */ + const uint8_t *custom_data; /*!< Pointer to buffer containing custom data */ + size_t customDataLen; /*!< Size in bytes of the custom data */ + cmox_kmac_inner_t internal_ctx; /*!< Internal handle for KMAC */ + cmox_kmac_impl_t impl; /*!< Implementation of KMAC */ +} cmox_kmac_handle_t; + +/** + * @} + */ + +/* Public constants ----------------------------------------------------------*/ + +/** @defgroup CMOX_KMAC_PUBLIC_CONSTANTS KMAC public constants + * @{ + */ + +/** @defgroup CMOX_KMAC_IMPL KMAC implementations + * @{ + */ + +/** + * @brief Implementation of KMAC-128 algorithm (Defined internally) + */ +extern const cmox_kmac_impl_t CMOX_KMAC_128; + +/** + * @brief Implementation of KMAC-256 algorithm (Defined internally) + */ +extern const cmox_kmac_impl_t CMOX_KMAC_256; + +/** + * @} + */ + +/** @defgroup CMOX_KMAC_ALGO KMAC single-call algorithms + * @{ + */ + +/** + * @brief Identifier of the KMAC-128 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_KMAC_128_ALGO; + +/** + * @brief Identifier of the KMAC-256 mac algorithm for single-call function + * (Defined internally) + */ +extern const cmox_mac_algo_t CMOX_KMAC_256_ALGO; + +/** + * @} + */ + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_KMAC_PUBLIC_METHODS KMAC public method prototypes + * @{ + */ + +/** + * @brief KMAC constructor + * + * The function is used for specifying which KMAC implementation to use in + * order to implement the MAC algorithm. + * + * @param P_pThis Pointer to the KMAC handle to initialize + * @param P_impl Constant that specifies the implementation to use. + * This parameter can be one of the following values: + * @arg CMOX_KMAC_128 + * @arg CMOX_KMAC_256 + * @return cmox_mac_handle_t* Pointer to a general MAC handle. This will + * be used by the general purpose MAC functions in order to + * perform the algorithm + */ +cmox_mac_handle_t *cmox_kmac_construct(cmox_kmac_handle_t *P_pThis, + cmox_kmac_impl_t P_impl); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_KMAC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/mac/cmox_mac.h b/firmware/ui/dependencies/cmox/include/mac/cmox_mac.h new file mode 100644 index 00000000..f83b6b75 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/mac/cmox_mac.h @@ -0,0 +1,284 @@ +/** + ****************************************************************************** + * @file cmox_mac.h + * @author MCD Application Team + * @brief Header file for the MAC module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_MAC_H +#define CMOX_MAC_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Include files -------------------------------------------------------------*/ +#include +#include +#include "cmox_mac_retvals.h" + +/** @addtogroup CMOX_MAC + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ +/* Public types --------------------------------------------------------------*/ + +/** @defgroup CMOX_MAC_PUBLIC_TYPES MAC module public types + * @{ + */ + +/** + * @brief MAC Virtual Table + * + * This type specifies a pointer to the virtual table containing the methods + * for a particular algorithm (e.g. HMAC-256 or CMAC) + */ +typedef const struct cmox_mac_vtableStruct_st *cmox_mac_vtable_t; + +/** + * @brief MAC algorithm type + * + * This type specifies the algorithm to use with the MAC module + * (e.g. HMAC-SHA256). The type is defined as a pointer to a structure, that + * contains the functions for the specific algorithm, defined in the library + * internally + */ +typedef const struct cmox_mac_algoStruct_st *cmox_mac_algo_t; + + +/** + * @brief MAC handle structure definition + */ +typedef struct +{ + cmox_mac_vtable_t table; /*!< MAC virtual table */ + size_t tagLen; /*!< Size in bytes of the authenticated tag */ + uint32_t internalState; /*!< MAC internal state */ +} cmox_mac_handle_t; + +/** + * @} + */ + +/* Public methods prototypes -------------------------------------------------*/ + +/** @defgroup CMOX_MAC_PUBLIC_METHODS MAC public method prototypes + * @{ + */ + +/** + * @brief Cleanup the MAC handler + * + * @param P_pThis MAC handler to cleanup + * @return cmox_mac_retval_t MAC return value + */ +cmox_mac_retval_t cmox_mac_cleanup(cmox_mac_handle_t *P_pThis); + +/** + * @brief Initialize the MAC handle based on the selected algorithm + * + * @param P_pThis MAC handle to initialize + * @return cmox_mac_retval_t Hash return value + * @note The MAC handle must be derived from an algorithm-specific handle + * using the correct construct + */ +cmox_mac_retval_t cmox_mac_init(cmox_mac_handle_t *P_pThis); + +/** + * @brief Set the size of the tag + * + * @param P_pThis MAC handle to set + * @param P_tagLen Size in bytes of the tag + * @return cmox_mac_retval_t MAC return value + * @note This function is optional when used for HMAC or CMAC algorithms. If not + * called, the tag length will be set as the default specified by the + * algorithm (e.g. 16 bytes for CMAC) during the initialization phase. + * @note With KMAC algorithm, this function is mandatory and must be called + * before the cmox_mac_setKey function + */ +cmox_mac_retval_t cmox_mac_setTagLen(cmox_mac_handle_t *P_pThis, + size_t P_tagLen); + +/** + * @brief Set the custom data to be combined with the plaintext for the MAC + * computation + * + * @param P_pThis MAC handle to use for computing the authenticated tag + * @param P_pCustomData Buffer of bytes containing the custom data + * @param P_customDataLen Size in bytes of the custom data + * @return cmox_mac_retval_t MAC return value + * @note This function is useful only for KMAC algorithm. It can be called for + * other algorithms but will not produce any results + * @note If the KMAC to compute doesn't need any custom data, this function can + * be skipped. + */ +cmox_mac_retval_t cmox_mac_setCustomData(cmox_mac_handle_t *P_pThis, + const uint8_t *P_pCustomData, + size_t P_customDataLen); + +/** + * @brief Set the key to be used for computing the authenticated tag + * + * @param P_pThis MAC handle to use for computing the authenticated tag + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Size in bytes of the key + * @return cmox_mac_retval_t MAC return value + * @note The KMAC algorithm is specified to be used even without key. However, + * this function is mandatory to be called with the parameter P_keyLen + * set to 0. + */ +cmox_mac_retval_t cmox_mac_setKey(cmox_mac_handle_t *P_pThis, + const uint8_t *P_pKey, + size_t P_keyLen); + +/** + * @brief Append part or the totality of the plaintext to the MAC handle + * + * @param P_pThis MAC handle to use for computing the authenticated tag + * @param P_pInput Buffer of bytes containing the data to append + * @param P_inputLen Size in bytes of the data to append + * @return cmox_hash_retval_t MAC return value + */ +cmox_mac_retval_t cmox_mac_append(cmox_mac_handle_t *P_pThis, + const uint8_t *P_pInput, + size_t P_inputLen); + +/** + * @brief Compute the authenticated tag of the already appended data + * + * @param P_pThis MAC handle where the data has been appended + * @param P_pTag Buffer of bytes where the authenticated tag will be stored + * @param P_pTagLen Number of bytes generated by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_mac_retval_t MAC return value + */ +cmox_mac_retval_t cmox_mac_generateTag(cmox_mac_handle_t *P_pThis, + uint8_t *P_pTag, + size_t *P_pTagLen); + +/** + * @brief Verify the already appended data with the reference tag + * + * @param P_pThis MAC handle where the data has been appended + * @param P_pTag Buffer of bytes containing the reference tag + * @param P_pFaultCheck Optional value to check, together with the retval, + * to verify if some fault happened + * @return cmox_mac_retval_t + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must + * be done against the success value, and not comparing the value with the + * failure value. Indeed, in presence of faults, especially P_pFaultCheck, + * could be a dirty value. + */ +cmox_mac_retval_t cmox_mac_verifyTag(cmox_mac_handle_t *P_pThis, + const uint8_t *P_pTag, + uint32_t *P_pFaultCheck); + +/** + * @brief Compute the authenticated tag of a message using a MAC algorithm + * + * @param P_algo Identifier of the hash algorithm to use for the computation. + * This parameter can be one of the following: + * @arg CMOX_CMAC_AES_ALGO + * @arg CMOX_HMAC_SHA1_ALGO + * @arg CMOX_HMAC_SHA224_ALGO + * @arg CMOX_HMAC_SHA256_ALGO + * @arg CMOX_HMAC_SHA384_ALGO + * @arg CMOX_HMAC_SHA512_ALGO + * @arg CMOX_HMAC_SHA512_224_ALGO + * @arg CMOX_HMAC_SHA512_256_ALGO + * @arg CMOX_HMAC_SM3_ALGO + * @arg CMOX_KMAC_128_ALGO + * @arg CMOX_KMAC_256_ALGO + * @param P_pInput Buffer of bytes containing the message to process + * @param P_inputLen Size in bytes of the message to process + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Size in bytes of the key + * @param P_pCustomData Buffer of bytes containing the custom data + * @param P_customDataLen Size in bytes of the custom data + * @param P_pTag Buffer of bytes where the authenticated tag will be stored + * @param P_expectedTagLen Size in bytes of the tag to compute + * @param P_pComputedTagLen Number of bytes generated by the function. + * It is an optional parameter and can be set to NULL if not needed. + * @return cmox_mac_retval_t + */ +cmox_mac_retval_t cmox_mac_compute(cmox_mac_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + const uint8_t *P_pKey, + size_t P_keyLen, + const uint8_t *P_pCustomData, + size_t P_customDataLen, + uint8_t *P_pTag, + size_t P_expectedTagLen, + size_t *P_pComputedTagLen); + +/** + * @brief Verify the authenticity of a message using a MAC algorithm + * + * @param P_algo Identifier of the hash algorithm to use for the computation. + * This parameter can be one of the following: + * @arg CMOX_CMAC_AES_ALGO + * @arg CMOX_HMAC_SHA1_ALGO + * @arg CMOX_HMAC_SHA224_ALGO + * @arg CMOX_HMAC_SHA256_ALGO + * @arg CMOX_HMAC_SHA384_ALGO + * @arg CMOX_HMAC_SHA512_ALGO + * @arg CMOX_HMAC_SHA512_224_ALGO + * @arg CMOX_HMAC_SHA512_256_ALGO + * @arg CMOX_HMAC_SM3_ALGO + * @arg CMOX_KMAC_128_ALGO + * @arg CMOX_KMAC_256_ALGO + * @param P_pInput Buffer of bytes containing the message to process + * @param P_inputLen Size in bytes of the message to process + * @param P_pKey Buffer of bytes containing the key + * @param P_keyLen Size in bytes of the key + * @param P_pCustomData Buffer of bytes containing the custom data + * @param P_customDataLen Size in bytes of the custom data + * @param P_pReceivedTag Buffer of bytes containing the received tag + * @param P_receivedTagLen Size in bytes of the received tag + * @return cmox_mac_retval_t + */ +cmox_mac_retval_t cmox_mac_verify(cmox_mac_algo_t P_algo, + const uint8_t *P_pInput, + size_t P_inputLen, + const uint8_t *P_pKey, + size_t P_keyLen, + const uint8_t *P_pCustomData, + size_t P_customDataLen, + const uint8_t *P_pReceivedTag, + size_t P_receivedTagLen); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_MAC_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/mac/cmox_mac_retvals.h b/firmware/ui/dependencies/cmox/include/mac/cmox_mac_retvals.h new file mode 100644 index 00000000..e2dac17d --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/mac/cmox_mac_retvals.h @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @file cmox_mac_retvals.h + * @author MCD Application Team + * @brief return values for MAC functionality + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CMOX_MAC_RETVALS_H +#define CMOX_MAC_RETVALS_H + +/* Include files -------------------------------------------------------------*/ +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_MAC + * @{ + */ + +/** @defgroup CMOX_MAC_RETVALS MAC return values + * @{ + */ + +/* Macros --------------------------------------------------------------------*/ + +/** + * @brief MAC operation successfully performed + */ +#define CMOX_MAC_SUCCESS ((cmox_mac_retval_t)0x00030000U) + + +/** + * @brief Some error happens internally in the MAC module + */ +#define CMOX_MAC_ERR_INTERNAL ((cmox_mac_retval_t)0x00030001U) + +/** + * @brief One or more parameter has been wrongly passed to the function + * (e.g. pointer to NULL) + */ +#define CMOX_MAC_ERR_BAD_PARAMETER ((cmox_mac_retval_t)0x00030002U) + +/** + * @brief Error on performing the operation + * (e.g. an operation has been called before initializing the handle) + */ +#define CMOX_MAC_ERR_BAD_OPERATION ((cmox_mac_retval_t)0x00030003U) + +/** + * @brief Authentication of the tag has been successful + */ +#define CMOX_MAC_AUTH_SUCCESS ((cmox_mac_retval_t)0x0003C726U) + +/** + * @brief Authentication of the tag failed + */ +#define CMOX_MAC_AUTH_FAIL ((cmox_mac_retval_t)0x00036E93U) + +/* Public types --------------------------------------------------------------*/ + +/** + * @brief MAC module return value type + */ +typedef uint32_t cmox_mac_retval_t; + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_MAC_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa.h b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa.h new file mode 100644 index 00000000..8d1a46a4 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa.h @@ -0,0 +1,175 @@ +/** + ****************************************************************************** + * @file cmox_rsa.h + * @author MCD Application Team + * @brief This file provides common function for RSA module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_RSA_H +#define CMOX_RSA_H + +#include +#include + +#include "rsa/cmox_rsa_types.h" +#if !defined(CMOX_DEFAULT_FILE) +#include "cmox_default_config.h" +#else +#include CMOX_DEFAULT_FILE +#endif /* CMOX_DEFAULT_FILE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_RSA + * @{ + */ + +/** + * @defgroup CMOX_RSA_PUBLIC_METHODS RSA public method prototypes + * @{ + */ + +/** + * @brief Mandatory function to set Low Level Mathematical Functions, and working memory buffer, for RSA + * @param[in,out] P_pRsaCtx Context for RSA operations + * @param[in] P_Math Structure pointer with the Low-level Mathematical functions + * This parameter can be one of the following: + * @arg CMOX_MATH_FUNCS_SMALL + * @arg CMOX_MATH_FUNCS_FAST + * @param[in] P_Modexp Structure pointer with the Modular Exponentiation function + * This parameter can be one of the following: + * @arg CMOX_MODEXP_PUBLIC + * @arg CMOX_MODEXP_PRIVATE_LOWMEM + * @arg CMOX_MODEXP_PRIVATE_MIDMEM + * @arg CMOX_MODEXP_PRIVATE_HIGHMEM + * @param[in] P_pBuf The preallocated static buffer that will be used + * @param[in] P_BufLen The size in bytes of the P_pBuf buffer + */ +void cmox_rsa_construct(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_math_funcs_t P_Math, + const cmox_modexp_func_t P_Modexp, + uint8_t *P_pBuf, + size_t P_BufLen); + +/** + * @brief Clean the RSA context and the internal temporary buffer + * @param[in,out] P_pRsaCtx Context for RSA operations + */ +void cmox_rsa_cleanup(cmox_rsa_handle_t *P_pRsaCtx); + +/** + * @brief Set the key (public or private) in the key structure + * @param[out] P_pKey Key to set + * @param[in] P_pModulus Modulus + * @param[in] P_ModulusLen Modulus Length (in Bytes) + * @param[in] P_pExp Exponent (private or public) + * @param[in] P_ExpLen Exponent Length (in Bytes) + * @retval CMOX_RSA_SUCCESS + * @retval CMOX_RSA_ERR_BAD_PARAMETER + */ +cmox_rsa_retval_t cmox_rsa_setKey(cmox_rsa_key_t *P_pKey, + const uint8_t *P_pModulus, + size_t P_ModulusLen, + const uint8_t *P_pExp, + size_t P_ExpLen); + +/** + * @brief Set the private CRT key in the key structure + * @param[out] P_pPrivKey Private Key to set + * @param[in] P_ModulusBitLen Modulus Length (in bits) + * @param[in] P_pExpP Secret exponent (mod P) dP + * @param[in] P_ExpPLen dP Length (in Bytes) + * @param[in] P_pExpQ Secret exponent (mod Q) dQ + * @param[in] P_ExpQLen dQ Length (in Bytes) + * @param[in] P_pP First secret prime P + * @param[in] P_PLen P Length (in Bytes) + * @param[in] P_pQ Second secret prime Q + * @param[in] P_QLen Q Length (in Bytes) + * @param[in] P_pIq Inverse of Q (mod P) invQ + * @param[in] P_IqLen invQ Length (in Bytes) + * @retval CMOX_RSA_SUCCESS + * @retval CMOX_RSA_ERR_BAD_PARAMETER + */ +cmox_rsa_retval_t cmox_rsa_setKeyCRT(cmox_rsa_key_t *P_pPrivKey, + size_t P_ModulusBitLen, + const uint8_t *P_pExpP, + size_t P_ExpPLen, + const uint8_t *P_pExpQ, + size_t P_ExpQLen, + const uint8_t *P_pP, + size_t P_PLen, + const uint8_t *P_pQ, + size_t P_QLen, + const uint8_t *P_pIq, + size_t P_IqLen); + +/** + * @brief Set the private CRT key in the key structure, enabling the Fault Attacks Countermeasure. + * @param[out] P_pPrivKey Private Key to set + * @param[in] P_ModulusBitLen Modulus Length (in bits) + * @param[in] P_pExpP Secret exponent (mod P) dP + * @param[in] P_ExpPLen dP Length (in Bytes) + * @param[in] P_pExpQ Secret exponent (mod Q) dQ + * @param[in] P_ExpQLen dQ Length (in Bytes) + * @param[in] P_pP First secret prime P + * @param[in] P_PLen P Length (in Bytes) + * @param[in] P_pQ Second secret prime Q + * @param[in] P_QLen Q Length (in Bytes) + * @param[in] P_pIq Inverse of Q (mod P) invQ + * @param[in] P_IqLen invQ Length (in Bytes) + * @param[in] P_pPubKey Public Key + * @param[in] P_PubKeyLen Public Key Length (in Bytes) + * @retval CMOX_RSA_SUCCESS + * @retval CMOX_RSA_ERR_BAD_PARAMETER + * @note This function enables the protection against the Bellcore attack for RSA-CRT computation. + * This countermeasure is useful to protect RSA-CRT using PKCS#1 v1.5 for Signature Creation. + * Indeed, PKCS#1 v2.2 Signature Creation is not vulnerable because of the presence of an input random, + * and Decryption processes (both for PKCS#1 v1.5 and v2.2) are not vulnerable because the plaintext + * is not returned if not correct (therefore not exploitable by an attacker). + */ +cmox_rsa_retval_t cmox_rsa_setKeyCRTwithFACM(cmox_rsa_key_t *P_pPrivKey, + size_t P_ModulusBitLen, + const uint8_t *P_pExpP, + size_t P_ExpPLen, + const uint8_t *P_pExpQ, + size_t P_ExpQLen, + const uint8_t *P_pP, + size_t P_PLen, + const uint8_t *P_pQ, + size_t P_QLen, + const uint8_t *P_pIq, + size_t P_IqLen, + const uint8_t *P_pPubKey, + size_t P_PubKeyLen); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_RSA_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v15.h b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v15.h new file mode 100644 index 00000000..d994d9eb --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v15.h @@ -0,0 +1,206 @@ +/** + ****************************************************************************** + * @file cmox_rsa_pkcs1v15.h + * @author MCD Application Team + * @brief Header file for RSA PKCS#1 v1.5 definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_RSA_PKCS1V15_H +#define CMOX_RSA_PKCS1V15_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include "rsa/cmox_rsa.h" +#include "utils/cmox_utils_retvals.h" + +/** @addtogroup CMOX_RSA + * @{ + */ + +/** + * @defgroup CMOX_RSA_PKCS1V15 RSA PKCS#1 v1.5 standard + * @{ + */ + +/** + * @brief Hash algorithms to use with RSA PKCS#1 API + * @defgroup CMOX_RSA_PKCS1V15_HASH Hash functions to use in RSA PKCS#1 v1.5 + * @{ + */ + +/** + * @brief SHA1 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA1; +/** + * @brief SHA224 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA224; +/** + * @brief SHA256 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA256; +/** + * @brief SHA384 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA384; +/** + * @brief SHA512 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA512; +/** + * @brief SHA512/224 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA512_224; +/** + * @brief SHA512/256 Hash structure for the RSA PKCS#1 v1.5 functions + */ +extern const cmox_rsa_pkcs1v15_hash_t CMOX_RSA_PKCS1V15_HASH_SHA512_256; + +/** + * @} + */ + +/** + * @defgroup CMOX_RSA_PKCS1V15_PUBLIC_METHODS RSA PKCS#1 v1.5 public method prototypes + * @{ + */ + +/** + * @brief Sign a message using PKCS#1 v1.5 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPrivKey Private Key (standard or CRT) + * @param[in] P_pDigest Message to sign + * @param[in] P_HashId Hash to use + * @param[out] P_pSignature Output signature + * @param[out] P_pSignatureLen Output signature Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to sign + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v15_sign(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPrivKey, + const uint8_t *P_pDigest, + const cmox_rsa_pkcs1v15_hash_t P_HashId, + uint8_t *P_pSignature, + size_t *P_pSignatureLen); + +/** + * @brief Verify a message signed with PKCS#1 v1.5 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPubKey Public Key + * @param[in] P_pDigest Message to verify + * @param[in] P_HashId Hash to use + * @param[in] P_pSignature Signature + * @param[in] P_SignatureLen Signature Length (in Bytes) + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_RSA_AUTH_SUCCESS Signature verified + * @retval CMOX_RSA_AUTH_FAIL Signature NOT verified + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_INVALID_SIGNATURE Input signature corrupted or not in the expected format + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to verify + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v15_verify(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPubKey, + const uint8_t *P_pDigest, + const cmox_rsa_pkcs1v15_hash_t P_HashId, + const uint8_t *P_pSignature, + size_t P_SignatureLen, + uint32_t *P_pFaultCheck); + +/** + * @brief Encrypt a message using PKCS#1 v1.5 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPubKey Public Key + * @param[in] P_pInput Message to encrypt + * @param[in] P_InputLen Message Length (in Bytes) + * @param[in] P_pRandom Random buffer + * @param[in] P_RandomLen Random Length (in Bytes) + * @param[out] P_pOutput Output encrypted buffer + * @param[out] P_pOutputLen Output Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to encrypt + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_WRONG_RANDOM Random material too short or not valid for the functionality + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v15_encrypt(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPubKey, + const uint8_t *P_pInput, + size_t P_InputLen, + const uint8_t *P_pRandom, + size_t P_RandomLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Decrypt a message using PKCS#1 v1.5 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPrivKey Private Key (standard or CRT) + * @param[in] P_pInput Message to decrypt + * @param[in] P_InputLen Message Length (in Bytes) + * @param[out] P_pOutput Output decrypted buffer + * @param[out] P_pOutputLen Output Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_WRONG_DECRYPTION Decryption failed, probably due to a wrong private key + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v15_decrypt(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPrivKey, + const uint8_t *P_pInput, + size_t P_InputLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_RSA_PKCS1V15_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v22.h b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v22.h new file mode 100644 index 00000000..ae868633 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_pkcs1v22.h @@ -0,0 +1,226 @@ +/** + ****************************************************************************** + * @file cmox_rsa_pkcs1v22.h + * @author MCD Application Team + * @brief Header file for RSA PKCS#1 v2.2 definitions and functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_RSA_PKCS1V22_H +#define CMOX_RSA_PKCS1V22_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include "rsa/cmox_rsa.h" +#include "utils/cmox_utils_retvals.h" + +/** @addtogroup CMOX_RSA + * @{ + */ + +/** + * @defgroup CMOX_RSA_PKCS1V22 RSA PKCS#1 v2.2 standard + * @{ + */ + +/** + * @brief Hash algorithms to use with RSA PKCS#1 API + * @defgroup CMOX_RSA_PKCS1V22_HASH Hash functions to use in RSA PKCS#1 v2.2 + * @{ + */ + +/** + * @brief SHA1 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA1; +/** + * @brief SHA224 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA224; +/** + * @brief SHA256 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA256; +/** + * @brief SHA384 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA384; +/** + * @brief SHA512 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA512; +/** + * @brief SHA512/224 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA512_224; +/** + * @brief SHA512/256 Hash structure for the RSA PKCS#1 v2.2 functions + */ +extern const cmox_rsa_pkcs1v22_hash_t CMOX_RSA_PKCS1V22_HASH_SHA512_256; + +/** + * @} + */ + +/** + * @defgroup CMOX_RSA_PKCS1V22_PUBLIC_METHODS RSA PKCS#1 v2.2 public method prototypes + * @{ + */ + +/** + * @brief Sign a message using PKCS#1 v2.2 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPrivKey Private Key (standard or CRT) + * @param[in] P_pDigest Message to sign + * @param[in] P_HashId Hash to use + * @param[in] P_pRandom Random buffer + * @param[in] P_RandomLen Random Length (in Bytes) + * @param[out] P_pSignature Output signature + * @param[out] P_pSignatureLen Output signature Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to sign + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v22_sign(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPrivKey, + const uint8_t *P_pDigest, + const cmox_rsa_pkcs1v22_hash_t P_HashId, + const uint8_t *P_pRandom, + size_t P_RandomLen, + uint8_t *P_pSignature, + size_t *P_pSignatureLen); + +/** + * @brief Verify a message signed with PKCS#1 v2.2 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPubKey Public Key + * @param[in] P_pDigest Message to verify + * @param[in] P_HashId Hash to use + * @param[in] P_RandomLen Random Length (in Bytes) + * @param[in] P_pSignature Signature + * @param[in] P_SignatureLen Signature Length (in Bytes) + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_RSA_AUTH_SUCCESS Signature verified + * @retval CMOX_RSA_AUTH_FAIL Signature NOT verified + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_INVALID_SIGNATURE Input signature corrupted or not in the expected format + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v22_verify(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPubKey, + const uint8_t *P_pDigest, + const cmox_rsa_pkcs1v22_hash_t P_HashId, + size_t P_RandomLen, + const uint8_t *P_pSignature, + size_t P_SignatureLen, + uint32_t *P_pFaultCheck); + +/** + * @brief Encrypt a message using PKCS#1 v2.2 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPubKey Public Key + * @param[in] P_pInput Message to encrypt + * @param[in] P_InputLen Message Length (in Bytes) + * @param[in] P_HashId Hash to use + * @param[in] P_pRandom Random buffer + * @param[in] P_RandomLen Random Length (in Bytes) + * @param[in] P_pLabel Label (Optional) + * @param[in] P_LabelLen Label Length (in Bytes) + * @param[out] P_pOutput Output encrypted buffer + * @param[out] P_pOutputLen Output Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to encrypt + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v22_encrypt(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPubKey, + const uint8_t *P_pInput, + size_t P_InputLen, + const cmox_rsa_pkcs1v22_hash_t P_HashId, + const uint8_t *P_pRandom, + size_t P_RandomLen, + const uint8_t *P_pLabel, + size_t P_LabelLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @brief Decrypt a message using PKCS#1 v2.2 + * @param[in] P_pRsaCtx Context for RSA operations + * @param[in] P_pPrivKey Private Key (standard or CRT) + * @param[in] P_pInput Message to decrypt + * @param[in] P_InputLen Message Length (in Bytes) + * @param[in] P_HashId Hash to use + * @param[in] P_pLabel Label (Optional) + * @param[in] P_LabelLen Label Length (in Bytes) + * @param[out] P_pOutput Output decrypted buffer + * @param[out] P_pOutputLen Output Length (in Bytes) + * @retval CMOX_RSA_SUCCESS Everything OK + * @retval CMOX_RSA_ERR_MATH_ALGO_MISMATCH Mathematical function set is incompatible with current functionality + * @retval CMOX_RSA_ERR_MEXP_ALGO_MISMATCH Modexp function set is not compatible with current functionality + * @retval CMOX_RSA_ERR_BAD_PARAMETER Some NULL/wrong/empty parameter + * @retval CMOX_RSA_ERR_MEMORY_FAIL Not enough memory + * @retval CMOX_RSA_ERR_INTERNAL Something went wrong during internal computations (e.g. hash) + * @retval CMOX_RSA_ERR_WRONG_DECRYPTION Decryption failed, probably due to a wrong private key + * @retval CMOX_RSA_ERR_MODULUS_TOO_SHORT Modulus too short for the message to decrypt + */ +cmox_rsa_retval_t cmox_rsa_pkcs1v22_decrypt(cmox_rsa_handle_t *P_pRsaCtx, + const cmox_rsa_key_t *P_pPrivKey, + const uint8_t *P_pInput, + size_t P_InputLen, + const cmox_rsa_pkcs1v22_hash_t P_HashId, + const uint8_t *P_pLabel, + size_t P_LabelLen, + uint8_t *P_pOutput, + size_t *P_pOutputLen); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_RSA_PKCS1V22_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_retvals.h b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_retvals.h new file mode 100644 index 00000000..ee41f738 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_retvals.h @@ -0,0 +1,73 @@ +/** + ****************************************************************************** + * @file cmox_rsa_retvals.h + * @author MCD Application Team + * @brief This file provides the error types and code for RSA modules + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_RSA_RETVALS_H +#define CMOX_RSA_RETVALS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_RSA + * @{ + */ + +/** + * @defgroup CMOX_RSA_RETVALS RSA return values + * @{ + */ + +/** + * @brief Return value type for RSA module + */ +typedef uint32_t cmox_rsa_retval_t; + +#define CMOX_RSA_SUCCESS ((cmox_rsa_retval_t)0x00050000) /*!< RSA operation successfully performed */ +#define CMOX_RSA_ERR_INTERNAL ((cmox_rsa_retval_t)0x00050001) /*!< Internal computat. error (e.g. hash) */ +#define CMOX_RSA_ERR_BAD_PARAMETER ((cmox_rsa_retval_t)0x00050003) /*!< One of the expected parameter is invalid */ +#define CMOX_RSA_ERR_MODULUS_TOO_SHORT ((cmox_rsa_retval_t)0x00050007) /*!< Input too long for the current modulus */ +#define CMOX_RSA_ERR_INVALID_SIGNATURE ((cmox_rsa_retval_t)0x00050009) /*!< RSA invalid signature value */ +#define CMOX_RSA_ERR_WRONG_DECRYPTION ((cmox_rsa_retval_t)0x0005000A) /*!< RSA invalid decryption, due to mismatch between private key and input */ +#define CMOX_RSA_ERR_WRONG_RANDOM ((cmox_rsa_retval_t)0x0005000B) /*!< Random not compliant with the API (Recall with other random material) */ +#define CMOX_RSA_ERR_MEMORY_FAIL ((cmox_rsa_retval_t)0x0005000C) /*!< Not enough memory */ +#define CMOX_RSA_ERR_MATH_ALGO_MISMATCH ((cmox_rsa_retval_t)0x00050010) /*!< Math customization not supported by current functionality */ +#define CMOX_RSA_ERR_MEXP_ALGO_MISMATCH ((cmox_rsa_retval_t)0x00050011) /*!< Modexp function not supported by current functionality */ +#define CMOX_RSA_AUTH_SUCCESS ((cmox_rsa_retval_t)0x0005C726) /*!< RSA signature successful verification */ +#define CMOX_RSA_AUTH_FAIL ((cmox_rsa_retval_t)0x00056E93) /*!< RSA signature not verified */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_RSA_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_types.h b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_types.h new file mode 100644 index 00000000..f70949ed --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/rsa/cmox_rsa_types.h @@ -0,0 +1,118 @@ +/** + ****************************************************************************** + * @file cmox_rsa_types.h + * @author MCD Application Team + * @brief This file provides the types used within the RSA module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_RSA_TYPES_H +#define CMOX_RSA_TYPES_H + +#include +#include +#include "cmox_common.h" +#include "rsa/cmox_rsa_retvals.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** + * @brief Structure for the RSA context + */ +typedef struct +{ + cmox_membuf_handle_st membuf_str; /*!< Memory buffer structure */ + cmox_modexp_func_t modexp_ptr; /*!< Modexp customization structure */ + cmox_math_funcs_t math_ptr; /*!< Math customization structure */ + uint32_t magic_num_check; /*!< Magic number for diagnostic checks */ +} cmox_rsa_handle_t; + +/** + * @brief Internal structure type for the RSA modular exponentiation function + */ +struct cmox_rsa_intfuncStruct_t; +/** + * @brief Public pointer type for the RSA modular exponentiation function + */ +typedef struct cmox_rsa_intfuncStruct_t *cmox_rsa_intfunc_t; + +/** + * @brief Internal structure type for the Fault Attacks countermeasure + */ +struct cmox_rsa_facmStruct_t; +/** + * @brief Public pointer type for the Fault Attacks countermeasure + */ +typedef const struct cmox_rsa_facmStruct_t *cmox_rsa_facm_t; + +/** + * @brief Structure to hold public or private key parameters + */ +typedef struct +{ + cmox_rsa_intfunc_t f; /*!< Function executing CRT/standard modexp */ + size_t mod_bitlen; /*!< Length (in bytes) of Modulus */ + + union + { + /* Standard public/private fields */ + struct + { + const uint8_t *mod; /*!< Modulus */ + const uint8_t *exp; /*!< Public/secret Exponent */ + size_t exp_len; /*!< Length (in bytes) of Exponent */ + } std; + + /* CRT fields */ + struct + { + const uint8_t *p; /*!< Parameter P (in case of CRT) or normal modulus */ + size_t p_len; /*!< Length (in bytes) of P/Modulus */ + const uint8_t *q; /*!< Parameter Q */ + size_t q_len; /*!< Length (in bytes) of Q */ + const uint8_t *dp; /*!< Secret exponent (mod P) (in case of CRT), or normal secret exponent */ + size_t dp_len; /*!< Length (in bytes) of dP/Exponent */ + const uint8_t *dq; /*!< Secret exponent (mod Q) */ + size_t dq_len; /*!< Length (in bytes) of dQ */ + const uint8_t *iq; /*!< Q^(-1) (mod P) */ + size_t iq_len; /*!< Length (in bytes) of iQ */ + const uint8_t *pub_exp; /*!< public exponent */ + size_t pub_exp_len;/*!< Length (in bytes) of the public exponent */ + cmox_rsa_facm_t facm_flag; /*!< Parameter to enable/disable the countermeasure to the Fault Attacks */ + } crt; + } fields; /*!< Union for STD or CRT key structure */ +} cmox_rsa_key_t; + +/** + * @brief Pointer type linked to the structure to hold Hash information for PKCS#1 v1.5 + */ +typedef const struct cmox_rsa_pkcs1v15_hash_st *cmox_rsa_pkcs1v15_hash_t; + +/** + * @brief Pointer type linked to the structure to hold Hash information for PKCS#1 v2.2 + */ +typedef const struct cmox_rsa_pkcs1v22_hash_st *cmox_rsa_pkcs1v22_hash_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_RSA_TYPES_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/utils/cmox_utils_compare.h b/firmware/ui/dependencies/cmox/include/utils/cmox_utils_compare.h new file mode 100644 index 00000000..f95bf456 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/utils/cmox_utils_compare.h @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * @file cmox_utils_compare.h + * @author MCD Application Team + * @brief Header file for public comparison function and utilities + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_UTILS_COMPARE_H +#define CMOX_UTILS_COMPARE_H + +#include "utils/cmox_utils_retvals.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @addtogroup CMOX_UTILS + * @{ + */ + +/** + * @brief Compares two buffers in a fault-secure way + * @param[in] P_pBuf1 First buffer + * @param[in] P_Len1 Length of the first input buffer + * @param[in] P_pBuf2 Second buffer + * @param[in] P_Len2 Length of the second input buffer + * @param[out] P_pFaultCheck Optional value to check, together with the retval, to verify if some fault happened + * @retval CMOX_UTILS_AUTH_SUCCESS The two buffers are equal + * @retval CMOX_UTILS_AUTH_FAIL The two buffers are different + * @warning If it's necessary to be protected against fault attacks, it's very important that P_Len1 and P_Len2 + * are different memory locations (or registers), otherwise a single fault could be fatal. + * @note P_pFaultCheck value, if the parameter is provided, MUST be checked to + * be equal to the retval, and both MUST be equal to the successful value. + * P_pFaultCheck MUST be checked only if the main result is successful, + * and has no relevance if the main result is not successful. + * Every comparison (both for the return value and for P_pFaultCheck) must be done against + * the success value, and not comparing the value with the failure value. Indeed, in presence of faults, + * especially P_pFaultCheck, could be a dirty value. + */ +cmox_utils_retval_t cmox_utils_compare(const uint8_t *P_pBuf1, + uint32_t P_Len1, + const uint8_t *P_pBuf2, + uint32_t P_Len2, + uint32_t *P_pFaultCheck); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CMOX_UTILS_COMPARE_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/include/utils/cmox_utils_retvals.h b/firmware/ui/dependencies/cmox/include/utils/cmox_utils_retvals.h new file mode 100644 index 00000000..79088b99 --- /dev/null +++ b/firmware/ui/dependencies/cmox/include/utils/cmox_utils_retvals.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file cmox_utils_retvals.h + * @author MCD Application Team + * @brief This file provides the error types and code for UTILS modules + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef CMOX_UTILS_RETVALS_H +#define CMOX_UTILS_RETVALS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @addtogroup CMOX_UTILS + * @{ + */ + +/** @defgroup CMOX_UTILS_RETVALS Utils return values + * @{ + */ + +/** + * Return value type for the UTILS module + */ +typedef uint32_t cmox_utils_retval_t; + +#define CMOX_UTILS_AUTH_SUCCESS ((cmox_utils_retval_t)0x0007C726) /*!< UTILS operation successfully performed */ +#define CMOX_UTILS_AUTH_FAIL ((cmox_utils_retval_t)0x00076E93) /*!< Input buffers are different */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CMOX_UTILS_RETVALS_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/ui/dependencies/cmox/lib/libSTM32Cryptographic_CM4.a b/firmware/ui/dependencies/cmox/lib/libSTM32Cryptographic_CM4.a new file mode 100644 index 0000000000000000000000000000000000000000..2436975138aef12b030c7fa9da45fdac9ebcc185 GIT binary patch literal 617262 zcmeEv2YeJo`~O@o3E}7gVz@wnfRr>sK*Y->xgRymINs$D*T^kcV~BYZx6z&@B90`zd!TIWcPWV?>swgXXcri zor@XcsV(u1wGOw-T|!D?d{TTu{KzD`J)RTs|5K8aIVvG#E zC_;Sq^L}10LN33KkgJORp1&oM5cC^{@&29+LeM`1deLvaT-`sLO~`9@LiUg2{l^mt zLEl`!`yb{Lg8rBFyg%{^A?W}7rCnYV7D+U{A0nD_Pw+meE771IJ(%}tE}}u7U99f& zhY`(1D~P7-d)`<2i3WZBFQ@l67ZDBmdoSnxc6jDL;a@vQH0|+CD~X2n2WAir_5Qs? zgZ@xG?~g|j4S22bR=MxEhG?qNjdyFQTXZWzbLkN1qTq z^*==sz0&^);S}Crh$n^)ddc@0M-0>_6%a#vd`2%~KtH~L_XQsk1Ns@GdGEQC7*6Nw z0l#DdG2HY5?{Bja1Nu9Qd4JyyVnF|B=hOQgGl}8#&xqlJ8KM1WZxh2$KHeXL^n*8Q zcJMyDh8WTJ7{L3O&xjHIkQaDAaw9RKcMc=Q%qqDbPl!?JC*Mkp?eSN>LX7B_9_RfH z@x+LJO$G07-%N~3ziBlwKKd;&KJ!|ze{U@@qCc>Q_h0=Z`^O6Z%W9miwz9 z&8%OsjF?z|O9e40{l?A2#QMk95L0{oYsZPHz5bg&iRm=n+`TX1eB5DTMn7U3@0~To zJg!#qd5Oe~{vto`eVd3G{k$2xU(%VF(ccu$`wbI`8U2H6dH>Yc#Qe%0-tVg=X7pe5 zlKUgq5i@v;;aj=yu!dN=%qNzf(?a{9pAZZB5kq)Crhr(`r$55`aR-P+%}@D-SUeHw zxp~vvX_nL5$8%PoaD~P zOfQ(8Kgm61Qkru@rd*aeQB~#!zFQ72%uSmxA(Sp&s8Gg5ueiz$k*h8tlqyNDu4$C0 z!UdihiK>*{PcE;jmt@uRs_LEP^>rertk&ygi0aD8sm@FV1JX+$JliV|US3&KT`TD? zuPT>_%6Sc9xH?6+`fAy8kW}Vsx-%VfN}kmM)15XUD=%0Ad8f*h!})wxs+Vy?1z;Z_ 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%0Drn? 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 DtxT?8 literal 0 HcmV?d00001 diff --git a/firmware/ui/dependencies/sframe b/firmware/ui/dependencies/sframe index cdec59ca..9df6dda1 160000 --- a/firmware/ui/dependencies/sframe +++ b/firmware/ui/dependencies/sframe @@ -1 +1 @@ -Subproject commit cdec59ca6de55479edb14b0b714d74a27c108862 +Subproject commit 9df6dda186a138820afecefa3a6d3dac84d4c5ac diff --git a/firmware/ui/stm32f405rgtx_flash.ld b/firmware/ui/stm32f405rgtx_flash.ld deleted file mode 100644 index 4dcf56f0..00000000 --- a/firmware/ui/stm32f405rgtx_flash.ld +++ /dev/null @@ -1,208 +0,0 @@ -/* -****************************************************************************** -** - -** File : LinkerScript.ld -** -** Author : STM32CubeMX -** -** Abstract : Linker script for STM32F405RGTx series -** 1024Kbytes FLASH and 192Kbytes RAM -** -** Set heap size, stack size and stack location according -** to application requirements. -** -** Set memory bank area and size if external memory is used. -** -** Target : STMicroelectronics STM32 -** -** Distribution: The file is distributed “as is,” without any warranty -** of any kind. -** -***************************************************************************** -** @attention -** -**

© COPYRIGHT(c) 2019 STMicroelectronics

-** -** Redistribution and use in source and binary forms, with or without modification, -** are permitted provided that the following conditions are met: -** 1. Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** 3. Neither the name of STMicroelectronics nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -***************************************************************************** -*/ - -/* Entry Point */ -ENTRY(Reset_Handler) - -/* Highest address of the user mode stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */ -/* Generate a link error if heap and stack don't fit into RAM */ -_Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ - -/* Specify the memory areas */ -MEMORY -{ -RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K -CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K -FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K -} - -/* Define output sections */ -SECTIONS -{ - /* The startup code goes first into FLASH */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - . = ALIGN(4); - } >FLASH - - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text) /* .text sections (code) */ - *(.text*) /* .text* sections (code) */ - *(.glue_7) /* glue arm to thumb code */ - *(.glue_7t) /* glue thumb to arm code */ - *(.eh_frame) - - KEEP (*(.init)) - KEEP (*(.fini)) - - . = ALIGN(4); - _etext = .; /* define a global symbols at end of code */ - } >FLASH - - /* Constant data goes into FLASH */ - .rodata : - { - . = ALIGN(4); - *(.rodata) /* .rodata sections (constants, strings, etc.) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - . = ALIGN(4); - } >FLASH - - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH - .ARM : { - __exidx_start = .; - *(.ARM.exidx*) - __exidx_end = .; - } >FLASH - - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array*)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } >FLASH - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array*)) - PROVIDE_HIDDEN (__init_array_end = .); - } >FLASH - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(SORT(.fini_array.*))) - KEEP (*(.fini_array*)) - PROVIDE_HIDDEN (__fini_array_end = .); - } >FLASH - - /* used by the startup to initialize data */ - _sidata = LOADADDR(.data); - - /* Initialized data sections goes into RAM, load LMA copy after code */ - .data : - { - . = ALIGN(4); - _sdata = .; /* create a global symbol at data start */ - *(.data) /* .data sections */ - *(.data*) /* .data* sections */ - - . = ALIGN(4); - _edata = .; /* define a global symbol at data end */ - } >RAM AT> FLASH - - _siccmram = LOADADDR(.ccmram); - - /* CCM-RAM section - * - * IMPORTANT NOTE! - * If initialized variables will be placed in this section, - * the startup code needs to be modified to copy the init-values. - */ - .ccmram : - { - . = ALIGN(4); - _sccmram = .; /* create a global symbol at ccmram start */ - *(.ccmram) - *(.ccmram*) - - . = ALIGN(4); - _eccmram = .; /* create a global symbol at ccmram end */ - } >CCMRAM AT> FLASH - - - /* Uninitialized data section */ - . = ALIGN(4); - .bss : - { - /* This is used by the startup in order to initialize the .bss secion */ - _sbss = .; /* define a global symbol at bss start */ - __bss_start__ = _sbss; - *(.bss) - *(.bss*) - *(COMMON) - - . = ALIGN(4); - _ebss = .; /* define a global symbol at bss end */ - __bss_end__ = _ebss; - } >RAM - - /* User_heap_stack section, used to check that there is enough RAM left */ - ._user_heap_stack : - { - . = ALIGN(8); - PROVIDE ( end = . ); - PROVIDE ( _end = . ); - . = . + _Min_Heap_Size; - . = . + _Min_Stack_Size; - . = ALIGN(8); - } >RAM - - - - /* Remove information from the standard libraries */ - /DISCARD/ : - { - libc.a ( * ) - libm.a ( * ) - libgcc.a ( * ) - } - -} - - From 7580e5cbaae7a1b3cc6e272427d25011348fdc7a Mon Sep 17 00:00:00 2001 From: trigaux Date: Tue, 3 Jun 2025 13:21:47 -0400 Subject: [PATCH 6/6] Update format exclusions. --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index e6a0bfe3..dcea794b 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -15,4 +15,4 @@ jobs: - uses: jidicula/clang-format-action@v4.13.0 with: clang-format-version: '18' - exclude-regex: '(lib|Drivers|Core|net/include/sys|net/include/netinet|sframe|gsl)' + exclude-regex: '(lib|Drivers|Core|net/include/sys|net/include/netinet|cmox)'