diff --git a/features/mbedtls/platform/inc/platform_mbed.h b/features/mbedtls/platform/inc/platform_mbed.h index 53b2fca16a5..7f345a6b363 100644 --- a/features/mbedtls/platform/inc/platform_mbed.h +++ b/features/mbedtls/platform/inc/platform_mbed.h @@ -20,3 +20,21 @@ #if defined(DEVICE_TRNG) #define MBEDTLS_ENTROPY_HARDWARE_ALT #endif + +#if defined(DEVICE_AES) +#define MBEDTLS_AES_ALT +#endif + +#if defined(DEVICE_SHA) +#define MBEDTLS_SHA1_ALT +#define MBEDTLS_SHA256_ALT +#endif + +#if defined(DEVICE_ECC) +#define MBEDTLS_ECP_DEVICE_ALT +#define MBEDTLS_ECP_DOUBLE_JAC_ALT +#define MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +#define MBEDTLS_MPI_MODULAR_DIVISION_ALT +#endif \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/Changes_sl_mbedtls.txt b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/Changes_sl_mbedtls.txt new file mode 100644 index 00000000000..130ea024ebb --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/Changes_sl_mbedtls.txt @@ -0,0 +1,67 @@ +================ Revision history ============================================ +5.0.0: + - Added basic support for Series 1 Configuration 2 devices (EFR32MG12, etc.) + - Bugfix: The asynchronous callback of mbedtls_ccm_auth_decrypt and + mbedtls_cmac_verify_tag reported incorrect error codes when authentication + verification fails. + - Bugfix: In asynchronous mode, the output buffer of mbedtls_ccm_auth_decrypt + was not properly cleared when authentication verification fails. + +4.4.0: + - Added CMAC support with a Silicon Labs specific API (slcl_cmac.c). + CMAC is not covered by the standard mbedtls interface. + The CMAC plugin use the CRYPTO hardware module for acceleration. + - Added CCM plugin (slcl_ccm.c) with CRYPTO hardware acceleration and + optimized CCM functions for BLE (mbedtls_ccm_encrypt_and_tag_ble and + mbedtls_ccm_auth_decrypt_ble). + - Added CRYPTO preemption support in the following plugins: + slcl_aes.c, slcl_ccm.c, slcl_cmac.c, slcl_ecp.c, slcl_sha1.c and + slcl_sha256.c. + - Added support for alternative CRYPTO critical region implementations + (for the CRYPTO preemption support). + - Added support for asynchronous (non-blocking) API calls in the following + plugins: slcl_aes.c, slcl_ccm.c and slcl_cmac.c. + - Added support for moving data with BUFC and DMA (to/from CRYPTO registers) + in the following plugins: slcl_aes.c and slcl_ccm.c. + - In order to support error codes in new SIlicon Labs specific APIs + extended error code interface of the standard mbedtls by using the full + 32-bit integer range, see details in mbedtls_ecode.h. + - Added support for AES module on EFM32GG (Giant Gecko) in slcl_aes.c. + Compile with MBEDTLS_SLCL_PLUGINS in order to enable EFM32GG support. + +4.3.1: + - No changes. + +4.3.0: + - Updated to mbedtls-2.2.0 including EC JPAKE support. + - sl_aes.c: + In mbedtls_aes_setkey_enc and mbedtls_aes_setkey_dec change return value to + MBEDTLS_ERR_AES_INVALID_KEY_LENGTH when key length is not 128 or 256 bits. + In mbedtls_aes_crypt_cfb128 added support for data lengths not dividable + with 16 (AES block size), by using software (no crypto) implementation. + In mbedtls_aes_crypt_cfb8 return errors from mbedtls_aes_crypt_ecb. + - library/bignum.c: + In mbedtls_mpi_sub_abs and mbedtls_mpi_mul_mpi copy to and use local + variables only if necessary. + - library/ecp.c: + In ecp_modp call halResetWatchdog #ifdef MBEDTLS_HAVE_HAL_WATCHDOG_TIMER + for Thread stack integration. + - library/aes.c: + In mbedtls_aes_self_test allow failure when setting 192 bit keys which is + not supported by CRYPTO. + - library/gcm.c: + In mbedtls_gcm_self_test allow failure when setting 192 bit keys which is + not supported by CRYPTO. + - library/x509.c and x509_crt.c: + Excluded code when MBEDTLS_FS_IO is defined which is not supported on + Silicon Labs devices. + - Added sl_timing.c and timing_alt.h in order to compiler modules depending on + MBEDTLS_TIMING_C. The user should #define MBEDTLS_TIMING_ALT in order to + compile. + +4.2.1: + - No changes. + +4.2.0: + - First version including support for mbedtls 2.0.0 and CRYPTO acceleration of + AES (sl_aes.c), ECC (sl_ecp.c), SHA1 (sl_sha1.c) and SHA256 (sl_sha256.c). diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/README.txt b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/README.txt new file mode 100644 index 00000000000..5506a5d5d2b --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/README.txt @@ -0,0 +1,34 @@ +README for mbed TLS CRYPTO hardware acceleraton plugins from Silicon Labs +========================================================================= + +Introduction +------------ +This folder include alternative implementations (plugins) from Silicon Labs for some of the mbed TLS library functions, including AES, CCM, CMAC, ECC (ECP, ECDH, ECDSA, ECJPAKE), SHA1 and SHA256. The plugins use the AES and CRYPTO hardware modules to accelerate the standard mbed TLS library functions that are implemented in C. The CRYPTO hardware module is incorporated in the new generations of MCUs from SIlicon Labs and the AES hardware module is incorporated in the classic EFM32 MCUs from Silicon Labs. + +Please refer to the mbedTLS section of the Gecko SDK documentation for more information on using mbed TLS on Silicon Labs devices. + +Configuration +------------- +The configuration macros of the CRYPTO hardware acceleraton plugins from Silicon Labs are documented in configs/config-sl-crypto-all-acceleration.h. The configs/config-sl-crypto-all-acceleration.h enables acceleration of all plugins from Silicon Labs and provides a full mbedtls configuration which can be used to get started with application development. Please refer to the Gecko SDK documentation for more information on using mbed TLS on Silicon Labs devices. Please refer to the main README file (in the mbedtls base folder) and `include/mbedtls/config.h` for general mbed TLS configuration. Below is a summary of the configuration macros of the CRYPTO hardware acceleraton plugins: + +#define MBEDTLS_AES_ALT /* Includes CRYPTO accelerated implementation of the aes.h interface. */ +#define MBEDTLS_SHA1_ALT /* Includes CRYPTO accelerated implementation of the sha1.h interface. */ +#define MBEDTLS_SHA256_ALT /* Includes CRYPTO accelerated implementation of the sha256.h interface. */ +#define MBEDTLS_ECP_DEVICE_ALT /* Includes CRYPTO accelerated implementation of some functions in ecp.c. */ +#define MBEDTLS_ECP_DOUBLE_JAC_ALT /* Includes CRYPTO accelerated implementation of the ecp_double_jac function. */ +#define MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT /* Includes CRYPTO accelerated implementation of the ecp_add_mixed function. */ +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT /* Includes CRYPTO accelerated implementation of the ecp_normalize_jac function. */ +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT /* Includes CRYPTO accelerated implementation of the ecp_normalize_jac_many function. */ +#define MBEDTLS_MPI_MODULAR_DIVISION_ALT /* Includes the CRYPTO accelerated function mbedtls_mpi_div_mod which can serve as a replacement of the regular mbedtls_mpi_inv_mod function of mbedtls. */ +#define MBEDTLS_SLCL_PLUGINS /* Enables group 2 plugins (slcl_xxx.c) including support for CRYPTO preemption, asynchronous API support, DMA and BUFC I/O modes, and support for classic EFM32 devices with AES module, EFM32GG, etc. */ +#define MBEDTLS_CRYPTO_DEVICE_PREEMPTION /* Include CRYPTO preemption */ +#define MBEDTLS_CRYPTO_CRITICAL_REGION_ALT /* Include alternative implementation of CRYPTO critical regions (of CRYPTO preemption support). */ +#define MBEDTLS_INCLUDE_ASYNCH_API /* Include asynchronous API support */ +#define MBEDTLS_INCLUDE_IO_MODE_DMA /* Include support for moving data to/from CRYPTO with DMA */ + +Compiling +--------- +Please refer to the example programs in the EFM32 SDK for project files examples for various IDE/toolchains. +I.e: +kits/SLSTK3401A_EFM32PG/examples/mbedtls_aescrypt +kits/SLSTK3401A_EFM32PG/examples/mbedtls_ecdsa diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/.gitignore b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/.gitignore new file mode 100644 index 00000000000..b25c15b81fa --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aes_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aes_alt.h new file mode 100644 index 00000000000..aee14a3326e --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aes_alt.h @@ -0,0 +1,397 @@ +/** + * \file aes_alt.h + * + * \brief AES block cipher + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_AES_ALT_H +#define MBEDTLS_AES_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_aes AES block cipher + * \brief CRYPTO hardware accelerated AES block cipher. + * \{ + ******************************************************************************/ + +#if defined( MBEDTLS_SLCL_PLUGINS ) +#include "aesdrv.h" +#include "sl_crypto.h" +#endif + +#include +#include + +#define MBEDTLS_AES_ENCRYPT 1 +#define MBEDTLS_AES_DECRYPT 0 + +/* Silicon Labs specific error codes: */ +#define MBEDTLS_ERR_AES_NOT_SUPPORTED ((int)MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED) +#define MBEDTLS_ERR_AES_AUTHENTICATION_FAILED ((int)MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED) +#define MBEDTLS_ERR_AES_OUT_OF_RESOURCES ((int)MBEDTLS_ECODE_AESDRV_OUT_OF_RESOURCES) +#define MBEDTLS_ERR_AES_INVALID_PARAM ((int)MBEDTLS_ECODE_AESDRV_INVALID_PARAM) + +#if defined(MBEDTLS_AES_ALT) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined( MBEDTLS_SLCL_PLUGINS ) +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + +/** + * \brief AES asynchronous context structure + */ +typedef struct +{ + AESDRV_BlockCipherAsynchContext_t aesdrv_asynch_ctx;/*!< AESDRV asynchronous + context */ +} +mbedtls_aes_asynch_context; + +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ +#endif /* #if defined( MBEDTLS_SLCL_PLUGINS ) */ + +/** + * \brief AES context structure + */ +typedef struct +{ +#if defined( MBEDTLS_SLCL_PLUGINS ) + AESDRV_Context_t aesdrv_ctx; /*!< AESDRV context */ + mbedtls_device_io_mode io_mode; /*!< I/O mode */ + mbedtls_device_io_mode_specific io_mode_specific; /*!< I/O mode specific + data */ +#endif + unsigned int keybits; /*!< size of key */ + uint32_t key[8]; /*!< AES key 128 or 256 bits */ +} +mbedtls_aes_context; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +#if defined( MBEDTLS_SLCL_PLUGINS ) +/** + * \brief + * Set the device instance of an AES context. + * + * \details + * This function sets the AES/CRYPTO device instance of an AES context. + * Subsequent calls to AES API functions with this context will use the + * new AES/CRYPTO device instance. + * + * \param[in] ctx + * AES device context. + * + * \param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref aes.h. + ******************************************************************************/ +int mbedtls_aes_set_device_instance(mbedtls_aes_context *ctx, + unsigned int devno); + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/** + * \brief Set an AES context in asynchronous mode. + * + * \details + * This function enables or disables asynchronous (non-blocking) mode of an + * AES context. In order to enable, the user must set the + * @p asynch_ctx parameter to point to an asynchronous aes context structure + * @ref mbedtls_aes_asynch_context. Subsequent calls to the AES API + * functions with the specified context will behave asynchronously, i.e. + * initiate the hardware to execute the operation and return as soon as + * possible. The user may specify a callback function by setting the + * @p asynch_callback parameter which will called when the operation has + * completed. + * In order to disable, the user must set the @p asynch_context parameter + * to NULL. All subsequent calls to AES API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * \param ctx AES context + * \param asynch_ctx AES asynchronous context structure + * \param asynch_callback Asynchronous callback + * \param user_arg User specific argument which will be + * sent to callback. + * + * \return 0 if successful, or error code + */ +int mbedtls_aes_set_asynch( mbedtls_aes_context *ctx, + mbedtls_aes_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* user_arg ); + +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/** + * \brief + * Set the device I/O mode of an AES context. + * + * \details + * This function sets the device data I/O mode of an AES context. The data + * can be moved by Core CPU, DMA or BUFC between CRYPTO and RAM. + * + * \param[in] ctx + * AES device context. + * + * \param[in] mode + * I/O mode (Core CPU, DMA or BUFC). + * + * \param[in] specific + * I/O mode specific configuration \ref mbedtls_device_io_mode_specific. + * + * \warning + * If BUFC is selected (\ref MBEDTLS_DEVICE_IO_MODE_BUFC), this function does + * not enable the BUFC clock and does not do any global BUFC initialization. + * I.e. the user is responsible for performing BUFC initialization prior to + * calling this function. + * If DMA is selected (\ref MBEDTLS_INCLUDE_IO_MODE_DMA), this function + * performs full DMA driver initialization by calling DMADRV_Init + * (non-destructive) and allocates DMA channel resources to be used by CCM. + * + * \return + * 0 if success. Error code if failure, see \ref aes.h. + ******************************************************************************/ +int mbedtls_aes_set_device_io_mode( mbedtls_aes_context *ctx, + mbedtls_device_io_mode mode, + mbedtls_device_io_mode_specific *specific ); + +#endif + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \details + * TODO: doc asynch mode output buffer not ready until completion + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_AES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_aes) */ + +#endif /* MBEDTLS_AES_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aesdrv.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aesdrv.h new file mode 100644 index 00000000000..e29a46699b0 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/aesdrv.h @@ -0,0 +1,213 @@ +/** + * \file aesdrv.h + * + * \brief Definitions for AES based ciphers with CRYPTO hw acceleration + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SILICON_LABS_AESDRV_H +#define __SILICON_LABS_AESDRV_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "em_device.h" +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) + +#include "mbedtls_ecode.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + ******************************* ERROR CODES ********************************** + ******************************************************************************/ + +#define MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED (MBEDTLS_ECODE_AESDRV_BASE | 0x1) +#define MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED (MBEDTLS_ECODE_AESDRV_BASE | 0x2) +#define MBEDTLS_ECODE_AESDRV_OUT_OF_RESOURCES (MBEDTLS_ECODE_AESDRV_BASE | 0x3) +#define MBEDTLS_ECODE_AESDRV_INVALID_PARAM (MBEDTLS_ECODE_AESDRV_BASE | 0x4) + +/******************************************************************************* + ******************************* TYPEDEFS ********************************** + ******************************************************************************/ + +/** Enum defines which data I/O mode to use for moving data to/from the + AES/CRYPTO hardware module. */ +typedef enum +{ + aesdrvIoModeCore, /** Core CPU moves data to/from the data registers. */ + + aesdrvIoModeBufc, /** Buffer Controller moves data to/from the CRYPTO + data registers. */ + + aesdrvIoModeDma /** DMA moves data to/from the CRYPTO data registers. */ +} AESDRV_IoMode_t; + +/** DMA I/O mode specific configuration structure. */ +typedef struct +{ + unsigned int dmaChIn; /**< DMA input channel. Allocated by AESDRV. */ + unsigned int dmaChOut; /**< DMA output channel. Allocated by AESDRV. */ +} AESDRV_DmaConfig_t; + +#if defined(BUFC_PRESENT) +/** BUFC I/O mode specific configuration structure. */ +typedef struct +{ + uint8_t bufId; /**< BUFC buffer id. Must be setup by user. */ +} AESDRV_BufcConfig_t; +#endif + +/** Data I/O mode specific configuration structure. */ +typedef union +{ + AESDRV_DmaConfig_t dmaConfig; +#if defined(BUFC_PRESENT) + AESDRV_BufcConfig_t bufcConfig; +#endif +} AESDRV_IoModeSpecific_t; + +/** Prototype of counter callback function provided by user. */ +typedef void (*AESDRV_CtrCallback_t)(uint8_t *ctr); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * AESDRV asynchronous (non-blocking) operation completion callback function. + * + * @details + * The callback function is called when an asynchronous (non-blocking) + * AES operation has completed. + * + * @param[in] result + * The result of the AES operation. + * + * @param[in] userArgument + * Optional user defined argument supplied when starting the asynchronous + * AES operation. + ******************************************************************************/ +typedef void (*AESDRV_AsynchCallback_t)(int result, void* userArgument); + +/** AESDRV cipher modes, used to specify type of asynchronous context. */ +typedef enum +{ + cipherModeNone, + cipherModeBlockCipher, /**< Basic AES block cipher modes (CBC, CFB etc.) */ + cipherModeCcm, /**< CCM and CCM* - Counter Mode with CBC-MAC */ + cipherModeCcmBle, /**< CCM optimized for BLE. */ + cipherModeCmac, /**< Cipher-based Message Authentication Code - + variation of CBC-MAC, equivalent to OMAC1 */ + cipherModeGcm /**< Galois/Counter mode including message + authentication code (GMAC).*/ +} AESDRV_CipherMode_t; + +/** AESDRV Context structures.*/ + +/** Context structure for asynchronous basic AES block cipher operations. */ +typedef struct +{ + unsigned int remainingBlocks; + uint32_t* pBlockIn; + uint32_t* pBlockOut; + uint8_t* pInitialVector; + AESDRV_AsynchCallback_t asynchCallback; + void* asynchCallbackArgument; +} AESDRV_BlockCipherAsynchContext_t; + +/** Context structure for asynchronous CCM(*) and GCM operations. */ +typedef struct +{ + const uint8_t* pHdr; + const uint8_t* pDataInput; + uint8_t* pDataOutput; + uint32_t la; + uint32_t lm; + uint32_t hdrLength; + uint32_t dataLength; + uint8_t* pAuthTag; + uint8_t authTagLength; + bool encryptingHeader; + bool encrypt; + AESDRV_AsynchCallback_t asynchCallback; + void* asynchCallbackArgument; +} AESDRV_CCM_AsynchContext_t, AESDRV_GCM_AsynchContext_t; + +/** Context structure for asynchronous CMAC operations. */ +typedef struct +{ + uint32_t* dataPointer; + uint32_t dataBlocks; + uint32_t lastBlock[4]; + uint8_t* digest; + uint16_t digestLengthBits; + bool encrypt; + AESDRV_AsynchCallback_t asynchCallback; + void* asynchCallbackArgument; +} AESDRV_CMAC_AsynchContext_t; + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) +#include "cryptodrv.h" + +/* Main AESDRV context structure. */ +typedef struct +{ + CRYPTODRV_Context_t cryptodrvContext; /**< CRYPTO driver context */ + AESDRV_IoMode_t ioMode; /**< Data I/O mode. */ + AESDRV_IoModeSpecific_t ioModeSpecific; /**< Data I/O mode specific + config. */ + bool authTagOptimize; /**< Enable/disable optimized + handling of authentication + tag in CCM/GCM. Tag + optimization expects tag size + 0,4,8,12 or 16 bytes.*/ +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + + AESDRV_CipherMode_t cipherMode; /**< Asynch mode */ + void* pAsynchContext; /**< Asynch context */ + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +} AESDRV_Context_t; + +#elif ( defined(AES_COUNT) && (AES_COUNT > 0) ) + +typedef struct +{ + uint32_t ccmCounter[4]; /**< CCM counter */ +} AESDRV_Context_t; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ + +#endif /* __SILICON_LABS_AESDRV_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ccm_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ccm_alt.h new file mode 100644 index 00000000000..b6ec9a4b580 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ccm_alt.h @@ -0,0 +1,313 @@ +/** + * \file ccm_alt.h + * + * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_CCM_ALT_H +#define MBEDTLS_CCM_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_ccm CBC-MAC (CCM) for 128-bit block ciphers + * \brief CRYPTO hardware accelerated counter with CBC-MAC (CCM) for 128-bit block ciphers. + * \{ + ******************************************************************************/ + +#if defined( MBEDTLS_CCM_ALT ) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "aesdrv.h" +#include "sl_crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/** + * \brief CCM asynchronous context structure + */ +typedef struct +{ + AESDRV_CCM_AsynchContext_t aesdrv_asynch_ctx; /*!< AESDRV CCM asynchronous + context */ +} +mbedtls_ccm_asynch_context; +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/** + * \brief CCM context structure + */ +typedef struct +{ + AESDRV_Context_t aesdrv_ctx; /*!< AESDRV context */ + unsigned int keybits; /*!< size of key */ + uint32_t key[8]; /*!< AES key 128 or 256 bits */ + mbedtls_device_io_mode io_mode; /*!< I/O mode */ + mbedtls_device_io_mode_specific io_mode_specific; /*!< IO mode specific + data. */ +} +mbedtls_ccm_context; + +/** + * \brief Initialize CCM context (just makes references valid) + * Makes the context ready for mbedtls_ccm_setkey() or + * mbedtls_ccm_free(). + * + * \param ctx CCM context to initialize + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); + +/** + * \brief + * Set the device instance of an CCM context. + * + * \details + * This function sets the AES/CRYPTO device instance of an CCM context. + * Subsequent calls to CCM API functions with this context will use the + * new AES/CRYPTO device instance. + * + * \param[in] ctx + * CCM device context. + * + * \param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref ccm.h. + ******************************************************************************/ +int mbedtls_ccm_set_device_instance(mbedtls_ccm_context* ctx, + unsigned int devno); + +/** + * \brief + * Set the device I/O mode of an CCM context. + * + * \details + * This function sets the device data I/O mode of an CCM context. The data + * can be moved by Core CPU, DMA or BUFC between CRYPTO and RAM. + * + * \param[in] ctx + * CCM device context. + * + * \param[in] mode + * I/O mode (Core CPU, DMA or BUFC). + * + * \param[in] specific + * I/O mode specific configuration \ref mbedtls_device_io_mode_specific. + * + * \warning + * If BUFC is selected (\ref MBEDTLS_DEVICE_IO_MODE_BUFC), this function does + * not enable the BUFC clock and does not do any global BUFC initialization. + * I.e. the user is responsible for performing BUFC initialization prior to + * calling this function. + * If DMA is selected (\ref MBEDTLS_INCLUDE_IO_MODE_DMA), this function + * performs full DMA driver initialization by calling DMADRV_Init + * (non-destructive) and allocates DMA channel resources to be used by CCM. + * + * \return + * 0 if success. Error code if failure, see \ref ccm.h. + ******************************************************************************/ +int mbedtls_ccm_set_device_io_mode +( + mbedtls_ccm_context* ctx, + mbedtls_device_io_mode mode, + mbedtls_device_io_mode_specific* specific + ); + +/** + * \brief CCM initialization (encryption and decryption) + * + * \param ctx CCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits key size in bits (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + +/** + * \brief Set an CCM context in asynchronous mode. + * + * \details + * This function enables or disables asynchronous (non-blocking) mode of an + * CCM context. In order to enable, the user must set the + * @p asynch_ctx parameter to point to an asynchronous ccm context structure + * @ref mbedtls_ccm_asynch_context. Subsequent calls to the CCM API + * functions with the specified context will behave asynchronously, i.e. + * initiate the hardware to execute the operation and return as soon as + * possible. The user may specify a callback function by setting the + * @p asynch_callback parameter which will called when the operation has + * completed. + * In order to disable, the user must set the @p asynch_context parameter + * to NULL. All subsequent calls to CCM API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * \param ctx CCM context + * \param asynch_ctx CCM asynchronous context structure + * \param asynch_callback Asynchronous callback + * \param user_arg User specific argument which will be + * sent to callback. + * + * \return 0 if successful, or error code + */ +int mbedtls_ccm_set_asynch( mbedtls_ccm_context *ctx, + mbedtls_ccm_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* user_arg ); + +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/** + * \brief Free a CCM context and underlying cipher sub-context + * + * \param ctx CCM context to free + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM buffer encryption + * + * \param ctx CCM context + * \param length length of the input data in bytes + * \param iv nonce (initialization vector) + * \param iv_len length of IV in bytes + * must be 2, 3, 4, 5, 6, 7 or 8 + * \param add additional data + * \param add_len length of additional data in bytes + * must be less than 2^16 - 2^8 + * \param input buffer holding the input data + * \param output buffer for holding the output data + * must be at least 'length' bytes wide + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate in bytes + * must be 4, 6, 8, 10, 14 or 16 + * + * \note The tag is written to a separate buffer. To get the tag + * concatenated with the output as in the CCM spec, use + * tag = output + length and make sure the output buffer is + * at least length + tag_len wide. + * + * \return 0 if successful + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief CCM buffer authenticated decryption + * + * \param ctx CCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); + +/** + * \brief CCM buffer encryption optimized for BLE + * + * \param ctx CCM context + * \param data Input/output buffer of payload data of BLE packet + * \param length length of input data + * \param iv nonce (initialization vector) + * must be 13 bytes + * \param header header of BLE packet (1 byte) + * \param tag buffer where the BLE packet tag (4 bytes) will be written + * + * \return 0 if successful + */ +int mbedtls_ccm_encrypt_and_tag_ble( mbedtls_ccm_context *ctx, + unsigned char *data, + size_t length, + const unsigned char *iv, + unsigned char header, + unsigned char *tag ); + +/** + * \brief CCM buffer authenticated decryption optimized for BLE + * + * \param ctx CCM context + * \param data Input/output buffer of payload data of BLE packet + * \param length length of input data + * \param iv nonce (initialization vector) + * must be 13 bytes + * \param header header of BLE packet (1 byte) + * \param tag authentication tag of BLE packet (4 bytes) + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match payload + */ +int mbedtls_ccm_auth_decrypt_ble( mbedtls_ccm_context *ctx, + unsigned char *data, + size_t length, + const unsigned char *iv, + unsigned char header, + unsigned char *tag ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ccm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined( MBEDTLS_CCM_ALT ) */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_ccm) */ + +#endif /* MBEDTLS_CCM_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac.h new file mode 100644 index 00000000000..58cb00e46a2 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac.h @@ -0,0 +1,47 @@ +/** + * \file cmac.h + * + * \brief CMAC cipher mode based on 128 bit AES. + * + * Copyright (C) 2016, Silicon Labs, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of the mbedTLS plugins package from Silicon Labs + */ +#ifndef MBEDTLS_CMAC_H +#define MBEDTLS_CMAC_H + +/* + * This file implements CMAC (Cipher-based Message Authentication Code) + * cipher mode encryption/decryption based on 128 bit AES. + * For a general description please see + * https://en.wikipedia.org/wiki/CMAC + * or for detailed specification see + * http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf + * http://dl.acm.org/citation.cfm?id=2206249 + */ + +#if defined( MBEDTLS_CMAC_ALT ) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "cmac_alt.h" + +#else /* #if defined( MBEDTLS_CMAC_ALT ) */ + +// Regular implementation does not exist yet. + +#endif /* #if defined( MBEDTLS_CMAC_ALT ) */ + +#endif /* MBEDTLS_CMAC_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac_alt.h new file mode 100644 index 00000000000..014c2e55ac9 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cmac_alt.h @@ -0,0 +1,231 @@ +/** + * \file cmac_alt.h + * + * \brief CMAC cipher mode based on 128 bit AES. + * + * Copyright (C) 2016, Silicon Labs, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_CMAC_ALT_H +#define MBEDTLS_CMAC_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_cmac CMAC cipher mode based on 128 bit AES + * \brief CRYPTO hardware accelerated CMAC (Cipher-based Message Authentication Code) + * \details + * Encryption and decryption based on 128-bit AES. + * For a general description please see + * https://en.wikipedia.org/wiki/CMAC + * or for detailed specification see + * http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf + * http://dl.acm.org/citation.cfm?id=2206249 + * \{ + ******************************************************************************/ + +#if defined( MBEDTLS_CMAC_ALT ) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "aesdrv.h" +#include "sl_crypto.h" +#include "cipher.h" +#include + +#define MBEDTLS_ERR_CMAC_BAD_INPUT ((int)MBEDTLS_ERR_CMAC_BASE | 0x01) +#define MBEDTLS_ERR_CMAC_AUTH_FAILED ((int)MBEDTLS_ERR_CMAC_BASE | 0x02) + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/** + * \brief CMAC asynchronous context structure + */ +typedef struct +{ + AESDRV_CMAC_AsynchContext_t aesdrv_asynch_ctx; /*!< AESDRV CMAC asynchronous + context */ +} +mbedtls_cmac_asynch_context; +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/** + * \brief CMAC context structure + */ +typedef struct +{ + AESDRV_Context_t aesdrv_ctx; /*!< AESDRV context */ + unsigned int keybits; /*!< size of key */ + uint32_t key[8]; /*!< AES key 128 or 256 bits */ +} +mbedtls_cmac_context; + +/** + * \brief Initialize CMAC context (just makes references valid) + * Makes the context ready for mbedtls_cmac_setkey() or + * mbedtls_cmac_free(). + * + * \param ctx CMAC context to initialize + */ +void mbedtls_cmac_init( mbedtls_cmac_context *ctx ); + +/** + * \brief + * Set the device instance of an CMAC context. + * + * \details + * This function sets the AES/CRYPTO device instance of an CMAC context. + * Subsequent calls to CMAC API functions with this context will use the + * new AES/CRYPTO device instance. + * + * \param[in] ctx + * CMAC device context. + * + * \param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref cmac.h. + ******************************************************************************/ +int mbedtls_cmac_set_device_instance(mbedtls_cmac_context* ctx, + unsigned int devno); + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/** + * \brief Set an CMAC context in asynchronous mode. + * + * \details + * This function enables or disables asynchronous (non-blocking) mode of an + * CMAC context. In order to enable, the user must set the + * @p asynch_ctx parameter to point to an asynchronous cmac context structure + * @ref mbedtls_cmac_asynch_context. Subsequent calls to the CMAC API + * functions with the specified context will behave asynchronously, i.e. + * initiate the hardware to execute the operation and return as soon as + * possible. The user may specify a callback function by setting the + * @p asynch_callback parameter which will called when the operation has + * completed. + * In order to disable, the user must set the @p asynch_ctx parameter + * to NULL. All subsequent calls to CMAC API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * \param ctx CMAC context + * \param asynch_ctx CMAC asynchronous context structure + * \param asynch_callback Asynchronous callback + * \param user_arg User specific argument which will be + * sent to callback. + * + * \return 0 if successful, or error code + */ +int mbedtls_cmac_set_asynch( mbedtls_cmac_context *ctx, + mbedtls_cmac_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* user_arg ); +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/** + * \brief CMAC initialization (encryption and decryption) + * + * \param ctx CMAC context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits key size in bits (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_cmac_setkey( mbedtls_cmac_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Free a CMAC context and underlying cipher sub-context + * + * \param ctx CMAC context to free + */ +void mbedtls_cmac_free( mbedtls_cmac_context *ctx ); + +/** + * \brief Generate CMAC tag + * + * \param ctx CMAC context + * \param data buffer holding the input data + * \param data_len length of the input data in bits + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate in bits + * must be less than 128 bits + * + * \note The tag is written to a separate buffer. To get the tag + * concatenated with the output as in the CMAC spec, use + * tag = data + length and make sure the output buffer is + * at least data_len + tag_len wide. + * + * \return 0 if successful + */ +int mbedtls_cmac_generate_tag( mbedtls_cmac_context *ctx, + const unsigned char *data, + size_t data_len, + unsigned char *tag, + size_t tag_len ); + +/** + * \brief Verify CMAC tag + * + * \param ctx CMAC context + * \param data buffer holding the input data + * \param data_len length of the input data in bits + * \param tag buffer holding the tag + * \param tag_len length of the tag in bits + * must be less than 128 bits + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CMAC_AUTH_FAILED if tag does not match data + */ +int mbedtls_cmac_verify_tag( mbedtls_cmac_context *ctx, + const unsigned char *data, + size_t data_len, + unsigned char *tag, + size_t tag_len ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CMAC_C) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_cmac_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_CMAC_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined( MBEDTLS_CMAC_ALT ) */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_cmac) */ + +#endif /* MBEDTLS_CMAC_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cryptodrv.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cryptodrv.h new file mode 100644 index 00000000000..fa446454383 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/cryptodrv.h @@ -0,0 +1,149 @@ +/* + * \file cryptodrv.h + * + * \brief CRYPTO driver definitions including CRYPTO preemption and + * asynchronous (non-blocking) support. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __SILICON_LABS_CRYPTODRV_H +#define __SILICON_LABS_CRYPTODRV_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "em_device.h" + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) + +#include "mbedtls_ecode.h" +#include "em_crypto.h" +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) +#include "dmadrv.h" +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + ******************************* ERROR CODES ********************************** + ******************************************************************************/ + +#define MBEDTLS_ECODE_CRYPTODRV_OPERATION_ABORTED (MBEDTLS_ECODE_CRYPTODRV_BASE | 0x1) /**< Operation was aborted. Possibly by higher priority task. The user will need to retry the operation in order to complete. */ +#define MBEDTLS_ECODE_CRYPTODRV_BUSY (MBEDTLS_ECODE_CRYPTODRV_BASE | 0x2) /**< The CRYPTO module is busy. */ + +/******************************************************************************* + ******************************* TYPEDEFS ********************************** + ******************************************************************************/ + +#if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) + +/** Context of CRYPTO hardware module. */ +typedef struct +{ + uint32_t CTRL; /**< Control Register */ + uint32_t WAC; /**< Wide Arithmetic Configuration */ + uint32_t SEQCTRL; /**< Sequence Control */ + uint32_t SEQCTRLB; /**< Sequence Control B */ + uint32_t IEN; /**< Interrupt Enable Register */ + uint32_t SEQ[5]; /**< Instruction Sequence registers */ + CRYPTO_DData_TypeDef DDATA[5]; /**< DDATA registers. Covers all data registers + of CRYPTO, including DATA(128 bit), DDATA (256bit), + QDATA (512bit) registers. */ +} CRYPTO_Context_t; + +#endif /* #if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) */ + +/***************************************************************************//** + * @brief + * CRYPTODRV asynchronous (non-blocking) operation completion callback function. + * + * @details + * The callback function is called when an asynchronous (non-blocking) + * CRYPTO operation has completed. + * + * @param[in] result + * The result of the CRYPTO operation. + * + * @param[in] userArgument + * Optional user defined argument supplied when starting the asynchronous + * CRYPTO operation. + ******************************************************************************/ +typedef void (*CRYPTODRV_AsynchCallback_t)(void* userArgument); + +/** CRYPTO device structure. */ +typedef struct +{ + CRYPTO_TypeDef* crypto; /**< CRYPTO hw instance */ + IRQn_Type irqn; /**< CRYPTO irq number */ + uint32_t clk; /**< CRYPTO clock */ +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) + void* pCryptoOwner; /**< Pointer to pointer of + CRYPTO unit owner */ + uint32_t* pNvicIser; /**< Pointer to storage + of NVIC ISER values. */ +#endif +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + DMADRV_PeripheralSignal_t dmaReqSigChIn; /**< DMA req signal channel in */ + DMADRV_PeripheralSignal_t dmaReqSigChOut;/**< DMA req signal channel out */ +#endif +} CRYPTO_Device_t; + +/** CRYPTODRV operation context. */ +typedef struct +{ + const CRYPTO_Device_t* device; /**< CRYPTO hw instance */ + +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) + + CRYPTO_Context_t cryptoContext; /**< CRYPTO hw context */ + bool aborted; /**< 'true' if an ongoing CRYPTO + instruction sequence was + aborted.*/ + unsigned long threadPriority; /**< Priority of thread/context */ + void* threadId; /**< Pointer to thread identifier*/ + + /* Double linked-list for CRYPTO context preemption. */ + void* pContextPreempted; /* Context preempted by _this_ + context. */ + void* pContextPreemptor; /* Context of preemptor + of _this_ context. */ +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + + CRYPTODRV_AsynchCallback_t asynchCallback; /**< Asynch callback */ + void* asynchCallbackArgument; /**< Parameter for + asynch callback */ + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +#endif /* #if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) */ + +} CRYPTODRV_Context_t; + +#ifdef __cplusplus +} +#endif + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ + +#endif /* #ifndef __SILICON_LABS_CRYPTODRV_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecode.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecode.h new file mode 100644 index 00000000000..66687e59c79 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecode.h @@ -0,0 +1,73 @@ +/***************************************************************************//** + * @file ecode.h + * @brief Energy Aware drivers error code definitions. + * @version 4.4.0 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * This file is licensed under the Silabs License Agreement. See the file + * "Silabs_License_Agreement.txt" for details. Before using this software for + * any purpose, you must agree to the terms of that agreement. + * + ******************************************************************************/ +#ifndef __SILICON_LABS_ECODE_H__ +#define __SILICON_LABS_ECODE_H__ + +/***************************************************************************//** + * @defgroup emdrv EMDRV + * @brief energyAware drivers + * @details + * + * EMDRV is a set of function specific high performance drivers for EFM32, EZR32 + * and EFR32 on-chip peripherals. Drivers are typically DMA based and are using + * all available low-energy features. For most drivers, the API offers both + * synchronous and asynchronous functions. The APIs are fully reentrant and + * callback based. + * + * Most drivers are compile-time configurable to allow the highest possible + * code size optimization for the application. Compile-time configuration is + * defined in *_config.h files. Templates for the configuration files can be + * found in emdrv\\config. + * + * @note + * EMDRV APIs use Ecode_t to return status. + * @n @n + * With the exception of ezradiodrv, EMDRV does not implement RF support. + * Please refer to stack documentation for more information. + * + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @brief Typedef for API function errorcode return values. + * + * @details + * Bit 24-31: sub-system, for example emLib, eaDrivers,... @n + * Bit 16-23: module, for example UART, LCD,... @n + * Bit 0-15: error code, specific error code + ******************************************************************************/ +typedef uint32_t Ecode_t; + +#define ECODE_EMDRV_BASE ( 0xF0000000 ) ///< Base value for all EMDRV errorcodes. + +#define ECODE_OK ( 0 ) ///< Generic success return value. + +#define ECODE_EMDRV_RTCDRV_BASE ( ECODE_EMDRV_BASE | 0x00001000 ) ///< Base value for RTCDRV error codes. +#define ECODE_EMDRV_SPIDRV_BASE ( ECODE_EMDRV_BASE | 0x00002000 ) ///< Base value for SPIDRV error codes. +#define ECODE_EMDRV_NVM_BASE ( ECODE_EMDRV_BASE | 0x00003000 ) ///< Base value for NVM error codes. +#define ECODE_EMDRV_USTIMER_BASE ( ECODE_EMDRV_BASE | 0x00004000 ) ///< Base value for USTIMER error codes. +#define ECODE_EMDRV_AESDRV_BASE ( ECODE_EMDRV_BASE | 0x00005000 ) ///< Base value for AESDRV error codes. +#define ECODE_EMDRV_ECC_BASE ( ECODE_EMDRV_BASE | 0x00006000 ) ///< Base value for ECC error codes. +#define ECODE_EMDRV_UARTDRV_BASE ( ECODE_EMDRV_BASE | 0x00007000 ) ///< Base value for UARTDRV error codes. +#define ECODE_EMDRV_DMADRV_BASE ( ECODE_EMDRV_BASE | 0x00008000 ) ///< Base value for DMADRV error codes. +#define ECODE_EMDRV_EZRADIODRV_BASE ( ECODE_EMDRV_BASE | 0x00009000 ) ///< Base value for EZRADIODRV error codes. +#define ECODE_EMDRV_SHADRV_BASE ( ECODE_EMDRV_BASE | 0x0000A000 ) ///< Base value for SHADRV error codes. +#define ECODE_EMDRV_RSADRV_BASE ( ECODE_EMDRV_BASE | 0x0000B000 ) ///< Base value for RSADRV error codes. +#define ECODE_EMDRV_CRYPTO_BASE ( ECODE_EMDRV_BASE | 0x0000C000 ) ///< Base value for CRYPTO error codes. +#define ECODE_EMDRV_TEMPDRV_BASE ( ECODE_EMDRV_BASE | 0x0000D000 ) ///< Base value for TEMPDRV error codes. + +/** @} (end addtogroup emdrv) */ + +#endif // __SILICON_LABS_ECODE_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecp_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecp_alt.h new file mode 100644 index 00000000000..b7a0e4e793f --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/ecp_alt.h @@ -0,0 +1,703 @@ +/** + * \file ecp_alt.h + * + * \brief Elliptic curves over GF(p) + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_ECP_ALT_H +#define MBEDTLS_ECP_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_ecp Elliptic curves over GF(p) + * \brief CRYPTO hardware accelerated elliptic curves over GF(p). + * \{ + ******************************************************************************/ + +#if defined( MBEDTLS_ECP_ALT ) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "cryptodrv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain parameters (curve, subgroup and generator) identifiers. + * + * Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only well-known domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, + MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ + MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ + MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */ + MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ +} mbedtls_ecp_group_id; + +/** + * Number of supported curves (plus one for NONE). + * + * (Montgomery curves excluded for now.) + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/** + * Curve information for use by other modules + */ +typedef struct +{ + mbedtls_ecp_group_id grp_id; /*!< Internal identifier */ + uint16_t tls_id; /*!< TLS NamedCurve identifier */ + uint16_t bit_size; /*!< Curve size in bits */ + const char *name; /*!< Human-friendly name */ +} mbedtls_ecp_curve_info; + +/** + * \brief ECP point structure (jacobian coordinates) + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or Z == 1. (Other + * values of Z are used by internal functions only.) + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, X and Y are its standard (affine) coordinates. + */ +typedef struct +{ + mbedtls_mpi X; /*!< the point's X coordinate */ + mbedtls_mpi Y; /*!< the point's Y coordinate */ + mbedtls_mpi Z; /*!< the point's Z coordinate */ +} +mbedtls_ecp_point; + +/** + * \brief ECP group structure + * + * We consider two types of curves equations: + * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) + * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (Curve25519 + draft) + * In both cases, a generator G for a prime-order subgroup is fixed. In the + * short weierstrass, this subgroup is actually the whole curve, and its + * cardinal is denoted by N. + * + * In the case of Short Weierstrass curves, our code requires that N is an odd + * prime. (Use odd in mbedtls_ecp_mul() and prime in mbedtls_ecdsa_sign() for blinding.) + * + * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is + * the quantity actually used in the formulas. Also, nbits is not the size of N + * but the required size for private keys. + * + * If modp is NULL, reduction modulo P is done using a generic algorithm. + * Otherwise, it must point to a function that takes an mbedtls_mpi in the range + * 0..2^(2*pbits)-1 and transforms it in-place in an integer of little more + * than pbits, so that the integer may be efficiently brought in the 0..P-1 + * range by a few additions or substractions. It must return 0 on success and + * non-zero on failure. + */ +typedef struct +{ + mbedtls_ecp_group_id id; /*!< internal group identifier */ + mbedtls_mpi P; /*!< prime modulus of the base field */ + mbedtls_mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + mbedtls_mpi B; /*!< 1. B in the equation, or 2. unused */ + mbedtls_ecp_point G; /*!< generator of the (sub)group used */ + mbedtls_mpi N; /*!< 1. the order of G, or 2. unused */ + size_t pbits; /*!< number of bits in P */ + size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ + unsigned int h; /*!< internal: 1 if the constants are static */ + int (*modp)(mbedtls_mpi *); /*!< function for fast reduction mod P */ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< unused */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< unused */ + void *t_data; /*!< unused */ + mbedtls_ecp_point *T; /*!< pre-computed points for ecp_mul_comb() */ + size_t T_size; /*!< number for pre-computed points */ + + CRYPTODRV_Context_t cryptodrv_ctx; +} +mbedtls_ecp_group; + +/** + * \brief ECP key pair structure + * + * A generic key pair that could be used for ECDSA, fixed ECDH, etc. + * + * \note Members purposefully in the same order as struc mbedtls_ecdsa_context. + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_MAX_BITS) +/** + * Maximum size of the groups (that is, of N and P) + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#endif + +#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) +#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 ) + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: 6. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade memory for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * The cost is increasing EC peak memory usage by a factor roughly 2. + * + * Change this value to 0 to reduce peak memory usage. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/* \} name SECTION: Module settings */ + +/* + * Point formats, from RFC 4492's enum ECPointFormat + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format */ + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< ECCurveType's named_curve */ + +/** + * \brief + * Set the device instance of an ECP group context. + * + * \details + * This function sets the CRYPTO device instance of an ECP group context. + * Subsequent calls to the ECP functions with this group context will use the + * new CRYPTO device instance. + * + * \param[in] grp + * ECP group context. + * + * \param[in] devno + * CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref aes.h. + ******************************************************************************/ +int mbedtls_ecp_set_device_instance(mbedtls_ecp_group *grp, + unsigned int devno); + +/** + * \brief Get the list of supported curves in order of preferrence + * (full information) + * + * \return A statically allocated array, the last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief Get the list of supported curves in order of preferrence + * (grp_id only) + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief Get curve information from an internal group identifier + * + * \param grp_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief Get curve information from a TLS NamedCurve value + * + * \param tls_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief Get curve information from a human-readable name + * + * \param name The name + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief Initialize a point (as zero) + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief Initialize a group (to something meaningless) + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief Initialize a key pair (as an invalid one) + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief Free the components of a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief Free the components of an ECP group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief Free the components of a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +/** + * \brief Copy the contents of point Q into P + * + * \param P Destination point + * \param Q Source point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief Copy the contents of a group object + * + * \param dst Destination group + * \param src Source group + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); + +/** + * \brief Set a point to zero + * + * \param pt Destination point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Tell if a point is zero + * + * \param pt Point to test + * + * \return 1 if point is zero, 0 otherwise + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Compare two points + * + * \note This assumes the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P First point to compare + * \param Q Second point to compare + * + * \return 0 if the points are equal, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief Import a non-zero point from two ASCII strings + * + * \param P Destination point + * \param radix Input numeric base + * \param x First affine coordinate as a null-terminated string + * \param y Second affine coordinate as a null-terminated string + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief Export a point into unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to export + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param olen Length of the actual output + * \param buf Output buffer + * \param buflen Length of the output buffer + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ); + +/** + * \brief Import a point from unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to import + * \param buf Input buffer + * \param ilen Actual length of input + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + * \note This function does NOT check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() for + * that. + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief Import a point from a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Destination point + * \param buf $(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after the ECPoint on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief Export a point as a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Point to export + * \param format Export format + * \param olen length of data written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Set a group using well-known domain parameters + * + * \param grp Destination group + * \param index Index in the list of well-known domain parameters + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups + * + * \note Index should be a value of RFC 4492's enum NamedCurve, + * usually in the form of a MBEDTLS_ECP_DP_XXX macro. + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id index ); + +/** + * \brief Set a group from a TLS ECParameters record + * + * \param grp Destination group + * \param buf &(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after ECParameters on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); + +/** + * \brief Write the TLS ECParameters record for a group + * + * \param grp ECP group used + * \param olen Number of bytes actually written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Multiplication by an integer: R = m * P + * (Not thread-safe to use same group in multiple threads) + * + * \note In order to prevent timing attacks, this function + * executes the exact same sequence of (base field) + * operations for any valid m. It avoids any if-branch or + * array index depending on the value of m. + * + * \note If f_rng is not NULL, it is used to randomize intermediate + * results in order to prevent potential timing attacks + * targeting these results. It is recommended to always + * provide a non-NULL f_rng (the overhead is negligible). + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply + * \param P Point to multiply + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m is not a valid privkey + * or P is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Multiplication and addition of two points by integers: + * R = m * P + n * Q + * (Not thread-safe to use same group in multiple threads) + * + * \note In contrast to mbedtls_ecp_mul(), this function does not guarantee + * a constant execution flow and timing. + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply P + * \param P Point to multiply by m + * \param n Integer by which to multiply Q + * \param Q Point to be multiplied by n + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m or n is not a valid privkey + * or P or Q is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); + +/** + * \brief Check that a point is a valid public key on this curve + * + * \param grp Curve/group the point should belong to + * \param pt Point to check + * + * \return 0 if point is a valid public key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note This function only checks the point is non-zero, has valid + * coordinates and lies on the curve, but not that it is + * indeed a multiple of G. This is additional check is more + * expensive, isn't required by standards, and shouldn't be + * necessary if the group used has a small cofactor. In + * particular, it is useless for the NIST groups which all + * have a cofactor of 1. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); + +/** + * \brief Check that an mbedtls_mpi is a valid private key for this curve + * + * \param grp Group used + * \param d Integer to check + * + * \return 0 if point is a valid private key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); + +/** + * \brief Generate a keypair with configurable base point + * + * \param grp ECP group + * \param G Chosen base point + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp ECP group + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp_id ECP group identifier + * \param key Destination keypair + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check a public-private key pair + * + * \param pub Keypair structure holding a public key + * \param prv Keypair structure holding a private (plus public) key + * + * \return 0 if successful (keys are valid and match), or + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA, or + * a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX code. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecp_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined( MBEDTLS_ECP_ALT ) */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_ecp) */ + +#endif /* #ifndef MBEDTLS_ECP_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/mbedtls_ecode.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/mbedtls_ecode.h new file mode 100644 index 00000000000..7804fb26ad1 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/mbedtls_ecode.h @@ -0,0 +1,64 @@ +/** + * \file mbedtls_ecode.h + * + * \brief Silicon Labs specific mbedtls error code definitions. + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_ECODE_H +#define MBEDTLS_ECODE_H + +/** + * This file defines the Silicon Labs specific mbedtls error code layout + * and values. + * + * Error code layout. + * + * The standard mbedtls error code layout use the negative space of 16 bits + * signed integers in order to support all architectures. However the standard + * mbedtls error code layout is fixed by ARM and does not define a sub-space + * for additional vendor specific error codes. Additionally the 16 bit + * requirement is not relevant for the Silicon Labs 32bit MCUs. Therefore + * Silicon Labs defines a 32 bit signed integer error code layout which does + * not use the values of the standard mbedtls error code layout given that the + * 16 most significant bits of standard mbedtls error codes are all ones (which + * should be the case when running on 32-bit architectures and the application + * does not strip off the 16 most significant bits): + * + * bit 31: Sign bit. 1 to signify that the value is part of the error + * code space. 0 for non error codes, in which case all 32 bits + * are 0 which means OK (i.e. operation succeded). + * bits 24-30: sub-system id, for example mbedtls, emdrv, etc + * bits 16-23: module id, for example UART, LCD,... + * bits 0-15: error code, specific error code + * + * The sub-system id and module id are not allowed to be all ones. + * + * Below is the list of module ids for the mbedtls sub-system. + * Module specific error codes are defined in the header file of + * each respective module. + */ + +#define MBEDTLS_ECODE_BASE ( 0xF1000000 ) /*!< Base value for all error codes. */ + +#define MBEDTLS_ECODE_AESDRV_BASE ( MBEDTLS_ECODE_BASE | 0x00005000 ) /*!< Base value for AESDRV error codes. */ +#define MBEDTLS_ECODE_ECC_BASE ( MBEDTLS_ECODE_BASE | 0x00006000 ) /*!< Base value for ECC error codes. */ +#define MBEDTLS_ECODE_SHA_BASE ( MBEDTLS_ECODE_BASE | 0x0000A000 ) /*!< Base value for SHA error codes. */ +#define MBEDTLS_ECODE_CRYPTODRV_BASE ( MBEDTLS_ECODE_BASE | 0x0000C000 ) /*!< Base value for CRYPTO error codes. */ +#define MBEDTLS_ERR_CMAC_BASE ( MBEDTLS_ECODE_AESDRV_BASE | 0xf00) /**< Base value of error codes for CMAC submodule (of AESDRV module). */ + +#endif /* #ifndef MBEDTLS_ECODE_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha1_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha1_alt.h new file mode 100644 index 00000000000..357b81596d4 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha1_alt.h @@ -0,0 +1,167 @@ +/** + * \file sha1_alt.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_SHA1_ALT_H +#define MBEDTLS_SHA1_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_sha1 SHA-1 cryptographic hash function + * \brief CRYPTO hardware accelerated SHA-1 cryptographic hash function. + * \{ + ******************************************************************************/ + +#if defined(MBEDTLS_SHA1_ALT) + +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "sl_crypto.h" +#include +#include + +#define MBEDTLS_ERR_SHA1_BAD_INPUT -0x5100 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ +#if defined( MBEDTLS_SLCL_PLUGINS ) + CRYPTODRV_Context_t cryptodrv_ctx; /*!< CRYPTODRV Context */ +#else + uint32_t state[8]; /*!< intermediate digest state */ +#endif + uint32_t total[2]; /*!< number of bytes processed */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +#if defined( MBEDTLS_SLCL_PLUGINS ) +/** + * \brief + * Set the device instance of an SHA1 context. + * + * \details + * This function sets the AES/CRYPTO device instance of an SHA1 context. + * Subsequent calls to SHA1 API functions with this context will use the + * new AES/CRYPTO device instance. + * + * \param[in] ctx + * SHA1 device context. + * + * \param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref sha1.h. + ******************************************************************************/ +int mbedtls_sha1_set_device_instance(mbedtls_sha1_context* ctx, + unsigned int devno); +#endif /* #if defined( MBEDTLS_SLCL_PLUGINS ) */ + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input Buffer holding the data. The input buffer needs to be big + * enough to hold the padding (MD-strenghtening) at the end, + * after the message of 'ilen' length. This function will + * perform MD-strengthening and append to the end of the + * input buffer. + * \param ilen length of the input data + * \param output SHA-1 checksum result + * + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, + unsigned char output[20]); + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined(MBEDTLS_SHA1_ALT) */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_sha1) */ + +#endif /* #ifndef MBEDTLS_SHA1_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha256_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha256_alt.h new file mode 100644 index 00000000000..a0f17e14515 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sha256_alt.h @@ -0,0 +1,171 @@ +/** + * \file sha256_alt.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_SHA256_ALT_H +#define MBEDTLS_SHA256_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_sha256 SHA-224 and SHA-256 cryptographic hash function + * \brief CRYPTO hardware accelerated SHA-224 and SHA-256 cryptographic hash function. + * \{ + ******************************************************************************/ + +#if defined(MBEDTLS_SHA256_ALT) + +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#include "sl_crypto.h" +#include +#include + +#define MBEDTLS_ERR_SHA256_BAD_INPUT -0x5100 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ +#if defined( MBEDTLS_SLCL_PLUGINS ) + CRYPTODRV_Context_t cryptodrv_ctx; /*!< CRYPTODRV Context */ +#else + uint32_t state[8]; /*!< intermediate digest state */ +#endif + uint32_t total[2]; /*!< number of bytes processed */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +#if defined( MBEDTLS_SLCL_PLUGINS ) +/** + * \brief + * Set the device instance of an SHA256 context. + * + * \details + * This function sets the AES/CRYPTO device instance of an SHA256 context. + * Subsequent calls to SHA256 API functions with this context will use the + * new AES/CRYPTO device instance. + * + * \param[in] ctx + * SHA256 device context. + * + * \param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * \return + * 0 if success. Error code if failure, see \ref sha256.h. + ******************************************************************************/ +int mbedtls_sha256_set_device_instance(mbedtls_sha256_context *ctx, + unsigned int devno); +#endif /* #if defined( MBEDTLS_SLCL_PLUGINS ) */ + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input Buffer holding the data. The input buffer needs to be big + * enough to hold the padding (MD-strenghtening) at the end, + * after the message of 'ilen' length. This function will + * perform MD-strengthening and append to the end of the + * input buffer. + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + * + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined(MBEDTLS_SHA256_ALT) */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_sha256) */ + +#endif /* #ifndef MBEDTLS_SHA256_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sl_crypto.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sl_crypto.h new file mode 100644 index 00000000000..3c1dc29bc02 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/sl_crypto.h @@ -0,0 +1,125 @@ +/** + * \file sl_crypto.h + * + * \brief Silicon Labs specific mbedTLS defintitions + * + * Copyright (C) 2016, Silicon Labs, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_SL_CRYPTO_H +#define MBEDTLS_SL_CRYPTO_H + +#include "em_device.h" + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined( MBEDTLS_SLCL_PLUGINS ) + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#include "cryptodrv.h" +#endif + +#include "mbedtls_ecode.h" +#include + +/** Error codes */ + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#define MBEDTLS_ERR_ABORTED ((int)MBEDTLS_ECODE_CRYPTODRV_OPERATION_ABORTED) /**< Operation was aborted. */ +#define MBEDTLS_ERR_DEVICE_BUSY ((int)MBEDTLS_ECODE_CRYPTODRV_BUSY) /**< CRYPTO/AES device busy */ +#endif +#endif /* #if defined( MBEDTLS_SLCL_PLUGINS ) */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Asynchronous (non-blocking) operation completion callback function. + * + * \details + * The callback function is called when an asynchronous (non-blocking) + * mbedtls operation has completed. + * + * \param[in] result + * The result of the asynchronous operation. + * + * \param[in] user_arg + * Optional user defined argument + ******************************************************************************/ +typedef void (*mbedtls_asynch_callback)(int result, void* user_arg); + +/** Enum defines which data I/O mode to use for moving data to/from the + AES/CRYPTO hardware module. */ +typedef enum +{ + MBEDTLS_DEVICE_IO_MODE_CORE, /*!< Core CPU moves data to/from the data + registers. */ + + MBEDTLS_DEVICE_IO_MODE_BUFC, /*!< Buffer Controller moves data to/from the + CRYPTO data registers. */ + +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + MBEDTLS_DEVICE_IO_MODE_DMA /*!< DMA moves data to/from the CRYPTO data + registers. */ +#endif +} mbedtls_device_io_mode; + +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) +/** DMA I/O mode specific configuration structure. */ +typedef struct +{ + unsigned int dma_ch_in; /*!< DMA input channel. Allocated by mbedtls. */ + unsigned int dma_ch_out; /*!< DMA output channel. Allocated by mbedtls. */ +} mbedtls_device_dma_config; +#endif + +#if defined(BUFC_PRESENT) +/** BUFC I/O mode specific configuration structure. */ +typedef struct +{ + uint8_t buf_id; /*!< BUFC buffer id. Must be setup by user. */ +} mbedtls_device_bufc_config; +#endif + +/** Data I/O mode specific configuration structure. */ +typedef union +{ +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + mbedtls_device_dma_config dma_config; /*!< DMA specific config */ +#endif +#if defined(BUFC_PRESENT) + mbedtls_device_bufc_config bufc_config; /*!< BUFC specific config */ +#endif + void* placeholder; /*!< Dummy place holder to + keep compiler happy when both + BUFC and DMA are disabled. */ +} mbedtls_device_io_mode_specific; + +#ifdef __cplusplus +} +#endif + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ + +#endif /* #ifndef MBEDTLS_SL_CRYPTO_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/timing_alt.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/timing_alt.h new file mode 100644 index 00000000000..8a2f3ff38ad --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/include/timing_alt.h @@ -0,0 +1,83 @@ +/** + * \file timing_alt.h + * + * \brief Portable interface to the CPU cycle counter + * + * Copyright (C) 2016, Silicon Labs, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBEDTLS_TIMING_ALT_H +#define MBEDTLS_TIMING_ALT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_timing Portable timing interface + * \brief Portable interface to the CPU cycle counter. + * \{ + ******************************************************************************/ + +#if defined(MBEDTLS_TIMING_ALT) + +/* SiliconLabs timing implementation */ + +#include "em_device.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize timing resources. + * + */ +void mbedtls_timing_init( void ); + +/** + * \brief Stop and free up timing resources. + * + */ +void mbedtls_timing_free( void ); + +/** + * \brief Return the CPU cycle counter value + * + */ +static inline unsigned long mbedtls_timing_hardclock( void ) +{ + return( DWT->CYCCNT ); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_TIMING_ALT */ + +/** \} (end addtogroup sl_crypto) */ +/** \} (end addtogroup sl_crypto_timing) */ + +#endif /* MBEDTLS_TIMING_ALT_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/.gitignore b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/.gitignore new file mode 100644 index 00000000000..b25c15b81fa --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr.h new file mode 100644 index 00000000000..8b318949471 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr.h @@ -0,0 +1,41 @@ +/* + * Definitions for authenticated encryption algorithms common to + * all crypto devices (AES, CRYPTO, etc.) + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SILICON_LABS_AESDRV_AUTHENCR_H +#define __SILICON_LABS_AESDRV_AUTHENCR_H + +#define CCM_MAX_DATA_LENGTH (0x10000-1) + +Ecode_t AESDRV_CCM_Generalized(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pOutputData, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt, + const bool encryptedPayload); + +#endif /* __SILICON_LABS_AESDRV_AUTHENCR_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_aes.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_aes.c new file mode 100644 index 00000000000..6ead0647f95 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_aes.c @@ -0,0 +1,701 @@ +/* + * Authenticated encryption algorithms implementation using AES hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "em_device.h" + +#if defined(AES_COUNT) && (AES_COUNT > 0) + +#if defined( AES_CTRL_KEYBUFEN ) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_internal.h" +#include "aesdrv_authencr.h" +#include "aesdrv_common_aes.h" +#include "em_aes.h" +#include "em_assert.h" +#include "string.h" + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ +static Ecode_t aesdrv_CCM_MICCompute(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encryptedPayload, + const bool encrypt); +static inline void aesdrv_CCM_CtrInit(const uint8_t* pNonce, + uint32_t* ctr, + bool ctrToZero); +static inline void aesdrv_CCM_Nonce(uint32_t* ccmCounter, + uint32_t* ctr0, + uint8_t authTagLength, + uint32_t la, + uint32_t lm); +static inline void aesdrv_CCM_AMICCompute(const uint8_t* pHdr, + uint32_t hdrLength); +static inline void aesdrv_CCM_PMICCompute(const uint8_t* pDataInput, + uint32_t length); +static inline void aesdrv_CCM_CTR128(uint32_t* ccmCounter, + uint32_t* out, + uint32_t* in, + uint32_t loopLength); +static inline void aesdrv_CCM_CTR128Single(uint32_t* ccmCounter, + uint32_t* out, + uint32_t* in); +static inline void aesdrv_CCM_DataWrite(const uint32_t* in); +static inline void aesdrv_CCM_DataRead(uint32_t* out); +static inline void aesdrv_CCM_DataRevRead(uint32_t* out); +static inline void aesdrv_CCM_XorDataWrite(const uint32_t* in); +static inline void aesdrv_CCM_XorDataRevWrite(const uint32_t* in); + +/** @endcond */ + +/******************************************************************************* + *************************** GLOBAL FUNCTIONS ****************************** + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * CCM optimized for BLE + * + * @details + * This function is an implementation of CCM optimized for Bluetooth Low Energy + * (BLE). This function assumes fixed header size (1 byte), + * fixed authentication tag (4bytes), fixed length field size (2 bytes) + * + * @param pData + * Pointer to data + * + * @param dataLength + * length of data (max. 27) + * + * @param hdr + * 1 byte header + * + * @param pKey + * 10 byte Security Key. If pKey is NULL, the current key will be used. + * + * @param pNonce + * 13 byte nonce + * + * @param encrypt + * true - encrypt + * false - decrypt + * + * @return + * ECODE_OK if success. Error code if failure. + * Encryption will always succeed. + * Decryption may fail if the authentication fails. + */ +Ecode_t AESDRV_CCMBLE(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + const uint32_t dataLength, + uint8_t hdr, + const uint8_t* pKey, + const uint8_t* pNonce, + uint8_t* pAuthTag, + const bool encrypt + ) +{ + return AESDRV_CCM(pAesdrvContext, + pData, pData, dataLength, + &hdr, 1, + pKey, 128/8, /* keyLength */ + pNonce, 13, + pAuthTag, 4, + encrypt); +} + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @brief + * Generalized, internal CCM function supporting both CCM and CCM*. + ******************************************************************************/ +Ecode_t AESDRV_CCM_Generalized(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt, + const bool encryptedPayload) +{ + int32_t i; + uint8_t lastBlock[16]; + uint32_t lastBlockLen; + uint32_t wholeBlockLen; + Ecode_t status = ECODE_OK; + const uint32_t * const _pKey = (const uint32_t *)pKey; + + if ( (keyLength != 128/8) || + (nonceLength != 13) || + (dataLength > CCM_MAX_DATA_LENGTH) ) + { + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + + /* Enable AES clock. */ + AESDRV_CLOCK_ENABLE; + + AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_XORSTART | AES_CTRL_DATASTART; + + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_pKey[i]); + } + + /* Compute counter and store in CCM counter in context structure. */ + aesdrv_CCM_CtrInit(pNonce, + pAesdrvContext->ccmCounter, + authTagLength && encrypt); + if (authTagLength) + { + if (encrypt) + { + status = + aesdrv_CCM_MICCompute(pAesdrvContext, + pDataInput, dataLength, + pHdr, hdrLength, + pAuthTag, authTagLength, + encryptedPayload, + encrypt); + } + } + + /* Encrypt / decrypt data */ + if (encryptedPayload) + { + lastBlockLen = dataLength%16; + wholeBlockLen = dataLength/16; + + /* Handle whole blocks first. Last one needs zero padding if it is smaller + * than block size (16 bytes).*/ + if (wholeBlockLen) + { + aesdrv_CCM_CTR128(pAesdrvContext->ccmCounter, + (uint32_t*)pDataOutput, + (uint32_t*)pDataInput, + wholeBlockLen); + } + + if (lastBlockLen) + { + aesdrv_CCM_CTR128Single(pAesdrvContext->ccmCounter, + (uint32_t*)lastBlock, + (uint32_t*)&pDataInput[dataLength-lastBlockLen]); + (void) memcpy(&pDataOutput[dataLength-lastBlockLen], + lastBlock, + lastBlockLen); + } + } + + /* Compute authentication part for decryption */ + if (!encrypt && authTagLength) + { + aesdrv_CCM_CtrInit(pNonce, pAesdrvContext->ccmCounter, !encrypt); + /* Compute the authentication tag MACTag from decrypted data */ + status = aesdrv_CCM_MICCompute(pAesdrvContext, + pDataOutput, dataLength, + pHdr, hdrLength, + pAuthTag, authTagLength, + encryptedPayload, + encrypt); + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == status) + { + memset(pDataOutput, 0, dataLength); + } + } + + /* Disable AES clock. */ + AESDRV_CLOCK_DISABLE; + return status; +} + +/******************************************************************************* + *************************** LOCAL FUNCTIONS ******************************* + ******************************************************************************/ + +/** + * Function calculates CCM MIC. Function assumes that CTR IV counter is already + * initialized. In case of encryption calculated tag is appended to pData. In + * case of decryption calculated tag is compared against tag located at the end + * of pData. + * + * @param pDataInput + * A pointer to PlainText. + * + * @param dataLength + * PlainText Length. + * + * @param pHdr + * A pointer to AuthData. + * + * @param hdrLength + * AuthData length. + * + * @param authTagLength + * Length of AuthenticationTag + * + * @param encryptedPayload + * true - authentication and encryption + * false - authentication only + * + * @param encrypt + * true - encryption + * false - decryption + * + * @return Error code + */ +static Ecode_t aesdrv_CCM_MICCompute(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encryptedPayload, + const bool encrypt) +{ + uint32_t tmpBuf[4]; + uint32_t tmpCtrl; + uint32_t *pTag = (uint32_t*)pAuthTag; + uint32_t lm; + uint32_t la; + Ecode_t status = ECODE_OK; + + if (encryptedPayload) + { + lm = dataLength; + la = hdrLength; + } + else + { + la = hdrLength + dataLength; + lm = 0; + } + + aesdrv_CCM_Nonce(pAesdrvContext->ccmCounter, tmpBuf, authTagLength, la, lm); + + /* Calculate authenticaton part of MIC. */ + if (la) + { + aesdrv_CCM_AMICCompute(pHdr, la); + } + + /* Calculate plaintext part of MIC. */ + aesdrv_CCM_PMICCompute(pDataInput, lm); + + /* Disable AES functionality - auto start after writing to XORDATA. Writing + * to XORDATA will just do XOR. */ + tmpCtrl = AES->CTRL; + AES->CTRL = tmpCtrl & (~AES_CTRL_XORSTART); + + /* AES_DATA register contains MIC which is not CTR encrypted. Xor already + * calculated CTR cipher block with clear MIC. After that operation AES_DATA + * contains proper MIC.*/ + aesdrv_CCM_XorDataWrite(tmpBuf); + + /* Reenable auto AES start after writing to XORDATA. */ + AES->CTRL = tmpCtrl; + + /* Read out 16 byte long authentication tag. */ + aesdrv_CCM_DataRevRead(tmpBuf); + + if (encrypt) + { + /* In case of encryption, copy authentication tag to packet. */ + memcpy(pTag,tmpBuf,authTagLength); + } + else + { + /* In case of decryption compare provided authentication tag with one + * which was calculated. */ + if (memcmp(pTag,tmpBuf,authTagLength)) + { + status = MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + } + + return status; +} + +/** + * @brief + * Function initializes counter. It can initialize counter to 0 or 1 based on + * function parameter. + * + * @param pNonce + * A pointer to 13 bytes long nonce. + * + * @param ctr + * A pointer to 16 byte CTR counter. + * + * @param ctrToZero + * true - counter initialized to 0 + * false - counter initialized to 1 + */ +static inline void aesdrv_CCM_CtrInit(const uint8_t* pNonce, + uint32_t* ctr, + bool ctrToZero) +{ + uint32_t ctrValue = ctrToZero ? 0 : 0x01000000; + + /* CCM Counter consists of: + * flags - 1 byte + * Nonce - 13 bytes + * counter - 2 bytes + * Counter is initialized taking into account that AES is working with reversed + * byte order. */ + ctr[0] = __REV(ctrValue | *(uint16_t *)(&pNonce[11])); + ctr[1] = __REV(*(uint32_t *)(&pNonce[7])); + ctr[2] = __REV(*(uint32_t *)(&pNonce[3])); + ctr[3] = __REV((2-1) | (*(uint32_t *)(&pNonce[0]) << 8)); +} + +static inline void aesdrv_CCM_DataWrite(const uint32_t* in) +{ + AES->DATA = in[0]; + AES->DATA = in[1]; + AES->DATA = in[2]; + AES->DATA = in[3]; +} + +static inline void aesdrv_CCM_DataRead(uint32_t * out) +{ + out[0] = AES->DATA; + out[1] = AES->DATA; + out[2] = AES->DATA; + out[3] = AES->DATA; +} + +static inline void aesdrv_CCM_DataRevRead(uint32_t * out) +{ + out[3] = __REV(AES->DATA); + out[2] = __REV(AES->DATA); + out[1] = __REV(AES->DATA); + out[0] = __REV(AES->DATA); +} + +static inline void aesdrv_CCM_XorDataWrite(const uint32_t* in) +{ + AES->XORDATA = in[0]; + AES->XORDATA = in[1]; + AES->XORDATA = in[2]; + AES->XORDATA = in[3]; +} + +static inline void aesdrv_CCM_XorDataRevWrite(const uint32_t* in) +{ + AES->XORDATA = __REV(in[3]); + AES->XORDATA = __REV(in[2]); + AES->XORDATA = __REV(in[1]); + AES->XORDATA = __REV(in[0]); +} + +/** + * Function prepares IV value for CBC according to CCM spec and calculates + * counter key to be XOR'ed with authentication tag. + * + * @param ctr0 + * A pointer to memory where encrypted counter will be stored. It is later used + * to encrypt authentication tag. + * + * @param authTagLength + * Length of Authentication tag. Can be 0,4,8,16 + * + * @param lm + * Lm parameter from CCM spec. + * + */ +static inline void aesdrv_CCM_Nonce(uint32_t* ccmCounter, + uint32_t* ctr0, + uint8_t authTagLength, + uint32_t la, + uint32_t lm) +{ + uint8_t flags; + uint8_t lenEnc; + + /* Counter is written to AES, AES starts encryption. While AES is processing + * first block for CCM CBC (B0) can be prepared utilizing similarities between + * CTR counter and B0. + */ + aesdrv_CCM_DataWrite(ccmCounter); + + /* Prepare flags to form B0 block. */ + flags = la ? 0x41 : 1; + if (authTagLength) + { + flags |= ((authTagLength-2)/2)<<3; + } + + /* Modify CTR counter to form B0. */ + ccmCounter[0] |= lm; + lenEnc = ccmCounter[3] >> 24; + ccmCounter[3] &= 0x00FFFFFF; + ccmCounter[3] |= (flags << 24); + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Read out encrypted counter to be used to encrypt authentication tag. */ + aesdrv_CCM_DataRead(ctr0); + + /* Process block B0. */ + aesdrv_CCM_DataWrite(ccmCounter); + + /* Transform back B0 to CTR counter. Setting counter to 1. It will be later on + * used when payload will be encrypted. It's done while waiting for AES to + * complete B0 encryption. + */ + ccmCounter[3] &= 0x00FFFFFF; + ccmCounter[3] |= lenEnc<<24; + ccmCounter[0] &= 0xFFFF0000; + ccmCounter[0] |= 0x00000001; + + while (AES->STATUS & AES_STATUS_RUNNING) + ; +} + +/** + * Function calculates a Auth part of CBC Authentication tag. Once function + * terminates AES->DATA register contains partial authentication tag. + * + * @param pHdr + * A pointer to AuthData. + * + * @param hdrLength + * Length of AuthData + */ +static inline void aesdrv_CCM_AMICCompute(const uint8_t * pHdr, uint32_t hdrLength) +{ + bool firstBlock = true; + uint16_t length = hdrLength+2; + uint8_t * _pData = (uint8_t *)pHdr; + uint32_t tmp = 0; + uint32_t padBuf[4]; + + /* Prepare first block of AuthData - starting with L(a) field. */ + if (length > 16) + { + hdrLength = __REV16(hdrLength); + tmp = __REV(hdrLength | ((*(uint16_t*)_pData)<<16)); + _pData -= 2; + } + + while (length) + { + if (length > 16) + { + /* For each AuthData block perform CBC. Last word (first in CCM spec + * byte order) is different for first block (contains length field). It's + * handled in loop prolog. */ + AES->XORDATA = __REV(((uint32_t *)_pData)[3]); + AES->XORDATA = __REV(((uint32_t *)_pData)[2]); + AES->XORDATA = __REV(((uint32_t *)_pData)[1]); + AES->XORDATA = tmp; + + _pData +=16; + length -= 16; + + firstBlock = false; + /* Clear padBuf while waiting for AES completion - to be used in last, + * incomplete block. */ + memset(padBuf,0,16); + + /* Prepare in advance last word for next block - it is done while waiting + * for AES completion. */ + tmp = __REV(((uint32_t *)_pData)[0]); + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + } + else + { + if (firstBlock) + { + /* In case first block is also last block length field L(a) must be + * concatenated with AuthData. */ + memset(padBuf,0,16); + padBuf[0] = __REV16(hdrLength); + memcpy( &((uint8_t*)padBuf)[2], _pData, length-2); + } + else + { + /* Copy last portion of data to zero padded buffer.*/ + memcpy(padBuf,_pData,length); + } + + aesdrv_CCM_XorDataRevWrite(padBuf); + length = 0; + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + } + } +} + +/** + * Function calculates PlainText part of CBC Authentication tag. + * + * @param pDataInput + * A pointer to PlainText + * + * @param length + * Length of PlainText + */ +static inline void aesdrv_CCM_PMICCompute(const uint8_t * pDataInput, uint32_t length) +{ + uint32_t padBuf[4]; + uint32_t * _pDataInput = (uint32_t *)pDataInput; + + while (length) + { + /* First process all full blcoks. */ + if (length > 16) + { + aesdrv_CCM_XorDataRevWrite(_pDataInput); + + _pDataInput +=4; + length -= 16; + while (AES->STATUS & AES_STATUS_RUNNING) + ; + } + else + { + /* Zero pad last, incomplete block. */ + memset(padBuf,0,16); + memcpy(padBuf,_pDataInput,length); + aesdrv_CCM_XorDataRevWrite(padBuf); + length = 0; + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + } + } +} + +/** + * Function performs CTR with 128bit AES on multiple blocks. + * + * @param out + * A pointer to output data. + * + * @param in + * A pointer to input data. + * + * @param loopLength + * Number of blocks + */ +static inline void aesdrv_CCM_CTR128(uint32_t* ccmCounter, + uint32_t* out, + uint32_t* in, + uint32_t loopLength) +{ + uint32_t ctrProduct[4]; + + memset(ctrProduct,0,16); + + /* Encrypt counter */ + aesdrv_CCM_DataWrite(ccmCounter); + /* Increment counter during encryption. */ + ccmCounter[0]++; + while (AES->STATUS & AES_STATUS_RUNNING); + aesdrv_CCM_DataRead(ctrProduct); + + while (--loopLength) + { + aesdrv_CCM_DataWrite(ccmCounter); + + /* Perform XOR with CTR product of previous block while waiting for AES + * completion. */ + out[0] = in[0] ^ __REV(ctrProduct[3]); + out[1] = in[1] ^ __REV(ctrProduct[2]); + out[2] = in[2] ^ __REV(ctrProduct[1]); + out[3] = in[3] ^ __REV(ctrProduct[0]); + + /* Increment counter */ + ccmCounter[0]++; + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + aesdrv_CCM_DataRead(ctrProduct); + + out += 4; + in += 4; + } + + /* Perform XOR with CTR product */ + out[0] = in[0] ^ __REV(ctrProduct[3]); + out[1] = in[1] ^ __REV(ctrProduct[2]); + out[2] = in[2] ^ __REV(ctrProduct[1]); + out[3] = in[3] ^ __REV(ctrProduct[0]); +} + +/** + * Function performs 128bit AES CTR on Single block. + * + * @param out + * A pointer to output data. + * + * @param in + * A pointer to input data. + */ +static inline void aesdrv_CCM_CTR128Single(uint32_t* ccmCounter, + uint32_t* out, + uint32_t* in) +{ + + aesdrv_CCM_DataWrite(ccmCounter); + + ccmCounter[0]++; + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + out[3] = in[3] ^ __REV(AES->DATA); + out[2] = in[2] ^ __REV(AES->DATA); + out[1] = in[1] ^ __REV(AES->DATA); + out[0] = in[0] ^ __REV(AES->DATA); +} +/** @endcond */ + +#endif /* #if defined( AES_CTRL_KEYBUFEN ) */ + +#endif /* #if defined(AES_COUNT) && (AES_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_crypto.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_crypto.c new file mode 100644 index 00000000000..3a967f04809 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_authencr_crypto.c @@ -0,0 +1,2492 @@ +/* + * Authenticated encryption algorithms implementation using CRYPTO hw module + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ccm.h" +#include "cmac.h" +#include "aesdrv_internal.h" +#include "aesdrv_common_crypto.h" +#include "aesdrv_authencr.h" +#include "cryptodrv_internal.h" +#include "em_crypto.h" +#include "em_assert.h" +#include + +/******************************************************************************* + *************************** STATIC FUNCTIONS ******************************* + ******************************************************************************/ + +/* CMAC specific functions. */ +static inline Ecode_t aesdrv_CMAC_Finalize( AESDRV_Context_t* pAesdrvContext, + bool encrypt, + uint8_t* digest, + uint16_t digestLengthBits); + +/* CCM specific functions. */ +static void aesdrv_CCM_HeaderProcess(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + uint32_t la + ); +static inline void aesdrv_CCM_Prepare( AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey + ); +static inline void aesdrv_CCM_NoncePrepare( AESDRV_Context_t* pAesdrvContext, + uint8_t const* pNonce, + uint8_t authTagLength, + uint32_t lm, + uint16_t la + ); +static inline void aesdrv_CCM_SeqSet( AESDRV_Context_t* pAesdrvContext, + const uint8_t authTagLength, + const bool encrypt + ); +static inline Ecode_t aesdrv_CCM_Execute( AESDRV_Context_t* pAesdrvContext, + const uint8_t* pHdr, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint8_t authTagLength, + uint32_t la, + uint32_t lm + ); +/* GCM specific functions. */ +static void aesdrv_GCM_Prepare( AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey, + uint8_t* pInitialVector + ); +static void aesdrv_GCM_Finalize( AESDRV_Context_t* pAesdrvContext, + unsigned int authDataLength, + unsigned int plaintextLength + ); +static inline void aesdrv_GCM_SeqSet( AESDRV_Context_t* pAesdrvContext, + const bool encrypt + ); +static void aesdrv_GCM_Execute( AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + uint16_t dataLength, + const uint8_t* pHdr, + uint32_t hdrLength); + +/* Functions used by CCM and GCM. */ +static inline Ecode_t aesdrvAuthTagHandle( AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength, + bool encrypt + ); +static void aesdrvAuthTagRead( AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength + ); +static Ecode_t aesdrvAuthTagCompare( AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength + ); +static void aesdrvDataLoad( CRYPTO_TypeDef* crypto, + uint8_t* pData, + uint16_t length + ); +static void aesdrvDataLoadStore( CRYPTO_TypeDef* crypto, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + uint16_t length + ); +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) +/* Asynch callbacks. */ +static void aesdrv_XCM_AsynchCallback( void* asynchCallbackArgument ); +static void aesdrv_CMAC_AsynchCallback( void* asynchCallbackArgument ); +static void aesdrvDataLoadAsynch( CRYPTO_TypeDef* crypto, + const uint8_t* pData, + uint16_t length + ); +static void aesdrvDataStoreAsynch( AESDRV_Context_t* pAesdrvContext ); +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + +/******************************************************************************* + ******************************** MACROS ************************************ + ******************************************************************************/ + +#define GCM_BLOCKSIZE (16) + +/** Patterns which keep repeating in sequencer codes for CCM and GCM are + * extracted into small procedures in order to make code more readable. + */ + +/** CBC tag calculcation procedure. + * + * Procedure is executed with following assumptions: + * - data to be processed is in DATA0 + * - DATA2 contains current tag + * - result is stored in DATA2 + */ +#define AESDRV_CBC_PROC \ + CRYPTO_CMD_INSTR_DATA2TODATA0XOR,\ + CRYPTO_CMD_INSTR_AESENC, \ + CRYPTO_CMD_INSTR_DATA0TODATA2 + +/** Authentication tag encrypt (CCM) procedure. + * + * Procedure is executed with following assumptions: + * - DATA1 contains counter + * - DATA2 contains tag to be encrypted + * - result is stored in DATA0 + */ +#define AESDRV_CCMTAG_ENCRYPT_PROC \ + CRYPTO_CMD_INSTR_DATA1INCCLR, \ + CRYPTO_CMD_INSTR_DATA1TODATA0, \ + CRYPTO_CMD_INSTR_AESENC, \ + CRYPTO_CMD_INSTR_DATA2TODATA0XOR + +/** CTR block with preincrementation. + * + * Procedure is executed with following assumptions: + * - DATA1 contains counter + * - result is stored in DATA0 + */ +#define AESDRV_CTR_PREPARE_PROC \ + CRYPTO_CMD_INSTR_DATA1INC, \ + CRYPTO_CMD_INSTR_DATA1TODATA0, \ + CRYPTO_CMD_INSTR_AESENC + +/** CTR encryption procedure. + * + * Procedure is executed with following assumptions: + * - data to be processed is in DATA0 + * - DATA1 contains counter which is preincremented + * - DATA3 is used as temporary register + * - result is stored in DATA0 + */ +#define AESDRV_CTR_PROC \ + CRYPTO_CMD_INSTR_DATA0TODATA3, \ + AESDRV_CTR_PREPARE_PROC, \ + CRYPTO_CMD_INSTR_DATA3TODATA0XOR + +/** GHASH procedure. + * + * Procedure is executed with following assumptions: + * - data to be processed is in DATA0 ( A[i] or C[i] ) + * - temporary GHASH is stored in DDATA0 + * - H is stored in DATA2 (part of DDATA3) + * - DDATA1 is used as temporary register + * + */ +#define AESDRV_GHASH_PROC \ + CRYPTO_CMD_INSTR_SELDDATA0DDATA2,\ + CRYPTO_CMD_INSTR_XOR, \ + CRYPTO_CMD_INSTR_BBSWAP128, \ + CRYPTO_CMD_INSTR_DDATA0TODDATA1, \ + CRYPTO_CMD_INSTR_SELDDATA0DDATA3,\ + CRYPTO_CMD_INSTR_MMUL, \ + CRYPTO_CMD_INSTR_BBSWAP128 + +/** Sequencer code for CCM authentication and encryption. There are 3 variants + * of the code: MCU,BUFC and DMA. + */ +static const CRYPTO_InstructionSequence_TypeDef ccmAuthEncr[] = { + { + /* MCU */ + CRYPTO_CMD_INSTR_EXECIFA, + + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + CRYPTO_CMD_INSTR_DATA0TODATA3, + + AESDRV_CBC_PROC, + + AESDRV_CTR_PREPARE_PROC, + + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + }, + { + /* BUFC */ + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + + CRYPTO_CMD_INSTR_EXECIFLAST, + AESDRV_CCMTAG_ENCRYPT_PROC + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA3, + + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PREPARE_PROC, + + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + + CRYPTO_CMD_INSTR_EXECIFLAST, + AESDRV_CCMTAG_ENCRYPT_PROC + } +#endif +}; + +/** Sequencer code for CCM decryption and authentication validation. There are + * 3 variants of the code: MCU,BUFC and DMA. + */ +static const CRYPTO_InstructionSequence_TypeDef ccmAuthDecr[] = { + { + /* MCU */ + CRYPTO_CMD_INSTR_EXECIFA, + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + CRYPTO_CMD_INSTR_DDATA3TODDATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_DATA3TODATA0, + CRYPTO_CMD_INSTR_DATA2TODATA0XORLEN, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_DATA0TODATA3, + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_DATA3TODATA0 + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PREPARE_PROC, + + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA3TODATA0XORLEN, + CRYPTO_CMD_INSTR_DATA0TOBUF, + + CRYPTO_CMD_INSTR_EXECIFA, + CRYPTO_CMD_INSTR_BUFTODATA0, + + CRYPTO_CMD_INSTR_EXECALWAYS, + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFLAST, + AESDRV_CCMTAG_ENCRYPT_PROC + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DMA0TODATA, /* 5*/ + CRYPTO_CMD_INSTR_DATA3TODATA0XORLEN, + CRYPTO_CMD_INSTR_DATATODMA0, + + CRYPTO_CMD_INSTR_EXECIFA, + CRYPTO_CMD_INSTR_DMA0TODATA, + + CRYPTO_CMD_INSTR_EXECALWAYS, /* 10 */ + AESDRV_CBC_PROC, + + CRYPTO_CMD_INSTR_EXECIFLAST, + AESDRV_CCMTAG_ENCRYPT_PROC + } +#endif +}; + +/** Sequencer code for CCM encryption or decryption only (no authentication). + * There are 3 variants of the code: MCU,BUFC and DMA. + */ +static const CRYPTO_InstructionSequence_TypeDef ccmEncrDecr[] = +{ + { + /* MCU */ + CRYPTO_CMD_INSTR_EXECIFB, + CRYPTO_CMD_INSTR_DATA0TODATA3, + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_EXECIFB, + CRYPTO_CMD_INSTR_DATA0TODATA3, + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_EXECIFB, + CRYPTO_CMD_INSTR_DATA0TODATA3, + AESDRV_CTR_PREPARE_PROC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0 + } +#endif +}; + +/** Sequencer code for GCM encryption and authentication. There are + * 3 variants of the code: MCU,BUFC and DMA. + */ +static const CRYPTO_InstructionSequence_TypeDef gcmAuthEncr[] = +{ + { + /* MCU */ + CRYPTO_CMD_INSTR_EXECIFB, + + AESDRV_CTR_PROC, + + CRYPTO_CMD_INSTR_EXECALWAYS, + + AESDRV_GHASH_PROC + + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PROC, + CRYPTO_CMD_INSTR_DATA0TOBUF, /* Store Ciphertext */ + + CRYPTO_CMD_INSTR_EXECALWAYS, + AESDRV_GHASH_PROC + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + + CRYPTO_CMD_INSTR_EXECIFB, + + AESDRV_CTR_PROC, + CRYPTO_CMD_INSTR_DATATODMA0, /* Store Ciphertext */ + + CRYPTO_CMD_INSTR_EXECALWAYS, + AESDRV_GHASH_PROC + } +#endif +}; +/** Sequencer code for GCM decryption and authentication validation. There are + * 3 variants of the code: MCU,BUFC and DMA. + */ +static const CRYPTO_InstructionSequence_TypeDef gcmAuthDecr[] = +{ + { + /* MCU */ + AESDRV_GHASH_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PROC + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + AESDRV_GHASH_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PROC, + CRYPTO_CMD_INSTR_DATA0TOBUF /* Store Ciphertext */ + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + AESDRV_GHASH_PROC, + + CRYPTO_CMD_INSTR_EXECIFB, + AESDRV_CTR_PROC, + CRYPTO_CMD_INSTR_DATATODMA0 /* Store Ciphertext */ + } +#endif +}; + +/* const_rb should be 0x87, but implementation requires bit- and byteswapped + constant */ +static const uint32_t cmac_const_rb[4] = {0x00000000, 0x00000000, + 0x00000000, 0xe1000000}; + +/******************************************************************************* + *************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Generalized, internal CCM function supporting both CCM and CCM*. + ******************************************************************************/ +Ecode_t AESDRV_CCM_Generalized(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt, + const bool encryptedPayload) +{ + uint32_t lm; + uint32_t la; + Ecode_t status, retval; + CRYPTODRV_Context_t* pCryptodrvContext = + &pAesdrvContext->cryptodrvContext; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; + AESDRV_AsynchCallback_t asynchCallback = + pAsynchContext ? pAsynchContext->asynchCallback : 0; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if ( (keyLength != 128/8) || + (nonceLength != 13) || + (dataLength > CCM_MAX_DATA_LENGTH) ) + { + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + + if (encryptedPayload) + { + la=hdrLength; + lm=dataLength; + } + else + { + la=hdrLength+dataLength; + lm=0; + } + + if ((0==authTagLength) && (0==lm)) + { +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (asynchCallback) + { + asynchCallback(ECODE_OK, pAsynchContext->asynchCallbackArgument); + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + return ECODE_OK; + } + + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Enabling CRYPTO clock, initial CRYPTO configuration and key loading.*/ + aesdrv_CCM_Prepare(pAesdrvContext, pKey); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Set initial value for CBC (DATA2) and CTR (DATA1) */ + aesdrv_CCM_NoncePrepare(pAesdrvContext, pNonce, authTagLength, lm, la); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Load appropriate instruction code to CRYPTO sequencer. */ + aesdrv_CCM_SeqSet(pAesdrvContext, authTagLength, encrypt); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + pAesdrvContext->cipherMode = cipherModeCcm; + + if (pAsynchContext && (la || lm)) + { + pAsynchContext->pAuthTag = pAuthTag; + pAsynchContext->encrypt = encrypt; + pAsynchContext->authTagLength = authTagLength; + CRYPTODRV_SetAsynchCallback (pCryptodrvContext, + aesdrv_XCM_AsynchCallback, pAesdrvContext); + /* Process data. */ + retval = aesdrv_CCM_Execute(pAesdrvContext, + pHdr, pDataInput, pDataOutput, + authTagLength, la, lm); + return retval; + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + /* Process data. */ + retval = aesdrv_CCM_Execute(pAesdrvContext, + pHdr, pDataInput, pDataOutput, + authTagLength, la, lm); + + if (ECODE_OK == retval) + { + /* read(encrypt==true) or validate tag. */ + retval = aesdrvAuthTagHandle(pAesdrvContext, + pAuthTag, authTagLength, encrypt); + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == retval) + { + memset(pDataOutput, 0, dataLength); + } + } + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + if (asynchCallback) + { + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == retval) + { + retval = (Ecode_t)MBEDTLS_ERR_CCM_AUTH_FAILED; + } + asynchCallback(retval, pAsynchContext->asynchCallbackArgument); + /* In asynch mode return OK, since status is returned in callback. */ + retval = ECODE_OK; + } + } +#endif + + return retval==ECODE_OK? status : retval; + } +} + +/** + * Function is an implementation of CCM optimized for BLE. + * Please refer to @ref aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CCMBLE(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + const uint32_t dataLength, + uint8_t hdr, + const uint8_t* pKey, + const uint8_t* pNonce, + uint8_t* pAuthTag, + const bool encrypt) +{ + /* Local variables used to optimize load/store sequences from memory to + crypto. We want to load all 4 32bit data words to local register + variables in the first sequence, then store them all in the second + sequence.*/ + register uint32_t iv0; + register uint32_t iv1; + register uint32_t iv2; + register uint32_t iv3; + Ecode_t status, retval=ECODE_OK; + CRYPTODRV_Context_t* pCryptodrvContext = + &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if (pAesdrvContext->ioMode != aesdrvIoModeBufc) + { + return AESDRV_CCM_Generalized(pAesdrvContext, + pData, pData, dataLength, + &hdr, 1, + pKey, 128/8, /* keyLength */ + pNonce, 13, + (uint8_t*)pAuthTag, 4, + encrypt, true); + } + else + { + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Setup CRYPTO for AES-128 mode (256 not supported) */ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + + AESDRV_HwIoSetup(pAesdrvContext, pData, 0, 0); + + if (pKey) + { + CRYPTO_KeyBuf128Write(crypto, (uint32_t *)pKey); + } + /* Calculate Counter IV for encryption. */ + iv0 = 0x01 | (*(uint32_t *)(&pNonce[0]) << 8); + iv1 = *(uint32_t *)(&pNonce[3]); + iv2 = *(uint32_t *)(&pNonce[7]); + iv3 = *(uint16_t *)(&pNonce[11]); + /* Store Counter IV in crypto->DATA1 */ + crypto->DATA1 = iv0; + crypto->DATA1 = iv1; + crypto->DATA1 = iv2; + crypto->DATA1 = iv3; + + /* Calculate CBC IV for authentication. */ + iv0 |= 0x49; + iv3 |= __REV(dataLength); + /* Store CBC IV in crypto->DATA0 */ + crypto->DATA0 = iv0; + crypto->DATA0 = iv1; + crypto->DATA0 = iv2; + crypto->DATA0 = iv3; + + /* Store header in crypto->DATA3 */ + crypto->DATA3 = 0x0100 | (hdr << 16); + crypto->DATA3 = 0; + crypto->DATA3 = 0; + crypto->DATA3 = 0; + + crypto->SEQCTRL = dataLength; + crypto->SEQCTRLB = 0; + + /* The following code is tested to run faster than using instruction + sequences. */ + crypto->CMD = CRYPTO_CMD_INSTR_AESENC; + crypto->CMD = CRYPTO_CMD_INSTR_DATA3TODATA0XOR; + crypto->CMD = CRYPTO_CMD_INSTR_AESENC; + crypto->CMD = CRYPTO_CMD_INSTR_DATA0TODATA3; + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + pAesdrvContext->cipherMode = cipherModeCcmBle; + + if (pAsynchContext) + { + pAsynchContext->pAuthTag = (uint8_t*)pAuthTag; + pAsynchContext->encrypt = encrypt; + pAsynchContext->authTagLength = 4; + pAsynchContext->encryptingHeader = false; + pAsynchContext->la = 0; + pAsynchContext->lm = 0; + CRYPTODRV_SetAsynchCallback (pCryptodrvContext, + aesdrv_XCM_AsynchCallback, pAesdrvContext); + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + if (encrypt) + { + CRYPTO_EXECUTE_14(crypto, + CRYPTO_CMD_INSTR_EXECIFA, + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TOBUFXOR, + CRYPTO_CMD_INSTR_EXECIFLAST, + CRYPTO_CMD_INSTR_DATA1INCCLR, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR + ); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (0==pAsynchContext) +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + uint32_t * _pAuthTag = (uint32_t *)pAuthTag; + *_pAuthTag = crypto->DATA0; + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + } + } + else + { + CRYPTO_EXECUTE_16(crypto, + CRYPTO_CMD_INSTR_EXECIFA, + /* AESDRV_CTR_PREPARE_PROC */ + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + + CRYPTO_CMD_INSTR_BUFTODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_DATA3TODATA0, + CRYPTO_CMD_INSTR_DATA2TODATA0XORLEN, + + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA3, + + CRYPTO_CMD_INSTR_EXECIFLAST, + CRYPTO_CMD_INSTR_DATA1INCCLR, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR + ); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (0==pAsynchContext) +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + uint32_t * _pAuthTag = (uint32_t *)pAuthTag; +#if (CRYPTO_COUNT > 1) + CRYPTO_InstructionSequenceWait(crypto); +#endif + if (crypto->DATA0 != *_pAuthTag) + { + retval = MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + } + } + + return retval==ECODE_OK? status : retval; + } +} + +/* + * GCM (Galois Counter Mode) block cipher mode encryption/decryption based + * on 128 bit AES. + * Please refer to @ref aesdrv.h for detailed description. + */ +Ecode_t AESDRV_GCM(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pInitialVector, + const uint32_t initialVectorLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt) +{ + Ecode_t status, retval = ECODE_OK; + CRYPTODRV_Context_t* pCryptodrvContext = + &pAesdrvContext->cryptodrvContext; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_GCM_AsynchContext_t* pAsynchContext = + (AESDRV_GCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; + AESDRV_AsynchCallback_t asynchCallback = + pAsynchContext ? pAsynchContext->asynchCallback : 0; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if ( (keyLength != 128/8) || (initialVectorLength != 12) ) + { + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + /* Prepare for GCM loop: set registers to inital values */ + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + aesdrv_GCM_Prepare(pAesdrvContext, pKey, (uint8_t*)pInitialVector); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + /* Load appropriate sequencer code to CRYPTO sequencer. */ + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + aesdrv_GCM_SeqSet(pAesdrvContext, encrypt); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + pAesdrvContext->cipherMode = cipherModeGcm; + + if (pAsynchContext && (dataLength || hdrLength)) + { + pAsynchContext->pAuthTag = pAuthTag; + pAsynchContext->encrypt = encrypt; + pAsynchContext->authTagLength = authTagLength; + CRYPTODRV_SetAsynchCallback (pCryptodrvContext, + aesdrv_XCM_AsynchCallback, pAesdrvContext); + + /* Process data */ + aesdrv_GCM_Execute(pAesdrvContext, + pDataInput, pDataOutput, dataLength, + pHdr, hdrLength); + + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + /* Process data */ + aesdrv_GCM_Execute(pAesdrvContext, + pDataInput, pDataOutput, dataLength, + pHdr, hdrLength); + + /* + ** Compute last part of the GHASH and authentication tag: + ** + ** Xm+n+1 = (Xm+n XOR (len(A)|len(C))) * H + ** + ** Compute the final authentication tag now. + ** T = MSBt (GHASH(H, A, C) XOR E(K, Y0)) + ** where GHASH(H, A, C) is Xm+n+1 which is stored in DATA0 (LSWord of DDATA2) + ** and + ** E(K, Y0) is stored in DATA3. + */ + aesdrv_GCM_Finalize(pAesdrvContext, hdrLength, dataLength); + + /* read(encrypt==true) or validate tag. */ + retval = aesdrvAuthTagHandle(pAesdrvContext, + pAuthTag, authTagLength, encrypt); + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == retval) + { + memset(pDataOutput, 0, dataLength); + } + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + + if (ECODE_OK == retval) + retval = status; + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (asynchCallback) + { + asynchCallback(retval, pAsynchContext->asynchCallbackArgument); + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + } + return retval; +} + +/** + * @brief + * Function is an implementation of CMAC-AES128 + * @details + * Function assumes fixed key length of 128bit, digest of max 128bit. + * + * @param[in] pAesdrvContext + * Pointer to CMAC context structure. + * + * @param[in] pData + * Pointer to data (message) Be careful: this memory should be allocated on + * block-size (128-bit) boundaries! + * + * @param[in] dataLengthBits + * length of actual data in bits + * + * @param[in] key + * Pointer to key buffer for the AES algorithm. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in/out] digest + * 128-bit (maximum) digest. If encrypting, the digest will be stored there. + * If verifying, the calculated digest will be compared to the one stored in + * this place. + * Warning: regardless of digestLengthBits, 128 bits will get written here. + * + * @param[in] digestLengthBits + * Requested length of the message digest in bits. LSB's will be zeroed out. + * + * @param[in] encrypt + * true - Generate hash + * false - Verify hash + * + * @return + * ECODE_OK if success. Error code if failure. + * Encryption will always succeed. + * Decryption may fail if the authentication fails. + */ +Ecode_t AESDRV_CMAC(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pData, + uint32_t dataLengthBits, + const uint8_t* key, + const uint32_t keyLength, + uint8_t* digest, + uint16_t digestLengthBits, + const bool encrypt + ) +{ + uint32_t i; + uint32_t subKey[4]; + uint32_t lastBlock[4]; + uint8_t* lastBlockBytePtr = (uint8_t *)lastBlock; + uint32_t* dataPointer = (uint32_t *)pData; + uint8_t bitsToPad; + Ecode_t status, retval = ECODE_OK; + CRYPTODRV_Context_t* pCryptodrvContext = + &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_CMAC_AsynchContext_t* pAsynchContext = + (AESDRV_CMAC_AsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + /* Check input arguments */ + if (digestLengthBits > 128) + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + if (digestLengthBits == 0) + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + if (keyLength != 128/8) + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Setup CRYPTO for AES-128 mode (256 not supported) */ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Calculate subkeys */ + /* magic value in DATA1 */ + CRYPTO_DataWrite(&crypto->DATA1, cmac_const_rb); + if (key) + { + /* Key in KeyBuf */ + CRYPTO_KeyBufWrite(crypto, (uint32_t*)key, cryptoKey128Bits); + } + /* Zero out DATA0 */ + for(i = 0; i < 4; i++) crypto->DATA0 = 0x00; + + CRYPTO_EXECUTE_17(crypto, + CRYPTO_CMD_INSTR_SELDATA0DATA1, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_SELDDATA0DATA1, + CRYPTO_CMD_INSTR_SHR, + CRYPTO_CMD_INSTR_EXECIFCARRY, + CRYPTO_CMD_INSTR_XOR, + CRYPTO_CMD_INSTR_EXECALWAYS, + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, // subkey1 in DATA2 + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_SHR, + CRYPTO_CMD_INSTR_EXECIFCARRY, + CRYPTO_CMD_INSTR_XOR, + CRYPTO_CMD_INSTR_EXECALWAYS, + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 // subkey2 in DATA0 + ); + CRYPTO_InstructionSequenceWait(crypto); + + /* Prepare input message for algorithm */ + bitsToPad = 128 - (dataLengthBits % 128); + + /* Determine which subKey we're going to use */ + if(bitsToPad != 128 || dataLengthBits == 0) + { + /* Input is treated as last block being incomplete */ + /* So store SubKey 2 */ + CRYPTO_DataRead(&crypto->DATA0, subKey); + } + else + { + /* Input is treated as block aligned, so store SubKey 1 */ + CRYPTO_DataRead(&crypto->DATA2, subKey); + } + + /* We can take a break from using CRYPTO here */ + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + /* Copy the last block of data into our local copy because we need + to change it */ + if(dataLengthBits < 128) + { + for(i = 0; i < 4; i++) + { + lastBlock[i] = dataPointer[i]; + } + } + else + { + for(i = 0; i < 4; i++) + { + lastBlock[i] = dataPointer[((dataLengthBits - 1) / 128)*4 + i]; + } + } + + if(bitsToPad != 128) + { + /* Input message needs to be padded */ + + /* Apply first one bit */ + if((bitsToPad % 8) == 0) + { + lastBlockBytePtr[16-(bitsToPad/8)] = 0x80; + dataLengthBits += 8; + bitsToPad -= 8; + } + else + { + lastBlockBytePtr[16-(bitsToPad/8)] |= (1 << ((bitsToPad - 1) % 8)); + dataLengthBits += bitsToPad % 8; + bitsToPad -= bitsToPad % 8; + } + + /* Apply zero-padding until block boundary */ + while(bitsToPad > 0) + { + lastBlockBytePtr[16-(bitsToPad/8)] = 0x00; + dataLengthBits += 8; + bitsToPad -= 8; + } + } + else + { + if (dataLengthBits == 0) + { + /* Clear out the data */ + for(i = 0; i < 4; i++) + { + lastBlock[i] = 0x00000000; + } + /* Pad */ + lastBlockBytePtr[0] = 0x80; + dataLengthBits = 128; + } + else + { + /* Input message was block-aligned, so no padding required */ + } + } + /* Store the XOR-ed version of the last block separate from the message */ + /* to avoid contamination of the input data */ + for(i = 0; i < 4; i++) + { + lastBlock[i] ^= subKey[i]; + } + + /* Calculate hash */ + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + crypto->SEQCTRL |= 16; + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + crypto->SEQCTRL |= dataLengthBits / 8; +#else + crypto->SEQCTRL |= 16; +#endif + } +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + crypto->CTRL |= CRYPTO_CTRL_DMA0RSEL_DATA0; +#endif + if (key) + { + CRYPTO_KeyBufWrite(crypto, (uint32_t*)key, cryptoKey128Bits); + } + for(i = 0; i < 4; i++) crypto->DATA0 = 0x00; + +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_SEQ_LOAD_2(crypto, + CRYPTO_CMD_INSTR_DMA0TODATAXOR, + CRYPTO_CMD_INSTR_AESENC); +#else + CRYPTO_SEQ_LOAD_1(crypto, + CRYPTO_CMD_INSTR_AESENC); +#endif + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + uint32_t dataBlocks = dataLengthBits/128; + + pAsynchContext->digest = digest; + pAsynchContext->digestLengthBits = digestLengthBits; + pAsynchContext->encrypt = encrypt; + memcpy (pAsynchContext->lastBlock, lastBlock, sizeof(lastBlock)); + + CRYPTODRV_SetAsynchCallback (pCryptodrvContext, + aesdrv_CMAC_AsynchCallback, pAesdrvContext); +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + if (dataBlocks > 1) + { + pAsynchContext->dataBlocks = dataBlocks - 1; + pAsynchContext->dataPointer = dataPointer + 4; + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0XOR, (uint8_t*)dataPointer); + } + else + { + pAsynchContext->dataBlocks = 0; + CRYPTO_DataWrite(&crypto->DATA0XOR, lastBlock); + } +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + /* Push all blocks except the last one */ + for(i = 0; i < (dataLengthBits/128) - 1; i++) + { + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0XOR, (uint8_t*)&(dataPointer[i*4])); +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + } + /* Don't forget to push the last block as well! */ + CRYPTO_DataWrite(&crypto->DATA0XOR, lastBlock); +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + CRYPTO_InstructionSequenceWait(crypto); + + retval = aesdrv_CMAC_Finalize(pAesdrvContext, + encrypt, digest, digestLengthBits); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + } + + return retval == ECODE_OK ? status : retval; +} + +/******************************************************************************* + *************************** LOCAL FUNCTIONS ******************************* + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * Callback function for asynchronous CCM and GCM operations. + * + * @param[in] asynchCallbackArgument + * Callback argument. + ******************************************************************************/ +static void aesdrv_XCM_AsynchCallback (void* asynchCallbackArgument) +{ + AESDRV_Context_t* pAesdrvContext = + (AESDRV_Context_t*) asynchCallbackArgument; + + if (pAesdrvContext) + { + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; + + int la = pAsynchContext->la; + if (la && pAsynchContext->authTagLength) + { + aesdrvDataLoadAsynch(crypto, pAsynchContext->pHdr, la); + if (la > 16) + { + pAsynchContext->la -= 16; + pAsynchContext->pHdr += 16; + } + else + { + pAsynchContext->la = 0; + } + return; + } + else + { + int lm = pAsynchContext->lm; + if (lm) + { + if (pAsynchContext->encryptingHeader) + { + /* We have just finished auth data handling mode, so should + kick off the plaintext handling, and return. */ + pAsynchContext->encryptingHeader = false; + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = lm > 16 ? 16 : lm; + aesdrvDataLoadAsynch(crypto, pAsynchContext->pDataInput, lm); + return; + } + + aesdrvDataStoreAsynch(pAesdrvContext); + + if (lm > 16) + { + lm = pAsynchContext->lm; + crypto->SEQCTRLB = lm > 16 ? 16 : lm; + aesdrvDataLoadAsynch(crypto, pAsynchContext->pDataInput, lm); + return; + } + else + { + lm = 0; + } + } + + if (lm == 0) + { + Ecode_t status, retval; + + /* Turn off interrupts. */ + CRYPTODRV_SetAsynchCallback(pCryptodrvContext, 0, 0); + + /* Encrypt authentication tag. */ + switch (pAesdrvContext->cipherMode) + { + case cipherModeCcm: + if (pAsynchContext->authTagLength) + { + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + CRYPTO_EXECUTE_4(crypto, + CRYPTO_CMD_INSTR_DATA1INCCLR, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA2TODATA0XOR); + crypto->IFC = 3; + } + break; + case cipherModeGcm: + aesdrv_GCM_Finalize(pAesdrvContext, + pAsynchContext->hdrLength, + pAsynchContext->dataLength); + break; + case cipherModeCcmBle: + break; + case cipherModeCmac: + case cipherModeBlockCipher: + case cipherModeNone: + /* Cipher mode should not be CMAC, block cipher or none. */ + EFM_ASSERT (false); + break; + } + + /* read(encrypt==true) or validate tag. */ + status = aesdrvAuthTagHandle(pAesdrvContext, + pAsynchContext->pAuthTag, + pAsynchContext->authTagLength, + pAsynchContext->encrypt); + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == status) + { + uint8_t *pDataStart = pAsynchContext->pDataOutput - + (pAsynchContext->dataLength - (pAsynchContext->dataLength&0xf)); + memset(pDataStart, 0, pAsynchContext->dataLength); + status = (Ecode_t)MBEDTLS_ERR_CCM_AUTH_FAILED; + } + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + retval = CRYPTODRV_Release(pCryptodrvContext); + + /* Finally call the user callback */ + if (pAsynchContext->asynchCallback) + { + pAsynchContext->asynchCallback(status==ECODE_OK? (int)retval : (int)status, + pAsynchContext->asynchCallbackArgument); + } + } + } + } +} + +/***************************************************************************//** + * @brief + * Callback function for asynchronous CMAC operation. + * + * @param[in] asynchCallbackArgument + * Callback argument. + ******************************************************************************/ +static void aesdrv_CMAC_AsynchCallback (void* asynchCallbackArgument) +{ + AESDRV_Context_t* pAesdrvContext = + (AESDRV_Context_t*) asynchCallbackArgument; + + if (pAesdrvContext) + { + AESDRV_CMAC_AsynchContext_t* pAsynchContext = + (AESDRV_CMAC_AsynchContext_t*) pAesdrvContext->pAsynchContext; + uint32_t dataBlocks = pAsynchContext->dataBlocks; + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; + + /* Push next block */ + if (dataBlocks) + { +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + if (dataBlocks > 1) + { + uint32_t* dataPointer = pAsynchContext->dataPointer; + pAsynchContext->dataBlocks = dataBlocks - 1; + pAsynchContext->dataPointer = dataPointer + 4; + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0XOR, (uint8_t*)dataPointer); + } + else + { + pAsynchContext->dataBlocks = 0; + CRYPTO_DataWrite(&crypto->DATA0XOR, pAsynchContext->lastBlock); + } +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_InstructionSequenceExecute(crypto); +#endif + } + else + { + Ecode_t status; + Ecode_t retval; + + /* Turn off interrupts. */ + CRYPTODRV_SetAsynchCallback(pCryptodrvContext, 0, 0); + + status = aesdrv_CMAC_Finalize(pAesdrvContext, + pAsynchContext->encrypt, + pAsynchContext->digest, + pAsynchContext->digestLengthBits); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + retval = CRYPTODRV_Release(pCryptodrvContext); + + /* Finally call the user callback */ + if (pAsynchContext->asynchCallback) + { + if (MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == status) + { + status = (Ecode_t)MBEDTLS_ERR_CMAC_AUTH_FAILED; + } + pAsynchContext->asynchCallback(status==ECODE_OK? (int)retval : (int)status, + pAsynchContext->asynchCallbackArgument); + } + } + } + + return; +} + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/***************************************************************************//** + * @brief + * Perform final CMAC processing. + * + * @param[in] encrypt + * True if encryption was requested. False if decryption was requested. + * + * @param[in] digest + * Pointer to location where digest should be stored. + * + * @param[in] digestLengthBits + * Length of digest in bits. + ******************************************************************************/ +static inline Ecode_t aesdrv_CMAC_Finalize(AESDRV_Context_t* pAesdrvContext, + bool encrypt, + uint8_t* digest, + uint16_t digestLengthBits) +{ + int i; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + /* If needed, verify */ + if(encrypt) + { + /* Read final hash/digest from CRYPTO. */ + CRYPTODRV_DataReadUnaligned(&crypto->DATA0, digest); + + /* mask away unneeded bits */ + i = digestLengthBits; + while (i < 128) { + if (i % 8 == 0) { + /* mask away a full byte */ + digest[i/8] = 0; + i += 8; + } else { + /* mask away partial byte */ + digest[i/8] &= ~(1 << (7-(i%8))); + i++; + } + } + } + else + { + /* Get hash from CRYPTO unintrusively */ + uint32_t hash128[4]; + uint8_t *hash = (uint8_t*) hash128; + + /* Read final hash/digest and compare it with expected. */ + CRYPTO_DataRead(&crypto->DATA0, hash128); + + /* Compare the full length of the digest */ + i = 0; + while( i < digestLengthBits ) + { + if(digestLengthBits - i >= 8) + { + /* If at least a full byte to go, use byte comparison */ + if(hash[i/8] != digest[i/8]) + { + return MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + i += 8; + } + else + { + /* If less then a byte to go, use bit comparison */ + if((hash[i/8] & (1 << (7-(i%8)))) != (digest[i/8] & (1 << (7-(i%8))))) + { + return MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + i += 1; + } + } + } + return ECODE_OK; +} + +/***************************************************************************//** + * @brief + * Function is doing initial CRYPTO setup and loads the key to KEYBUF + * + * @param[in] pKey + * 128 bit key + * + ******************************************************************************/ +static inline void aesdrv_CCM_Prepare(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey) +{ + const uint32_t * const _pKey = (const uint32_t *)pKey; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + /* Setup CRYPTO registers for CCM operation: + - AES-128 mode (256 not supported) + - width of counter in CTR cipher mode to 2 bytes. + - enable DMA unaligned access and set + */ + crypto->CTRL = CRYPTO_CTRL_AES_AES128 | + CRYPTO_CTRL_INCWIDTH_INCWIDTH2 | + CRYPTO_CTRL_DMA0MODE_LENLIMIT; + + if (pKey) + { + /* Load key into high key for key buffer usage */ + CRYPTO_KeyBuf128Write(crypto, (uint32_t *)_pKey); + } +} + +/***************************************************************************//** + * Function converts input 13 byte long nonce to 16 byte IV values used for + * authentication and encryption in CCM. After function completes both IV values + * are in CRYPTO registers. Counter IV in DATA1 and CBC IV in DATA2. + * + * @param pNonce + * 13byte long nonce. + * + * @param authTagLength + * Size of MIC. + * + * @param lm + * Message length - payload to be encrypted. + * + * @param la + * Authentication only length + * + ******************************************************************************/ +static inline void aesdrv_CCM_NoncePrepare(AESDRV_Context_t* pAesdrvContext, + uint8_t const * pNonce, + uint8_t authTagLength, + uint32_t lm, + uint16_t la) +{ + uint8_t flags; + /* Local variables used to optimize load/store sequences from memory to + crypto. We want to load all 4 32bit data words to local register + variables in the first sequence, then store them all in the second + sequence.*/ + uint32_t volatile* regPtr; + register uint32_t v0; + register uint32_t v1; + register uint32_t v2; + register uint32_t v3; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Flags for B0 are prepared */ + /* Set AData */ + flags = la ? 0x41 : 1; + + /* Set authentication field */ + flags |= ((authTagLength-2)/2)<<3; + + /* Partial authentication tag is kept in DATA2. + * + * DATA2 is loaded with B0 block and AES encrypted. + */ + if (authTagLength) + { + v0 = (flags) | (*(uint32_t *)(&pNonce[0]) << 8); + v1 = *(uint32_t *)(&pNonce[3]); + v2 = *(uint32_t *)(&pNonce[7]); + v3 = *(uint16_t *)(&pNonce[11]) | __REV(lm); + regPtr = (uint32_t volatile*) &crypto->DATA2; + /* Store data to CRYPTO */ + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_DATA2TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA2); + } + + /* Counter for CTR encryption is kept in DATA1. + * DATA1 is loaded with initial CTR value. + * flags in Counter value are constant because only L=2 is supported. + */ + v0 = 1 | (*(uint32_t *)(&pNonce[0]) << 8); + v1 = *(uint32_t *)(&pNonce[3]); + v2 = *(uint32_t *)(&pNonce[7]); + v3 = *(uint16_t *)(&pNonce[11]); + regPtr = (uint32_t volatile*) &crypto->DATA1; + /* Store data to CRYPTO */ + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; +} + +/***************************************************************************//** + * @brief + * Function loads CCM instruction sequence to CRYPTO based on input parameters + * and I/O mode. + * + * @param authTagLength + * length of authenticationTag + * + * @param encrypt + * true - encryption + * false - decryption + * + ******************************************************************************/ +static inline void aesdrv_CCM_SeqSet(AESDRV_Context_t* pAesdrvContext, + const uint8_t authTagLength, + const bool encrypt) +{ + const uint8_t * instrSeq; + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + if (authTagLength) + { + if (encrypt) + { + instrSeq = ccmAuthEncr[ioMode]; + } + else + { + instrSeq = ccmAuthDecr[ioMode]; + } + } + else + { + instrSeq = ccmEncrDecr[ioMode]; + } + CRYPTO_InstructionSequenceLoad(crypto, instrSeq); +} + +/***************************************************************************//** + * @brief + * Function performs CCM algorithm. In case of HW I/O mode it sets + * sequences lengths, setups hw I/O mode and triggers CRYPTO sequencer. + * When HW I/O mode is not used function performs CCM using MCU core access + * to CRYPTO registers. + * + * @param pHdr + * pointer do header + * + * @param pData + * pointer to data + * + * @param authTagLength + * length of authentication tag. + * + * @param la + * length of data to be authenticated only. + * + * @param lm + * length of data to be encrypted (and possibly authenticated). + * + ******************************************************************************/ +static inline Ecode_t aesdrv_CCM_Execute +( + AESDRV_Context_t* pAesdrvContext, + const uint8_t* pHdr, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint8_t authTagLength, + uint32_t la, + uint32_t lm + ) +{ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if (pAesdrvContext->ioMode == aesdrvIoModeCore) + { +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext && (la || lm)) + { + pAsynchContext->hdrLength = la; + pAsynchContext->dataLength = lm; + pAsynchContext->pHdr = (uint8_t*) pHdr; + pAsynchContext->la = la; + pAsynchContext->pDataInput = (uint8_t*) pDataInput; + pAsynchContext->pDataOutput = pDataOutput; + pAsynchContext->lm = lm; + pAsynchContext->authTagLength = authTagLength; + + /* Kick off interrupt driven CCM operation by processing header + (additional data) if included. If not, kick off with data encryption */ + if (la) + { + aesdrv_CCM_HeaderProcess(pAesdrvContext, (uint8_t*)pHdr, la); + } + else + { + pAsynchContext->encryptingHeader = false; + + /* Check if payload to be encrypted. */ + if (lm) + { + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 16; + aesdrvDataLoadAsynch(crypto, pDataInput, lm); + } + } + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + /* Process header (additional data) if included.*/ + if (la) + { + aesdrv_CCM_HeaderProcess(pAesdrvContext, (uint8_t*)pHdr, la); + } + + /* If there is a payload to be encrypted to the encryption. */ + if (lm) + { + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 16; + aesdrvDataLoadStore(crypto, pDataInput, pDataOutput, lm); + } + + /* Finally encrypt authentication tag. */ + if (authTagLength) + { + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + CRYPTO_EXECUTE_4(crypto, + CRYPTO_CMD_INSTR_DATA1INCCLR, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA2TODATA0XOR); + /* Wait for completion */ + CRYPTO_InstructionSequenceWait(crypto); + } + } + } + else + { + crypto->SEQCTRLB = lm; + crypto->SEQCTRL = la+2; + + /* Configure BUFC or DMA */ + AESDRV_HwIoSetup(pAesdrvContext, (uint8_t*)pHdr, la, lm); + + /* Load 16bit authentication length to CRYPTO. */ + crypto->DATA0BYTE = la >> 8; + crypto->DATA0BYTE = la; + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + pAsynchContext->la = 0; + pAsynchContext->lm = 0; + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + /* Trigger CRYPTO sequence. */ + CRYPTO_InstructionSequenceExecute(crypto); + /* Wait for completion */ + CRYPTO_InstructionSequenceWait(crypto); + } + return ECODE_OK; +} + +/***************************************************************************//** + * @brief + * Function is handling authentication only part of CCM. It assumes that + * CRYPTO is preloaded with proper instruction sequence. + * + * @param[in] pAesdrvontext + * AESDRV context + * + * @param[in] pHdr + * Input data + * + * @param[in] la + * length of data to be authenticated only. + ******************************************************************************/ +static void aesdrv_CCM_HeaderProcess(AESDRV_Context_t* pAesdrvContext, + uint8_t * pHdr, + uint32_t la) + +{ + uint32_t tempBuf32[4]; + uint8_t* tempBuf = (uint8_t*)tempBuf32; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + /* Prepare first block for CBC in CCM which consists of 2 byte length field + * and auth data which must be zero padded if there is less data than 14 bytes. + */ + memset(tempBuf, 0, 16); + + tempBuf[0] = (uint8_t)(la>>8); + tempBuf[1] = (uint8_t)la; + + memcpy(&tempBuf[2], pHdr, la<14 ? la : 14); + + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + + CRYPTO_DataWrite(&crypto->DATA0, tempBuf32); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + /* In the asynch mode, set the encryptingHeader flag in the context data in + order for the asynch callback to know that we are encrypting the header + part. */ + if (pAsynchContext) + { + pAsynchContext->encryptingHeader = true; + if (la > 14) + { + pAsynchContext->la -= 14; + pAsynchContext->pHdr += 14; + } + else + { + pAsynchContext->la = 0; + } + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + CRYPTO_InstructionSequenceExecute(crypto); + + /* Handle remaining header data. */ + if ( +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + (0==pAsynchContext) && +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + (la>14)) + { + la -= 14; + pHdr += 14; + aesdrvDataLoad(crypto, pHdr, la); + } +} + +/** + * Function setup crypto for GCM, loads Key to crypto and calculates initial + * values. + * + * @details + * Function is a common implementation for GCM with MCU,DMA and BUFC. + * + * @param pKey + * Key (128bit) + * @param pInitialVector + * Initial Vector (96bits) + */ +static void aesdrv_GCM_Prepare(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey, + uint8_t* pInitialVector) +{ + uint32_t j; + uint32_t* _ctr = (uint32_t *) pInitialVector; + const uint32_t* _key = (const uint32_t *) pKey; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + /* Setup CRYPTO for GCM operation: + - AES-128 mode (256 not supported) + - width of counter in CTR cipher mode to 4 bytes. + - enable DMA unaligned access and set + */ + crypto->CTRL = CRYPTO_CTRL_AES_AES128 | + CRYPTO_CTRL_INCWIDTH_INCWIDTH4 | + CRYPTO_CTRL_DMA0MODE_LENLIMIT; + crypto->WAC = 0; + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + + /* Set modulus to GCM. */ + CRYPTO_ModulusSet(crypto, cryptoModulusGcmBin128); + + /* Need to set result width? */ + CRYPTO_ResultWidthSet(crypto, cryptoResult128Bits); + + /* + ** CRYPTO register usage: + ** DATA0 - temporary result and plaintext + ** DATA2 - Hash key + ** DATA3 - E(K, Y0) which is used finally to XOR GHASH to produce the final tag + ** + ** DDATA0 - temporary results in the GHASH function (Xi-1) + ** DDATA1 - A and C parameters of the GHASH + ** DDATA2 - overlaps DATA0 and DATA1 + ** DDATA3 - overlaps DATA2 and DATA3 + ** DDATA4 - KEYBUF + */ + + /* Load initial values to the CRYPTO module. */ + for (j = 0; j < 4; j++) + { + if (pKey) + { + /* Load key into KEYBUFFER for key buffer usage. */ + crypto->KEYBUF = _key[j]; + } + /* Load the initial counter value Y0 into DATA1. + Y0 = IV | 1 + That is, the 12 byte Initial Vector concatenated with the initial + counter value 1 in the least significant 32bit word. + */ + if (j==3) + { + crypto->DATA1 = 0x01000000; + } + else + { + crypto->DATA1 = _ctr[j]; + } + } + + /* Organize and Compute the initial values. */ + CRYPTO_EXECUTE_6(crypto, + /* Compute hash key H=E(K,0) */ + CRYPTO_CMD_INSTR_DATA0TODATA0XOR,/* DATA0 = 0 */ + CRYPTO_CMD_INSTR_AESENC, /* DATA0 = AESENC(DATA0) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA2,/* Select DATA0 for BBSWAP instruction */ + CRYPTO_CMD_INSTR_BBSWAP128, /* Swap bit in H, needed for GMAC */ + CRYPTO_CMD_INSTR_DDATA0TODDATA3, /* Move resulting hash key + (in LSWord of DDATA0) to + DATA2 (LSWord ofDDATA3)*/ + /* Prepare GHASH(H,A) */ + CRYPTO_CMD_INSTR_CLR /* DDATA0 = 0 */ + ); +} + +/***************************************************************************//** + * @brief + * Function loads GCM instruction sequence to CRYPTO based on input parameters + * and hw I/O mode. + * + * @param encrypt + * true - encryption + * false - decryption + * + ******************************************************************************/ +static inline void aesdrv_GCM_SeqSet(AESDRV_Context_t* pAesdrvContext, + const bool encrypt) +{ + const uint8_t * instrSeq; + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + if (encrypt) + { + instrSeq = gcmAuthEncr[ioMode]; + } + else + { + instrSeq = gcmAuthDecr[ioMode]; + } + + CRYPTO_InstructionSequenceLoad(crypto, instrSeq); +} + +/***************************************************************************//** + * @brief + * Function performs GCM algorithm. In case of HW I/O mode it sets + * sequences lengths, setups hw I/O mode and triggers CRYPTO sequencer. + * When HW I/O mode is not used function performs GCM using MCU access + * to CRYPTO registers. + * + * @param[in] pDataInput + * If @p encrypt is true, pDataInput is the plaintext. + * I.e. the payload data to encrypt. + * If @p encrypt is false, pDataInput is the ciphertext. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pDataOutput + * If @p encrypt is true, pDataOutput is the ciphertext. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pDataOutput is the plaintext. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param dataLength + * data length + * + * @param pHdr + * pointer do header + * + * @param hdrLength + * header length. + * + ******************************************************************************/ +static void aesdrv_GCM_Execute(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + uint16_t dataLength, + const uint8_t* pHdr, + uint32_t hdrLength) +{ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_GCM_AsynchContext_t* pAsynchContext = + (AESDRV_GCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if (pAesdrvContext->ioMode == aesdrvIoModeCore) + { +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + pAsynchContext->hdrLength = hdrLength; + pAsynchContext->dataLength = dataLength; + pAsynchContext->lm = dataLength; + pAsynchContext->pDataInput = pDataInput; + pAsynchContext->pDataOutput = pDataOutput; + + /* Kick off interrupt driven GCM operation by processing header + (if present) or data encryption. */ + if (hdrLength) + { + if (hdrLength > 16) + { + pAsynchContext->la = hdrLength - 16; + pAsynchContext->pHdr = pHdr + 16; + } + else + { + pAsynchContext->la = 0; + } + pAsynchContext->encryptingHeader = true; + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + aesdrvDataLoadAsynch(crypto, pHdr, hdrLength); + } + else + { + pAsynchContext->la = 0; + /* Check if payload to be encrypted. */ + if (dataLength) + { + pAsynchContext->encryptingHeader = false; + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 16; + aesdrvDataLoadAsynch(crypto, pDataInput, dataLength); + } + } + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + /* Process authentication part only.*/ + if (hdrLength) + { + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + aesdrvDataLoad(crypto, (uint8_t*)pHdr, hdrLength); + } + + /* If there is a payload to be encrypted to the encryption. */ + if (dataLength) + { + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 16; + aesdrvDataLoadStore(crypto, pDataInput, pDataOutput, dataLength); + } + /* Wait for completion */ + while(!CRYPTO_InstructionSequenceDone(crypto)); + } + } + else + { + if (dataLength+hdrLength) + { +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (pAsynchContext) + { + pAsynchContext->hdrLength = hdrLength; + pAsynchContext->dataLength = dataLength; + pAsynchContext->la = 0; + pAsynchContext->lm = 0; + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + crypto->SEQCTRL = hdrLength; + crypto->SEQCTRLB = dataLength; + + AESDRV_HwIoSetup(pAesdrvContext, + (uint8_t*)pHdr, hdrLength, dataLength); + + /* Trigger CRYPTO sequence. */ + CRYPTO_InstructionSequenceExecute(crypto); + + /* Wait for completion */ + while(!CRYPTO_InstructionSequenceDone(crypto)); + } + } +} + +/** + * @brief + * Function calculates last part of GHASH (length fields) and + * Authentication Tag. + * + * @details + * Function is common for all three modes (MCU,BUFC,DMA). + * + * @param authDataLength + * Number of bytes in authentication part. + * + * @param plaintextLength + * Number of bytes in payload. + * + * @param pAuthTag + * pointer to memory where AuthTag is written. + * + * @param authTagLength + * length of authentication tag (in bytes). Up to 16 bytes. + */ +static void aesdrv_GCM_Finalize(AESDRV_Context_t* pAesdrvContext, + unsigned int authDataLength, + unsigned int plaintextLength) +{ + uint32_t ddata[8]; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + CRYPTO_DDataRead(&crypto->DDATA0, ddata); + + crypto->SEQCTRL = 16; + crypto->SEQCTRLB = 0; + + crypto->KEY = 0; + crypto->KEY = __REV((authDataLength * 8)); + crypto->KEY = 0; + crypto->KEY = __REV((plaintextLength * 8)); + + CRYPTO_EXECUTE_15(crypto, + /* Calculate last part of GHASH (length fields) */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, /* A[i] and Xi-1 */ + CRYPTO_CMD_INSTR_XOR, + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, /* temp result and H */ + CRYPTO_CMD_INSTR_MMUL, /* Xi is stored in DDATA0 */ + CRYPTO_CMD_INSTR_BBSWAP128, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_DATA2TODATA0, + /* Calculate AuthTag */ + CRYPTO_CMD_INSTR_DATA1INCCLR, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR + ); /* DATA0 = DATA0 ^ DATA3*/ +} + +/***************************************************************************//** + * @brief + * Function is called once Authentication Tag is already calculated (but not + * encrypted yet). Function is encrypting the tag and write back the tag (in + * case of encryption) or comparing received tag with calculcated tag (in case + * of decryption). + * + * @param[in,out] pAuthTag + * location of pAuthTag. In case of encryption tag will be stored there. In + * case of decryption location will be used for comparison with the tag + * calculated in CRYPTO. + * + * @param[in] encrypt + * true - encryption, false - decryption + * + * @param[in] authTagLength + * Length of authentication tag. + * + * @return + * true - in case of encryption always true, in case of decryption if + * authentication tag is validated with success. + * false - in case of decryption if authentication tag is invalid. + * + ******************************************************************************/ +static inline Ecode_t aesdrvAuthTagHandle(AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength, + bool encrypt) +{ + Ecode_t status = ECODE_OK; + + if (authTagLength) + { + if (encrypt) + { + aesdrvAuthTagRead(pAesdrvContext, pAuthTag, authTagLength); + } + else + { + status = aesdrvAuthTagCompare(pAesdrvContext, pAuthTag, authTagLength); + } + } + return status; +} + +/***************************************************************************//** + * @brief + * Function is reading authentication tag from CRYPTO. + * Function assumes that tag is in DATA0. + * + * @param[out] pAuthTag + * location of pAuthTag. + * + * @param[in] authTagLength + * Length of authentication tag. + * + ******************************************************************************/ +static void aesdrvAuthTagRead(AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength) +{ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + if (pAesdrvContext->authTagOptimize) + { + uint32_t * _pAuthTag = (uint32_t *)pAuthTag; + /* Local variables used to optimize load/store sequences from crypto to + memory. We want to load all 4 32bit data words to local register + variables in the first sequence, then store them all in the second + sequence.*/ + if (authTagLength<=4) + { + _pAuthTag[0] = crypto->DATA0; + } + else + { + uint32_t volatile* regPtr=&crypto->DATA0; + if (authTagLength > 12) + { + register uint32_t v0 = *regPtr; + register uint32_t v1 = *regPtr; + register uint32_t v2 = *regPtr; + register uint32_t v3 = *regPtr; + _pAuthTag[0] = v0; + _pAuthTag[1] = v1; + _pAuthTag[2] = v2; + _pAuthTag[3] = v3; + } + else + { + if (authTagLength > 8) + { + register uint32_t v0 = *regPtr; + register uint32_t v1 = *regPtr; + register uint32_t v2 = *regPtr; + _pAuthTag[0] = v0; + _pAuthTag[1] = v1; + _pAuthTag[2] = v2; + } + else + { + register uint32_t v0 = *regPtr; + register uint32_t v1 = *regPtr; + _pAuthTag[0] = v0; + _pAuthTag[1] = v1; + } + } + } + } + else + { + uint32_t tempBuf[4]; + CRYPTO_DataRead(&crypto->DATA0,tempBuf); + memcpy(pAuthTag,tempBuf,authTagLength); + } +} + +/***************************************************************************//** + * @brief + * Function is comparing authentication tag from CRYPTO with the received one. + * Function assumes that tag is in DATA0. + * + * @param[out] pAuthTag + * location of pAuthTag. + * + * @param[in] authTagLength + * Length of authentication tag. + * + * @return + * ECODE_OK - authentication tag is valid + * MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED - authentication tag is invalid. + * + ******************************************************************************/ +static Ecode_t aesdrvAuthTagCompare(AESDRV_Context_t* pAesdrvContext, + uint8_t* pAuthTag, + uint8_t authTagLength) +{ + Ecode_t status = ECODE_OK; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + if (pAesdrvContext->authTagOptimize) + { + uint32_t mask; + uint32_t zeroData; + CRYPTODRV_DataWriteUnaligned(&crypto->DATA3, pAuthTag); + + crypto->CMD = CRYPTO_CMD_INSTR_DATA3TODATA0XOR; + mask = (1 << (authTagLength/4))-1; + zeroData = (crypto->DSTATUS & _CRYPTO_DSTATUS_DATA0ZERO_MASK) + >> _CRYPTO_DSTATUS_DATA0ZERO_SHIFT; + + if ( (mask & zeroData) != mask) + { + status = MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + } + else + { + uint32_t tempBuf[4]; + CRYPTO_DataRead(&crypto->DATA0,tempBuf); + if (memcmp(pAuthTag,tempBuf,authTagLength)) + { + status = MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED; + } + } + + return status; +} + +/***************************************************************************//** + * @brief + * Function is loading DATA0 register with provided data and triggers CRYPTO + * sequence. Additionally, function handles zeropadding for last block. + * Function doesn't read back the data from CRYPTO it is supposed to be used + * for MIC only calculation part of CCM (header). + * + * @param[in] pData + * Input data + * + * @param[in] length + * length of data in bytes. + * + ******************************************************************************/ +static void aesdrvDataLoad(CRYPTO_TypeDef* crypto, + uint8_t * pData, + uint16_t length) +{ + uint32_t tempBuf[4]; + while(length) + { + /* Check if zero padding is needed. */ + if (length < 16) + { + /* Use temporary buffer for zero padding */ + memset(tempBuf,0,16); + memcpy(tempBuf,pData,length); + CRYPTO_DataWrite(&crypto->DATA0, tempBuf); + length = 0; + } + else + { + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, pData); + length -= 16; + pData += 16; + } + CRYPTO_InstructionSequenceExecute(crypto); + } +} + +/***************************************************************************//** + * @brief + * Function is loading DATA0 register with provided data and triggers CRYPTO + * sequence. Once sequence is completed that is read back from DATA0 and + * input data is overwritten. Additionally, function handles zeropadding + * for last block. Function is supposed to be used for payload part of CCM + * where data is encrypted. + * + * @param[in] pData + * Input data + * + * @param[in] length + * length of data in bytes. + * + ******************************************************************************/ +static void aesdrvDataLoadStore(CRYPTO_TypeDef* crypto, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + uint16_t length) +{ + uint32_t tempBuf[4]; + + while (length) + { + if (length < 16) + { + /* Use temporary buffer for zero padding */ + crypto->SEQCTRLB = length; + memset(tempBuf,0,16); + memcpy(tempBuf,pDataInput,length); + + CRYPTO_DataWrite(&crypto->DATA0, tempBuf); + CRYPTO_InstructionSequenceExecute(crypto); + + CRYPTO_DataRead(&crypto->DATA0, tempBuf); + memcpy(pDataOutput,tempBuf,length); + return; + } + else + { + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, pDataInput); + CRYPTO_InstructionSequenceExecute(crypto); + CRYPTODRV_DataReadUnaligned(&crypto->DATA0, pDataOutput); + length -= 16; + pDataInput += 16; + pDataOutput += 16; + } + } +} + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * Load data to CRYPTO in asynch mode. + * + * @details + * Function is loading DATA0 register with provided data, triggers CRYPTO + * sequencer and returns. The completion is handled by asynch callback. + * + * @param[in] pAsynchContext + * Context data for asynch mode. + * + ******************************************************************************/ +static void aesdrvDataLoadAsynch(CRYPTO_TypeDef* crypto, + const uint8_t* pData, + uint16_t length) +{ + if (length < 16) + { + /* Use temporary buffer for zero padding */ + uint32_t tempBuf[4]; + memset(tempBuf, 0, 16); + memcpy(tempBuf, pData, length); + CRYPTO_DataWrite(&crypto->DATA0, tempBuf); + } + else + { + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, pData); + } + CRYPTO_InstructionSequenceExecute(crypto); +} + +/***************************************************************************//** + * @brief + * Store output data from CRYPTO to memory in asynch mode. + * + * @details + * Function stores the output data located in the CRYPTO DATA0 register to + * the user output buffer in memory, and updates the asynch context data. + * + * @param[in] pAesdrvContext + * Context data aesdrv. + * + ******************************************************************************/ +static void aesdrvDataStoreAsynch(AESDRV_Context_t* pAesdrvContext) +{ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + AESDRV_CCM_AsynchContext_t* pAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAesdrvContext->pAsynchContext; + + int lm = pAsynchContext->lm; + if (lm < 16) + { + /* Use temporary buffer to store 128 bits (16 bytes) from + DATA0 register, and copy only lm bytes to user buffer. */ + uint32_t tempBuf[4]; + + CRYPTO_DataRead(&crypto->DATA0, tempBuf); + memcpy(pAsynchContext->pDataOutput, tempBuf, lm); + + pAsynchContext->lm = 0; + } + else + { + CRYPTODRV_DataReadUnaligned(&crypto->DATA0, pAsynchContext->pDataOutput); + pAsynchContext->lm -= 16; + pAsynchContext->pDataInput += 16; + pAsynchContext->pDataOutput += 16; + } + return; +} + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/** @endcond */ + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_aes.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_aes.c new file mode 100644 index 00000000000..84aae1cd566 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_aes.c @@ -0,0 +1,403 @@ +/* + * AES block cipher algorithms implementation using AES hw module + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This is an implementation of block cipher function using the AES hw + * module for acceleration. + * + * The module implements following interfaces: + * + * AESDRV_CBCx() + * AESDRV_CFBx() + * AESDRV_CTRx() + * AESDRV_DecryptKey128() + * AESDRV_DecryptKey256() + * AESDRV_ECBx() + * AESDRV_OFBx() + * + * Functions are mostly wrappers of emlib AES (em_aes.h) since block cipher + * functionality is provided by emlib. + */ + +#include "em_device.h" + +#if defined(AES_COUNT) && (AES_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_internal.h" +#include "aesdrv_common_aes.h" +#include "em_aes.h" +#include + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/* + * Generate 128 bit decryption key from 128 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DecryptKey128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + AESDRV_CLOCK_ENABLE; + AES_DecryptKey128(out,in); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +} + +/* + * Generate 256 bit decryption key from 256 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DecryptKey256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t * in) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + AESDRV_CLOCK_ENABLE; + AES_DecryptKey256(out,in); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +#else + (void) out; (void) in; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +/* + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CBC128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + uint8_t tmpIv[16]; + if (false == encrypt) + { + if (len>=16) + memcpy(tmpIv, &in[len-16], 16); + } + AESDRV_CLOCK_ENABLE; + AES_CBC128(out,in,len,key,iv,encrypt); + AESDRV_CLOCK_DISABLE; + if (len>=16) + { + if (encrypt) + memcpy(iv, &out[len-16], 16); + else + memcpy(iv, tmpIv, 16); + } + return ECODE_OK; +} + + /* + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CBC256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + uint8_t tmpIv[16]; + if (false == encrypt) + { + if (len>=16) + memcpy(tmpIv, &in[len-16], 16); + } + + AESDRV_CLOCK_ENABLE; + AES_CBC256(out,in,len,key,iv,encrypt); + AESDRV_CLOCK_DISABLE; + + if (len>=16) + { + if (encrypt) + memcpy(iv, &out[len-16], 16); + else + memcpy(iv, tmpIv, 16); + } + return ECODE_OK; +#else + (void) out; (void) in; (void) len; (void) key; (void) iv; (void) encrypt; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +/* + * Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + uint8_t tmpIv[16]; + if (false == encrypt) + { + if (len>=16) + memcpy(tmpIv, &in[len-16], 16); + } + + AESDRV_CLOCK_ENABLE; + AES_CFB128(out,in,len,key,iv,encrypt); + AESDRV_CLOCK_DISABLE; + + if (len>=16) + { + if (encrypt) + memcpy(iv, &out[len-16], 16); + else + memcpy(iv, tmpIv, 16); + } + return ECODE_OK; +} + +/* + * Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + uint8_t tmpIv[16]; + if (false == encrypt) + { + if (len>=16) + memcpy(tmpIv, &in[len-16], 16); + } + + AESDRV_CLOCK_ENABLE; + AES_CFB256(out,in,len,key,iv,encrypt); + AESDRV_CLOCK_DISABLE; + + if (len>=16) + { + if (encrypt) + memcpy(iv, &out[len-16], 16); + else + memcpy(iv, tmpIv, 16); + } + return ECODE_OK; +#else + (void) out; (void) in; (void) len; (void) key; (void) iv; (void) encrypt; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +/* + * Counter (CTR) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CTR128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + AESDRV_CtrCallback_t pCtrFunc; + + if (ctrCallback) + { + pCtrFunc = ctrCallback; + } + else + { + pCtrFunc = AES_CTRUpdate32Bit; + } + + AESDRV_CLOCK_ENABLE; + AES_CTR128(out,in,len,key,ctr,pCtrFunc); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +} + +/* + * Counter (CTR) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CTR256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + AESDRV_CtrCallback_t pCtrFunc; + + if (ctrCallback) + { + pCtrFunc = ctrCallback; + } + else + { + pCtrFunc = AES_CTRUpdate32Bit; + } + + AESDRV_CLOCK_ENABLE; + AES_CTR256(out,in,len,key,ctr,pCtrFunc); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +#else + (void) out; (void) in; (void) len; (void) key; (void) ctr; (void) ctrCallback; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +/* + * Electronic Codebook (ECB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_ECB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt + ) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + AESDRV_CLOCK_ENABLE; + AES_ECB128(out,in,len,key,encrypt); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +} + +/* + * Electronic Codebook (ECB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_ECB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + AESDRV_CLOCK_ENABLE; + AES_ECB256(out,in,len,key,encrypt); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +#else + (void) out; (void) in; (void) len; (void) key; (void) encrypt; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +/* + * Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_OFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ + AESDRV_CLOCK_ENABLE; + AES_OFB128(out,in,len,key,iv); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +} + +/* + * Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_OFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv) +{ + (void) pAesdrvContext; /* The pAesdrvContext parameter is not used for + basic AES block cipher mode. */ +#if defined( AES_CTRL_AES256 ) + AESDRV_CLOCK_ENABLE; + AES_OFB256(out,in,len,key,iv); + AESDRV_CLOCK_DISABLE; + return ECODE_OK; +#else + (void) out; (void) in; (void) len; (void) key; (void) iv; + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif +} + +#endif /* #if defined(AES_COUNT) && (AES_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_crypto.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_crypto.c new file mode 100644 index 00000000000..162e263ca27 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_blockcipher_crypto.c @@ -0,0 +1,1075 @@ +/* + * AES block cipher algorithms implementation using the CRYPTO hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This is an implementation of block cipher function using CRYPTO hw module. + * + * The module implements following public interfaces: + * AESDRV_CBCx() + * AESDRV_CFBx() + * AESDRV_CTRx() + * AESDRV_DecryptKey128() + * AESDRV_DecryptKey256() + * AESDRV_ECBx() + * AESDRV_OFBx() + */ + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_internal.h" +#include "aesdrv_common_crypto.h" +#include "cryptodrv_internal.h" +#include "em_assert.h" +#include "em_crypto.h" + +/******************************************************************************* + ******************************* MACROS ************************************ + ******************************************************************************/ +#define AES_BLOCKSIZE 16 + +/******************************************************************************* + ****************************** TYPEDEFS *********************************** + ******************************************************************************/ + +/** AESDRV list of instruction used by block cipher modes. It is limited to + * 8 instruction (2 SEQ registers) because none of cipher modes requires more + * to execute. */ +typedef const uint8_t AESDRV_BlockCipherInstrSeq_t[8]; + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ +static inline Ecode_t aesdrvProcessLoopMCU +( + AESDRV_Context_t* pAesdrvContext, + uint32_t len, + const uint8_t* in, + uint8_t* out + ); +static inline Ecode_t aesdrvProcessLoopHW +( + AESDRV_Context_t* pAesdrvContext + ); +static void aesdrvBlockCipherPrepare +( + AESDRV_Context_t* pAesdrvContext, + const uint8_t* key, + const uint8_t* iv, + CRYPTO_KeyWidth_TypeDef keyWidth, + AESDRV_BlockCipherInstrSeq_t* instrCode, + AESDRV_IoMode_t ioMode + ); +static void aesdrvBlockCipherHwSetup +( + AESDRV_Context_t* pAesdrvContext, + uint32_t len, + uint32_t * inout + ); +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) +static void aesdrvAsynchCallback +( + void* asynchCallbackArgument + ); +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ +static Ecode_t aesdrvBlockCipher +( + AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + CRYPTO_KeyWidth_TypeDef keyWidth, + AESDRV_BlockCipherInstrSeq_t* instrCode + ); +static Ecode_t aesdrvDecryptKey +( + AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + CRYPTO_KeyWidth_TypeDef keyWidth + ); + +/******************************************************************************* + ************************** STATIC VARIABLES ********************************* + ******************************************************************************/ + +/** CRYPTO sequencer instruction for CBC encryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_CBC_Encrypt[] = { + /* MCU */ + { + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA1, + CRYPTO_CMD_INSTR_DATA0TODATA2 + }, + + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_DATA0TODATA1 + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DATA0TODATA1 + } +#endif +}; + +/** CRYPTO sequencer instruction for CBC decryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_CBC_Decrypt[] = +{ + /*MCU*/ + { + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_DATA3TODATA1, + CRYPTO_CMD_INSTR_DATA0TODATA2 + }, + /*BUFC*/ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_DATA2TODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA1 + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /*DMA*/ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA1TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DATA2TODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA1 + } +#endif +}; + +/** CRYPTO sequencer instruction for CFB encryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_CFB_Encrypt[] = +{ + /* MCU */ + { + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_DATA0TODATA1 + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_DATA0TODATA1 + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DATA0TODATA1 + } +#endif +}; + +/** CRYPTO sequencer instruction for CFB decryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_CFB_Decrypt[] = +{ + /* MCU */ + { + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_DATA3TODATA1 + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_DATA3TODATA1 + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DATA3TODATA1 + } +#endif +}; + +/** CRYPTO sequencer instruction for CTR. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_CTR[] = +{ + /*MCU*/ + { + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TODATA2 + }, + /*BUFC*/ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_END + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /*DMA*/ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA1INC, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_END + } +#endif +}; + +/** CRYPTO sequencer instruction for ECB encryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_ECB_Encrypt[] = +{ + /* MCU */ + { + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + } +#endif +}; + +/** CRYPTO sequencer instruction for ECB decryption. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_ECB_Decrypt[] = +{ + /* MCU */ + { + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + } +#endif +}; + +/** CRYPTO sequencer instruction for OFB. + * There are 3 variants: MCU,BUFC,DMA. */ +static AESDRV_BlockCipherInstrSeq_t aesdrv_OFB[] = +{ + /* MCU */ + { + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA1, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TODATA2, + CRYPTO_CMD_INSTR_END, + CRYPTO_CMD_INSTR_END + }, + /* BUFC */ + { + CRYPTO_CMD_INSTR_BUFTODATA0, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA1, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATA0TOBUF, + CRYPTO_CMD_INSTR_END + }, +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* DMA */ + { + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DATA0TODATA3, + CRYPTO_CMD_INSTR_DATA1TODATA0, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DATA0TODATA1, + CRYPTO_CMD_INSTR_DATA3TODATA0XOR, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_END + } +#endif +}; + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/* + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CBC128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t * instr = encrypt ? + &aesdrv_CBC_Encrypt[ioMode] : &aesdrv_CBC_Decrypt[ioMode]; + + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey128Bits, instr); +} + +/* + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CBC256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t * instr = encrypt ? + &aesdrv_CBC_Encrypt[ioMode] : &aesdrv_CBC_Decrypt[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey256Bits, instr); +} + +/* + * Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t * instr = encrypt ? + &aesdrv_CFB_Encrypt[ioMode] : &aesdrv_CFB_Decrypt[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey128Bits, instr); +} + +/* + * Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t * instr = encrypt ? + &aesdrv_CFB_Encrypt[ioMode] : &aesdrv_CFB_Decrypt[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey256Bits, instr); +} + +/* + * Counter (CTR) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CTR128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback) +{ + (void)ctrCallback; /* We do not support user specified counter callback + for CRYPTO.*/ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = &aesdrv_CTR[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, ctr, cryptoKey128Bits, instr); +} + +/* + * Counter (CTR) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_CTR256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback) +{ + (void) ctrCallback; /* The ctrCallback parameter is not supported for + devices with CRYPTO.*/ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = &aesdrv_CTR[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, ctr, cryptoKey256Bits, instr); +} + +/* + * Electronic Codebook (ECB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_ECB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = + encrypt ? &aesdrv_ECB_Encrypt[ioMode] : &aesdrv_ECB_Decrypt[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, 0, cryptoKey128Bits, instr); +} + +/* + * Electronic Codebook (ECB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_ECB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = + encrypt ? &aesdrv_ECB_Encrypt[ioMode] : &aesdrv_ECB_Decrypt[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, 0, cryptoKey256Bits, instr); +} + +/* + * Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_OFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = &aesdrv_OFB[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey128Bits, instr); +} + +/* + * Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_OFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv) +{ + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + AESDRV_BlockCipherInstrSeq_t *instr = &aesdrv_OFB[ioMode]; + return aesdrvBlockCipher(pAesdrvContext, + out, in, len, key, iv, cryptoKey256Bits, instr); +} + +/* + * Generate 128 bit decryption key from 128 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DecryptKey128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in) +{ + return aesdrvDecryptKey(pAesdrvContext, out, in, cryptoKey128Bits); +} + + +/* + * Generate 256 bit decryption key from 256 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DecryptKey256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t * in) +{ + return aesdrvDecryptKey(pAesdrvContext, out, in, cryptoKey256Bits); +} + +/***************************************************************************//** + * @brief + * Generate decryption key from encryption key. The decryption + * key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES context structure. + * + * @param[out] out + * Buffer to place 128/256 bit decryption key. Must be at least 16/32 bytes + * long. It may be set equal to @p in, in which case the input buffer is + * overwritten. + * + * @param[in] in + * Buffer holding 128/256 bit encryption key. Must be at least 32 bytes long. + * + * @param[in] keyWidth + * Key width - 128 or 256 bits. + ******************************************************************************/ +static Ecode_t aesdrvDecryptKey(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + uint32_t* _out = (uint32_t *) out; + const uint32_t* _in = (const uint32_t *) in; + Ecode_t status, retval; + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + EFM_ASSERT(((uint32_t)_in&0x3)==0); + EFM_ASSERT(((uint32_t)_out&0x3)==0); + + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + status = CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + if (ECODE_OK == status) + { + + CRYPTO_KeyBufWrite(crypto, (uint32_t *)_in, keyWidth); + + CRYPTO_EXECUTE_1(crypto, CRYPTO_CMD_INSTR_AESENC); + + CRYPTO_KeyRead(crypto, _out, keyWidth); + + status = CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + } + retval = CRYPTODRV_Release(pCryptodrvContext); + + return ECODE_OK == retval ? status : retval; +} + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * Callback function for asynchronous operation. + * + * @param[in] asynchCallbackArgument + * Callback argument. + ******************************************************************************/ +static void aesdrvAsynchCallback (void* asynchCallbackArgument) +{ + AESDRV_Context_t* pAesdrvContext = + (AESDRV_Context_t*) asynchCallbackArgument; + + if (pAesdrvContext) + { + AESDRV_BlockCipherAsynchContext_t* pAsynchContext = + (AESDRV_BlockCipherAsynchContext_t*) pAesdrvContext->pAsynchContext; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + if (pAsynchContext->remainingBlocks) + { + /* Save encrypted/decrypted data */ + CRYPTODRV_DataReadUnaligned(&crypto->DATA2, (uint8_t*)pAsynchContext->pBlockOut); + + pAsynchContext->pBlockOut += 4; + pAsynchContext->pBlockIn += 4; + pAsynchContext->remainingBlocks--; + } + + if (pAsynchContext->remainingBlocks) + { + /* Load data and trigger encryption */ + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, (uint8_t*)pAsynchContext->pBlockIn); + CRYPTO_InstructionSequenceExecute(crypto); + } + else + { + Ecode_t status; + uint8_t* pInitialVector = pAsynchContext->pInitialVector; + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + + /* Turn off interrupts. */ + CRYPTODRV_SetAsynchCallback(pCryptodrvContext, 0, 0); + + /* Read the last counter value from DATA1 to user the counter pointer. */ + if (pInitialVector) + { + CRYPTODRV_DataReadUnaligned(&crypto->DATA1, pInitialVector); + } + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + status = CRYPTODRV_Release(pCryptodrvContext); + + /* Finally call the user callback */ + if (pAsynchContext->asynchCallback) + { + pAsynchContext->asynchCallback((int)status, + pAsynchContext->asynchCallbackArgument); + } + } + } +} + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/***************************************************************************//** + * @brief + * Generic function for performing AES block ciphers. + * + * @details + * Block cipher mode is identified by CRYPTO sequencer code + * provided. Each sequencer code assumes that: + * - IV/CTR is loaded into DATA1 + * - Input is loaded into DATA0 + * - Output is read from DATA2 + * + * @param[out] out + * Buffer to place 128/256 bit decryption key. Must be at least 16/32 bytes + * long. It may be set equal to @p in, in which case the input buffer is + * overwritten. + * + * @param[in] in + * Buffer holding 128/256 bit encryption key. Must be at least 32 bytes long. + * + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] keyWidth + * Key width - 128 or 256 bits. + * + * @param[in] instrCode + * CRYPTO sequencer instructions. + ******************************************************************************/ +static Ecode_t aesdrvBlockCipher +( + AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + CRYPTO_KeyWidth_TypeDef keyWidth, + AESDRV_BlockCipherInstrSeq_t* instrCode + ) +{ + Ecode_t status, retval; + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_BlockCipherAsynchContext_t* pAsynchContext = + (AESDRV_BlockCipherAsynchContext_t*) pAesdrvContext->pAsynchContext; +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + AESDRV_IoMode_t ioMode = pAesdrvContext->ioMode; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + status = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != status) + return status; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + aesdrvBlockCipherPrepare(pAesdrvContext, key, iv, keyWidth, instrCode, ioMode); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + /* If asynchronous non-blocking mode, register completion callback */ + if (pAsynchContext) + { + pAsynchContext->pInitialVector = iv; + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + CRYPTODRV_SetAsynchCallback (pCryptodrvContext, + aesdrvAsynchCallback, pAesdrvContext); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + if (ioMode == aesdrvIoModeCore) + { + retval = aesdrvProcessLoopMCU(pAesdrvContext, len, in, out); + } + else + { + EFM_ASSERT(in==out); + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + aesdrvBlockCipherHwSetup(pAesdrvContext, len, (uint32_t*)in); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + retval = aesdrvProcessLoopHW(pAesdrvContext); + } + + /* Release CRYPTO if blocking mode. */ +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (0 == pAsynchContext) +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + /* If the 'iv' pointer is set, read last iv value. */ + if (iv) + { + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + CRYPTODRV_DataReadUnaligned(&crypto->DATA1, iv); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + } + + status = CRYPTODRV_Release(pCryptodrvContext); + if (ECODE_OK != status) + retval = status; + } + + return retval; +} + +/***************************************************************************//** + * @brief + * Generic function for blockCipher preparation. It sets initial value in + * DATA1 register, loads the key to KEYBUF and loads CRYPTO sequence + * instructions. It is independent of I/O mode used. + * + * @param[in] key + * 128/256 bit encryption key. + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] keyWidth + * Key width - 128 or 256 bits. + * + * @param[in] instrCode + * CRYPTO sequencer instructions. + ******************************************************************************/ +static void aesdrvBlockCipherPrepare +( + AESDRV_Context_t* pAesdrvContext, + const uint8_t* key, + const uint8_t* iv, + CRYPTO_KeyWidth_TypeDef keyWidth, + AESDRV_BlockCipherInstrSeq_t* instrCode, + AESDRV_IoMode_t ioMode + ) +{ + const uint32_t* _instr = (const uint32_t *)instrCode; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + + /* Setup CRYPTO for basic AES block cipher operation: + - width of counter in CTR cipher mode to 4 bytes. + */ + if (instrCode == &aesdrv_CTR[ioMode]) + { + crypto->CTRL = CRYPTO_CTRL_INCWIDTH_INCWIDTH4; + } + else + { + crypto->CTRL = 0; + } + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + if (key) + { + CRYPTO_KeyBufWrite( crypto, (uint32_t *)key, keyWidth ); + } + + if (iv) + { + CRYPTODRV_DataWriteUnaligned( &crypto->DATA1, iv ); + } + + crypto->SEQ0 = _instr[0]; + crypto->SEQ1 = _instr[1]; +} + +/***************************************************************************//** + * @brief + * Function setups hw I/O mode (BUFC or DMA) and setup sequence length in + * CRYPTO. In case of DMA channels are configured and in case of BUFC buffer + * is setup. + * + * @param[in] len + * Number of bytes to process. + * + * @param[in] inout + * Pointer to input data. This location is also used to store the output. + * + ******************************************************************************/ +static void aesdrvBlockCipherHwSetup +( + AESDRV_Context_t* pAesdrvContext, + uint32_t len, + uint32_t* inout + ) +{ + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + EFM_ASSERT(len<=_CRYPTO_SEQCTRL_LENGTHA_MASK); + crypto->SEQCTRL = len; + AESDRV_HwIoSetup(pAesdrvContext, (uint8_t*)inout, 0, len); +} + +/***************************************************************************//** + * @brief + * Process loop function to be used in MCU mode. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * Function is processing requested number of blocks. Data transfers are + * handled by MCU. + * + * @param[in] len + * Length in bytes. + * + * @param[in] in + * Input buffer. + * + * @param[out] out + * Output buffer. + * + * @return Error code + ******************************************************************************/ +static inline Ecode_t aesdrvProcessLoopMCU +( + AESDRV_Context_t* pAesdrvContext, + uint32_t len, + const uint8_t* in, + uint8_t* out + ) +{ + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_BlockCipherAsynchContext_t* pAsynchContext = + (AESDRV_BlockCipherAsynchContext_t*) pAesdrvContext->pAsynchContext; + + if (pAsynchContext) + { + pAsynchContext->remainingBlocks = len / AES_BLOCKSIZE; + pAsynchContext->pBlockIn = (uint32_t*)in; + pAsynchContext->pBlockOut = (uint32_t*)out; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + /* Load data and trigger encryption */ + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, in); + + CRYPTO_InstructionSequenceExecute(crypto); + } + else +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + len /= AES_BLOCKSIZE; + while (len--) + { + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + crypto->SEQCTRL = 16 << _CRYPTO_SEQCTRL_LENGTHA_SHIFT; + + /* Load data and trigger encryption */ + CRYPTODRV_DataWriteUnaligned(&crypto->DATA0, in); + + CRYPTO_InstructionSequenceExecute(crypto); + + /* Save encrypted/decrypted data */ + CRYPTODRV_DataReadUnaligned(&crypto->DATA2, out); + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + + out += 16; + in += 16; + } + + } + return ECODE_OK; +} + +/***************************************************************************//** + * @brief + * Process loop function to be used in HW I/O mode. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * Function is processing requested number of blocks. Data transfers are + * handled by BUFC or DMA. + * + * @return Error code + ******************************************************************************/ +static inline Ecode_t aesdrvProcessLoopHW +( + AESDRV_Context_t* pAesdrvContext + ) +{ + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + AESDRV_BlockCipherAsynchContext_t* pAsynchContext = + (AESDRV_BlockCipherAsynchContext_t*) pAesdrvContext->pAsynchContext; + + if (pAsynchContext) + { + pAsynchContext->remainingBlocks = 0; + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + CRYPTO_InstructionSequenceExecute(crypto); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + if (0 == pAsynchContext) +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + { + CRYPTO_InstructionSequenceWait(crypto); + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + } + return ECODE_OK; +} + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common.c new file mode 100644 index 00000000000..366888e3018 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common.c @@ -0,0 +1,278 @@ +/* + * Common functions for AES based algorithms for AES and CRYPTO hw modules. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "em_device.h" + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_internal.h" +#include "aesdrv_authencr.h" + +#if defined(CRYPTO_PRESENT) +#include "cryptodrv_internal.h" +#include "aesdrv_common_crypto.h" +#include "em_crypto.h" +#endif + +#include "em_assert.h" + +/******************************************************************************* + *************************** GLOBAL FUNCTIONS ****************************** + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Computes the length of the MIC (Message Integrity Code) + * for a given security level, as defined in IEEE Std 802.15.4-2006 table 95. + * + * @details + * The two LSBs of securityLevel encodes a MIC length of 0, 4, 8, or 16. + * + * @param[in] securityLevel + * Security level to use. + * + * @return + * The length of the MIC for the given @p securityLevel + ******************************************************************************/ +uint8_t AESDRV_CCMStar_LengthOfMIC(uint8_t securityLevel) +{ + securityLevel &= 3; + if (securityLevel == 3) + { + securityLevel++; + } + return securityLevel * 4; +} + +/***************************************************************************//** + * @brief + * CCM block cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * Please see http://en.wikipedia.org/wiki/CCM_mode for a general description + * of CCM. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pInputData + * If @p encrypt is true, pInputData is the 'P' (payload) parameter in CCM. + * I.e. the Payload data to encrypt. + * If @p encrypt is false, pInputData is the 'C' (ciphertext) parameter in CCM. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pOutputData + * If @p encrypt is true, pOututData is the 'C' (ciphertext) parameter in CCM. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pOutputData is the 'P' (payload) parameter in CCM. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param[in] dataLength + * Length of data to be encrypted/decrypted, referred to as 'p' in CCM. + * Note that this does not include the length of the MIC which is specified + * with @p authTagLength. + * + * @param[in] pHdr + * The 'A' parameter in CCM. + * Header is used for MIC calculation. + * Must be at least @p hdrLength long. + * + * @param[in] hdrLength + * The 'a' parameter in CCM. + * Length of header. + * + * @param[in] pKey + * The 'K' parameter in CCM. + * Pointer to key buffer. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] pNonce + * The 'N' parameter in CCM. + * Pointer to the nonce, which must have length 15-authTagLength + * See @p authTagLength + * + * @param[in] nonceLength + * The length in bytes, of the @p pNonce, i.e. the 'N' parameter in CCM. + * Currently only nonce size equal to 13 bytes is supported. + * + * @param[in] pAuthTag + * The 'MIC' parameter in CCM. + * Pointer to the MIC buffer, which must have length @p authTagLength. + * + * @param[in] authTagLength + * The 't' parameter in CCM. + * The number of bytes used for the authentication tag. + * Possible values are 0, 4, 6, 8, 10, 12, 14, 16. + * Note that 0 is not a legal value in CCM, but is used for CCM*. + * + * @param[in] encrypt + * Set to true to run the generation-encryption process, + * false to run the decryption-verification process. + * + * @return + * ECODE_OK if success. Error code if failure. + * Encryption will always succeed. + * Decryption may fail if the authentication fails. + ******************************************************************************/ +Ecode_t AESDRV_CCM(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt) +{ + return AESDRV_CCM_Generalized( pAesdrvContext, + pDataInput, + pDataOutput, + dataLength, + pHdr, + hdrLength, + pKey, + keyLength, + pNonce, + nonceLength, + pAuthTag, + authTagLength, + encrypt, + true); +} + +/***************************************************************************//** + * @brief + * CCM* block cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * Please see IEEE Std 802.15.4-2006 Annex B for a description of CCM*. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pDataInput + * If @p encrypt is true, pDataInput is the plaintext. + * I.e. the payload data to encrypt. + * If @p encrypt is false, pDataInput is the ciphertext. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pDataOutput + * If @p encrypt is true, pDataOutput is the ciphertext. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pDataOutput is the plaintext. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param[in] dataLength + * Length of data to be encrypted/decrypted, referred to as l(m) in CCM*. + * Note that this does not include the length of the MIC, + * so for decryption there are + * l(c) = @p dataLength + CCM_LengthOfMIC(securityLevel) + * bytes available in the buffer. + * + * @param[in] pHdr + * The 'a' parameter in CCM*. + * Header is used for MIC calculation. + * Must be at least @p hdrLength long. + * + * @param[in] hdrLength + * Length of header. + * Referred to as l(a) in CCM* + * + * @param[in] pKey + * The 'K' parameter in CCM*. + * Pointer to key to use. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] pNonce + * The 'N' parameter in CCM. + * Pointer to the nonce, which has length 13 bytes. + * + * @param[in] nonceLength + * The length in bytes, of the @p pNonce, i.e. the 'N' parameter in CCM*. + * + * @param[in] securityLevel + * Security level to use. See table 95 in IEEE Std 802.15.4-2006 + * See also function CCM_LengthOfMIC + * Level 0: No encryption, no authentication + * Level 1: No encryption, M=4 bytes authentication tag + * Level 2: No encryption, M=8 bytes authentication tag + * Level 3: No encryption, M=16 bytes authentication tag + * Level 4: Encryption, no authentication + * Level 5: Encryption, M=4 bytes authentication tag + * Level 6: Encryption, M=8 bytes authentication tag + * Level 7: Encryption, M=16 bytes authentication tag + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure. + * Encryption will always succeed. + * Decryption may fail if the authentication fails. + ******************************************************************************/ +Ecode_t AESDRV_CCMStar(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t securityLevel, + const bool encrypt) +{ + return AESDRV_CCM_Generalized( pAesdrvContext, + pDataInput, + pDataOutput, + dataLength, + pHdr, + hdrLength, + pKey, + keyLength, + pNonce, + nonceLength, + pAuthTag, + AESDRV_CCMStar_LengthOfMIC(securityLevel), + encrypt, + (securityLevel > 3)); +} + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.c new file mode 100644 index 00000000000..622a4f1a712 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.c @@ -0,0 +1,195 @@ +/* + * Common functions for AES based algorithms for the AES hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "em_device.h" + +#if defined(AES_COUNT) && (AES_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_internal.h" +#include "aesdrv_common_aes.h" +#include "em_assert.h" +#include + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/* + * Initializes an AESDRV context structure. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_Init(AESDRV_Context_t* pAesdrvContext) +{ + /* Clear the driver context. */ + memset(pAesdrvContext, 0, sizeof(AESDRV_Context_t)); + return ECODE_OK; +} + +/* + * DeInitializes an AESDRV context structure. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DeInit(AESDRV_Context_t* pAesdrvContext) +{ + /* Clear the driver context. */ + memset(pAesdrvContext, 0, sizeof(AESDRV_Context_t)); + return ECODE_OK; +} + +/* + * Set the AES encryption key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetKey(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey, + uint32_t keyLength) +{ + (void) pAesdrvContext; /* Key is stored directly in AES hw module and + not set in context structure. */ + Ecode_t retval = ECODE_OK; + const uint32_t * const _pKey = (const uint32_t *)pKey; + + if (pKey == NULL) + { + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + + /* Enable AES clock. */ + AESDRV_CLOCK_ENABLE; + + /* Load key */ +#if defined( AES_CTRL_AES256 ) + if (32==keyLength) + { + int i, j; + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_pKey[j]); + AES->KEYHA = __REV(_pKey[i]); + } + } + else +#endif + { + if (16==keyLength) + { + int i; +#if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL |= AES_CTRL_KEYBUFEN; + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_pKey[i]); + } +#else + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_pKey[i]); + } +#endif + } + else + { + retval = MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + } + + /* Disable AES clock. */ + AESDRV_CLOCK_DISABLE; + + return retval; +} + +/* + * Set the AES device instance. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetDeviceInstance(AESDRV_Context_t* pAesdrvContext, + unsigned int devno) +{ + (void) pAesdrvContext; /* Multiple instances not supported for AES module. */ + + if (devno >= AES_COUNT) + return MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + else + return ECODE_OK; +} + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/* + * Setup the asynchronous mode of an AESDRV context. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetAsynchMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_CipherMode_t cipherMode, + void* pAsynchContext, + AESDRV_AsynchCallback_t asynchCallback, + void* asynchCallbackArgument + ) +{ + (void) pAesdrvContext; /* Asynch mode not supported for AES module. */ + (void) cipherMode; /* Asynch mode not supported for AES module. */ + (void) asynchCallback; /* Asynch mode not supported for AES module. */ + (void) asynchCallbackArgument; /* Asynch mode not supported for AES module. */ + + if (pAsynchContext) + { + /* The EFM32 AES implementation does not support asynchronous mode yet. */ + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; + } + else + { + return ECODE_OK; + } +} + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/* + * Setup CRYPTO I/O mode. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetIoMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_IoMode_t ioMode, + AESDRV_IoModeSpecific_t* ioModeSpecific + ) +{ + (void) pAesdrvContext; /* Not supported for AES module. */ + (void) ioModeSpecific; /* Not supported for AES module. */ + if (ioMode == aesdrvIoModeCore) + { + return ECODE_OK; + } + else + { + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; + } +} + +#endif /* #if defined(AES_COUNT) && (AES_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.h new file mode 100644 index 00000000000..746ff64c3eb --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_aes.h @@ -0,0 +1,34 @@ +/* + * Common definitions for AES based algorithms for the AES hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __SILICON_LABS_AESDRV_COMMON_AES_H +#define __SILICON_LABS_AESDRV_COMMON_AES_H + +#include "em_device.h" + +#if defined(AES_COUNT) && (AES_COUNT > 0) + +/******************************************************************************* + ******************************* MACROS ************************************ + ******************************************************************************/ +#define AESDRV_CLOCK_ENABLE CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_AES +#define AESDRV_CLOCK_DISABLE CMU->HFCORECLKEN0 &= ~CMU_HFCORECLKEN0_AES + +#endif /* #if defined(AES_COUNT) && (AES_COUNT > 0) */ + +#endif /* __SILICON_LABS_AESDRV_COMMON_AES_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.c new file mode 100644 index 00000000000..0af435f548e --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.c @@ -0,0 +1,708 @@ +/* + * Common functions for AES based algorithms for the CRYPTO hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv_common_crypto.h" +#include "cryptodrv_internal.h" +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) +#include "dmadrv.h" +#endif +#include "em_crypto.h" +#if defined(BUFC_PRESENT) +#include "em_bufc.h" +#endif +#include "em_assert.h" +#include + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ +#define AESDRV_UTILS_BUFC_BUFFER_NOT_SET 0xFF +#define AESDRV_UTILS_DMA_CHANNEL_NOT_SET 0xFFFF + +/******************************************************************************* + ************************** STATIC FUNCTIONS ******************************* + ******************************************************************************/ +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) +static void aesdrvDmaReset (AESDRV_Context_t* pAesdrvContext); +static Ecode_t aesdrvDmaInit (AESDRV_Context_t* pAesdrvContext); +static void aesdrvDmaSetup (AESDRV_Context_t* pAesdrvContext, + uint8_t const* pData, + uint32_t authDataLength, + uint32_t textLength + ); +static void aesdrvDmaAddrLenGet(uint8_t** pBufIn, + uint8_t** pBufOut, + uint16_t lengthA, + uint16_t lengthB, + uint16_t* dmaLengthIn, + uint16_t* dmaLengthOut); +#endif /* #if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + +#if defined(BUFC_PRESENT) +static void aesdrvBufcInit (AESDRV_Context_t* pAesdrvContext, + uint8_t bufId + ); +static void aesdrvBufcSetup (AESDRV_Context_t* pAesdrvContext, + uint8_t const* pData, + uint32_t authDataLength); +#endif + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/* + * Initializes an AESDRV context structure. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_Init(AESDRV_Context_t* pAesdrvContext) +{ + /* Start by clearing the device context. */ + memset(pAesdrvContext, 0, sizeof(AESDRV_Context_t)); + + /* Set I/O mode to mcu core. */ + pAesdrvContext->ioMode = aesdrvIoModeCore; + + /* Clear the DMA channel config */ + pAesdrvContext->ioModeSpecific.dmaConfig.dmaChIn = + AESDRV_UTILS_DMA_CHANNEL_NOT_SET; + pAesdrvContext->ioModeSpecific.dmaConfig.dmaChOut = + AESDRV_UTILS_DMA_CHANNEL_NOT_SET; + +#if defined(BUFC_PRESENT) + /* Clear the bufc buffer id */ + pAesdrvContext->ioModeSpecific.bufcConfig.bufId = + AESDRV_UTILS_BUFC_BUFFER_NOT_SET; +#endif + + /* Disable authentication tag optimization */ + pAesdrvContext->authTagOptimize = false; + + /* Set default CRYPTO device instance to use. */ + cryptodrvSetDeviceInstance(&pAesdrvContext->cryptodrvContext, 0); + + /* Set I/O mode to mcu core. */ + return AESDRV_SetIoMode(pAesdrvContext, aesdrvIoModeCore, 0); +} + +/* + * DeInitializes AESDRV context. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_DeInit(AESDRV_Context_t* pAesdrvContext) +{ + switch( pAesdrvContext->ioMode ) + { + case aesdrvIoModeCore: + /* Do nothing. */ + break; + case aesdrvIoModeDma: +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + aesdrvDmaReset(pAesdrvContext); +#endif + break; + case aesdrvIoModeBufc: +#if defined(BUFC_PRESENT) + /* Clear the bufc buffer id */ + aesdrvBufcInit(pAesdrvContext, AESDRV_UTILS_BUFC_BUFFER_NOT_SET); +#endif + break; + } + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + /* If set, clear the asynch context. The size to clear depends on the + cipher mode. */ + if (pAesdrvContext->pAsynchContext) + { + switch (pAesdrvContext->cipherMode) + { + case cipherModeBlockCipher: + memset(pAesdrvContext->pAsynchContext, 0, + sizeof(AESDRV_BlockCipherAsynchContext_t)); + break; + case cipherModeCcm: + case cipherModeCcmBle: + memset(pAesdrvContext->pAsynchContext, 0, + sizeof(AESDRV_CCM_AsynchContext_t)); + break; + case cipherModeCmac: + memset(pAesdrvContext->pAsynchContext, 0, + sizeof(AESDRV_CMAC_AsynchContext_t)); + break; + case cipherModeGcm: + memset(pAesdrvContext->pAsynchContext, 0, + sizeof(AESDRV_GCM_AsynchContext_t)); + break; + case cipherModeNone: + default: + break; + } + } +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + + /* Clear the device context. */ + memset(pAesdrvContext, 0, sizeof(AESDRV_Context_t)); + + return ECODE_OK; +} + +/* + * Set the AES/CRYPTO device instance. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetDeviceInstance(AESDRV_Context_t* pAesdrvContext, + unsigned int devno) +{ + /* Set default CRYPTO device instance to use. */ + return cryptodrvSetDeviceInstance(&pAesdrvContext->cryptodrvContext, + devno); +} + +/* + * Set the AES encryption key. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetKey(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey, + uint32_t keyLength) +{ + Ecode_t retval = ECODE_OK; + CRYPTODRV_Context_t* pCryptodrvContext = &pAesdrvContext->cryptodrvContext; + + EFM_ASSERT(pKey); + + retval = CRYPTODRV_Arbitrate(pCryptodrvContext); + if (ECODE_OK != retval) + return retval; + + CRYPTODRV_EnterCriticalRegion(pCryptodrvContext); + + if (32==keyLength) + { + CRYPTO_KeyBufWrite(pCryptodrvContext->device->crypto, + (uint32_t*)pKey, cryptoKey256Bits); + } + else + { + if (16==keyLength) + { + CRYPTO_KeyBufWrite(pCryptodrvContext->device->crypto, + (uint32_t*)pKey, cryptoKey128Bits); + } + else + { + retval = MBEDTLS_ECODE_AESDRV_INVALID_PARAM; + } + } + + CRYPTODRV_ExitCriticalRegion(pCryptodrvContext); + retval = CRYPTODRV_Release(pCryptodrvContext); + return retval; +} + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) +/* + * Setup the asynchronous mode of an AESDRV context. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetAsynchMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_CipherMode_t cipherMode, + void* pAsynchContext, + AESDRV_AsynchCallback_t asynchCallback, + void* asynchCallbackArgument + ) +{ + pAesdrvContext->pAsynchContext = pAsynchContext; + pAesdrvContext->cipherMode = cipherMode; + + switch (cipherMode) + { + default: + pAesdrvContext->pAsynchContext = 0; + break; + case cipherModeBlockCipher: + { + AESDRV_BlockCipherAsynchContext_t* pBlockCipherAsynchContext = + (AESDRV_BlockCipherAsynchContext_t*) pAsynchContext; + pBlockCipherAsynchContext->asynchCallback = asynchCallback; + pBlockCipherAsynchContext->asynchCallbackArgument = asynchCallbackArgument; + } + break; + case cipherModeCcm: + case cipherModeCcmBle: + { + AESDRV_CCM_AsynchContext_t* pCcmAsynchContext = + (AESDRV_CCM_AsynchContext_t*) pAsynchContext; + pCcmAsynchContext->asynchCallback = asynchCallback; + pCcmAsynchContext->asynchCallbackArgument = asynchCallbackArgument; + } + break; + case cipherModeCmac: + { + AESDRV_CMAC_AsynchContext_t* pCmacAsynchContext = + (AESDRV_CMAC_AsynchContext_t*) pAsynchContext; + pCmacAsynchContext->asynchCallback = asynchCallback; + pCmacAsynchContext->asynchCallbackArgument = asynchCallbackArgument; + } + break; + case cipherModeGcm: + { + AESDRV_GCM_AsynchContext_t* pGcmAsynchContext = + (AESDRV_GCM_AsynchContext_t*) pAsynchContext; + pGcmAsynchContext->asynchCallback = asynchCallback; + pGcmAsynchContext->asynchCallbackArgument = asynchCallbackArgument; + } + break; + } + + return ECODE_OK; +} +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/* + * Check if ioMode is valid for crypto device of context. + */ +bool aesdrvIoModeValid +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_IoMode_t ioMode + ) +{ + if (ioMode != aesdrvIoModeBufc) + { + return true; + } + else + { +#if (CRYPTO_COUNT == 1) + (void) pAesdrvContext; + return true; +#elif (CRYPTO_COUNT == 2) + if ( pAesdrvContext->cryptodrvContext.device->crypto == CRYPTO1 ) + { + return true; + } + else + { + return false; + } +#else +#error Unsupported CRYPTO_COUNT. +#endif + } +} + +/* + * Setup CRYPTO I/O mode. + * Please refer to aesdrv.h for detailed description. + */ +Ecode_t AESDRV_SetIoMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_IoMode_t ioMode, + AESDRV_IoModeSpecific_t* ioModeSpecific + ) +{ + Ecode_t retval = ECODE_OK; +#if !defined(BUFC_PRESENT) + (void) ioModeSpecific; +#endif + + if (aesdrvIoModeValid(pAesdrvContext, ioMode) == false) + { + return MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; + } + + /* Start by reseting any previous settings, if applicable. */ + if ( ioMode != pAesdrvContext->ioMode ) + { + switch(pAesdrvContext->ioMode ) + { + case aesdrvIoModeCore: + break; + case aesdrvIoModeDma: +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + aesdrvDmaReset(pAesdrvContext); +#endif + break; + case aesdrvIoModeBufc: +#if defined(BUFC_PRESENT) + /* Clear the bufc buffer id */ + aesdrvBufcInit(pAesdrvContext, AESDRV_UTILS_BUFC_BUFFER_NOT_SET); +#endif + break; + } + + /* Set requested I/O mode now. */ + switch( ioMode ) + { + case aesdrvIoModeCore: + /* Do nothing. Just continue without hitting default label which signals + error.*/ + break; + + case aesdrvIoModeBufc: +#if defined(BUFC_PRESENT) + { + BUFC_Init_TypeDef bufcInit = BUFC_INIT_DEFAULT; + + /* Make sure BUFC clock is running. */ +#if defined (CMU_HFRADIOCLKEN0_BUFC) + CMU->HFRADIOCLKEN0 |= CMU_HFRADIOCLKEN0_BUFC; +#endif +#if defined (CMU_HFRADIOALTCLKEN0_BUFC) + CMU->HFRADIOALTCLKEN0 |= CMU_HFRADIOALTCLKEN0_BUFC; +#endif + + BUFC_Init(&bufcInit); + + aesdrvBufcInit(pAesdrvContext, ioModeSpecific->bufcConfig.bufId); + } +#else + retval = MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif + break; + case aesdrvIoModeDma: +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + /* Start by reseting previous settings.*/ + aesdrvDmaReset(pAesdrvContext); + retval = aesdrvDmaInit(pAesdrvContext); +#else + retval = MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; +#endif + break; + + default: + retval = MBEDTLS_ECODE_AESDRV_NOT_SUPPORTED; + } + + if (ECODE_OK == retval) + { + /* If success we store the I/O mode for later references. */ + pAesdrvContext->ioMode = ioMode; + } + } + + return retval; +} + +/* + * Prepare CRYPTO I/O mode to transfer data + */ +void AESDRV_HwIoSetup(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + uint32_t authDataLength, + uint32_t textLength) +{ +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + (void)pAesdrvContext; (void)pData; (void)authDataLength; (void)textLength; +#endif + switch (pAesdrvContext->ioMode) + { + case aesdrvIoModeBufc: +#if defined(BUFC_PRESENT) + aesdrvBufcSetup( pAesdrvContext, pData, authDataLength ); +#endif + break; + case aesdrvIoModeDma: +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + aesdrvDmaSetup( pAesdrvContext, pData, authDataLength, textLength ); +#endif + break; + default: + break; + } +} + +/******************************************************************************* + *********************** LOCAL STATIC FUNCTIONS **************************** + ******************************************************************************/ + +#if defined(BUFC_PRESENT) +/** + * Function initializes BUFC for CRYPTO + * + * @details + * Function only needs to store buffer id to be used. + * + * @param bufId + * BUFC Buffer Id to be used later on by CRYPTO. + */ +static void aesdrvBufcInit(AESDRV_Context_t* pAesdrvContext, + uint8_t bufId) +{ + pAesdrvContext->ioModeSpecific.bufcConfig.bufId = bufId; +} + +/** + * Function setup BUFC for CRYPTO. + * + * @details + * Function assumes that same buffer is used for input and output (in place). + * Additionally, it supports packet authentication&encryption where first part + * of the packet is only authenticated (CCM,GCM). + * + * @param pData + * Address of input-output buffer. + * + * @param authDataLen + * Length of authentication part. + * + * @warning + * Function is modifying CRYPTO_CTRL register by doing + * OR operation assuming that bit fields which are set have previously been + * cleared. It must be ensured that access to this register is done in + * correct order and settings are not overwritten. + */ +static void aesdrvBufcSetup(AESDRV_Context_t* pAesdrvContext, + uint8_t const* pData, + uint32_t authDataLength) +{ + uint8_t bufId = pAesdrvContext->ioModeSpecific.bufcConfig.bufId; + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + uint32_t ctrl; + + EFM_ASSERT(bufId != AESDRV_UTILS_BUFC_BUFFER_NOT_SET); + + /* Setup BUFC */ + BUFC->BUF[bufId].CTRL = BUFC_BUF_CTRL_SIZE_SIZE2048; + BUFC->BUF[bufId].ADDR = (uint32_t)pData; + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_CLEAR; + BUFC->BUF[bufId].WRITEOFFSET = 2048 + (authDataLength); + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_PREFETCH; + + ctrl = crypto->CTRL; + ctrl &= ~_CRYPTO_CTRL_READBUFSEL_MASK & ~_CRYPTO_CTRL_WRITEBUFSEL_MASK; + ctrl |= bufId << _CRYPTO_CTRL_READBUFSEL_SHIFT + | bufId << _CRYPTO_CTRL_WRITEBUFSEL_SHIFT; + crypto->CTRL = ctrl; +} +#endif + +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + +/***************************************************************************//** + * Function resets DMA settings for CRYPTO. + * + * @details + * Function clears trigger settings for channel setup to be used by CRYPTO. + * + ******************************************************************************/ +static void aesdrvDmaReset(AESDRV_Context_t* pAesdrvContext) +{ + AESDRV_DmaConfig_t* dmaConfig= &pAesdrvContext->ioModeSpecific.dmaConfig; + + if (dmaConfig->dmaChIn != AESDRV_UTILS_DMA_CHANNEL_NOT_SET) + { + DMADRV_FreeChannel(dmaConfig->dmaChIn); + } + + if (dmaConfig->dmaChOut != AESDRV_UTILS_DMA_CHANNEL_NOT_SET) + { + DMADRV_FreeChannel(dmaConfig->dmaChOut); + } + dmaConfig->dmaChIn = AESDRV_UTILS_DMA_CHANNEL_NOT_SET; + dmaConfig->dmaChOut = AESDRV_UTILS_DMA_CHANNEL_NOT_SET; +} + +/***************************************************************************//** + * Function initializes DMADRV for CRYPTO and allocates two channels. + * + * @details + * Function assumes that same buffer is used for input and output (in place). + * Additionally, it supports packet authentication&encryption where first part + * of the packet is only authenticated (CCM,GCM). + * + * @return + * OK when DMA channel allocation completed, OUT_OF_RESOURCES if not + * + ******************************************************************************/ +static Ecode_t aesdrvDmaInit( AESDRV_Context_t* pAesdrvContext ) +{ + Ecode_t retval; + AESDRV_DmaConfig_t* dmaConfig = &pAesdrvContext->ioModeSpecific.dmaConfig; + + retval = DMADRV_Init(); + if ( retval == ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED || + retval == ECODE_EMDRV_DMADRV_OK ) + { + retval = ECODE_OK; + } + else + { + return MBEDTLS_ECODE_AESDRV_OUT_OF_RESOURCES; + } + + // Allocate first DMA channel + retval = DMADRV_AllocateChannel(&dmaConfig->dmaChIn, NULL); + if ( retval != ECODE_EMDRV_DMADRV_OK ) + { + return MBEDTLS_ECODE_AESDRV_OUT_OF_RESOURCES; + } + // Allocate second DMA channel + retval = DMADRV_AllocateChannel(&dmaConfig->dmaChOut, NULL); + if ( retval != ECODE_EMDRV_DMADRV_OK ) { + DMADRV_FreeChannel(dmaConfig->dmaChIn); + dmaConfig->dmaChIn = AESDRV_UTILS_DMA_CHANNEL_NOT_SET; + return MBEDTLS_ECODE_AESDRV_OUT_OF_RESOURCES; + } + + return ECODE_OK; +} + +/** + * Function setup DMA for CRYPTO. + * + * @details + * Function assumes that same buffer is used for input and output (in place). + * Additionally, it supports packet authentication&encryption where first part + * of the packet is only authenticated (CCM,GCM). + * + * @param authDataLen + * Length of authentication part. + * + * @param textLength + * Length of encrypted part. + * + * @warning + * Function is modifying CRYPTO_SEQCTRL and CRYPTO_SEQCTRLB registers. It must + * be ensured that access to those registers is done in + * correct order and settings are not overwritten. + * + */ +static void aesdrvDmaSetup(AESDRV_Context_t* pAesdrvContext, + uint8_t const* pData, + uint32_t authDataLength, + uint32_t textLength) +{ + uint8_t * _authData = (uint8_t*)pData; + uint8_t * _textData = (uint8_t*)((uint32_t)pData + authDataLength); + CRYPTO_TypeDef* crypto = pAesdrvContext->cryptodrvContext.device->crypto; + AESDRV_DmaConfig_t* dmaConfig = &pAesdrvContext->ioModeSpecific.dmaConfig; + uint16_t lenIn, lenOut; + uint32_t seqctrl; + + /* Ensure that dma for crypto was initialized. */ + EFM_ASSERT((dmaConfig->dmaChIn != AESDRV_UTILS_DMA_CHANNEL_NOT_SET) && + (dmaConfig->dmaChOut != AESDRV_UTILS_DMA_CHANNEL_NOT_SET)); + + crypto->CTRL &= (~_CRYPTO_CTRL_DMA0RSEL_MASK) & (~_CRYPTO_CTRL_DMA1RSEL_MASK); + seqctrl = crypto->SEQCTRL; + seqctrl &= (~_CRYPTO_SEQCTRL_DMA0SKIP_MASK) & (~_CRYPTO_SEQCTRL_DMA0PRESA_MASK); + seqctrl |= (uint32_t)_authData % 4 << _CRYPTO_SEQCTRL_DMA0SKIP_SHIFT; + crypto->SEQCTRL = seqctrl; + crypto->SEQCTRLB |= CRYPTO_SEQCTRLB_DMA0PRESB; + aesdrvDmaAddrLenGet((uint8_t **)&_authData, + (uint8_t **)&_textData, + authDataLength, + textLength, + &lenIn, &lenOut); + + DMADRV_MemoryPeripheral( dmaConfig->dmaChIn, +#ifdef EMDRV_DMADRV_LDMA + pAesdrvContext->cryptodrvContext.device->dmaReqSigChIn, +#else +#error "UDMA + CRYPTO is a non-exisiting combination" +#endif + (void*)&crypto->DATA0, + (void *)_authData, + true, + lenIn / 4, + dmadrvDataSize4, + NULL, + NULL ); + + if (textLength) + { + DMADRV_PeripheralMemory( dmaConfig->dmaChOut, + pAesdrvContext->cryptodrvContext.device->dmaReqSigChOut, + (void *)_textData, + (void*)&crypto->DATA0, + true, + lenOut / 4, + dmadrvDataSize4, + NULL, + NULL ); + } +} + +/** + * Function calculates length transfers for reading to crypto and from crypto. + * + * @details + * Function takes into account address alignment for input and output buffer. + * It overwrites provided addresses applying alignment. + * + * @param pBufIn + * Address of input buffer. Will be modified by the function if not word + * aligned. + * + * @param pBufOut + * Address of output buffer. Will be modified by the function if not word + * aligned. + * + * @param lengthA + * Length of authentication part of CCM. + * @param lengthB + * Length of payload to be encrypted. + * @return + */ +static void aesdrvDmaAddrLenGet(uint8_t** pBufIn, + uint8_t** pBufOut, + uint16_t lengthA, + uint16_t lengthB, + uint16_t* dmaLengthIn, + uint16_t* dmaLengthOut) +{ + uint8_t* pIn = *pBufIn; + uint8_t* pOut = *pBufOut; + uint8_t moduloA = (uint32_t)pIn % 4; + uint8_t moduloB = (uint32_t)pOut % 4; + + *dmaLengthIn = lengthA+lengthB; + *dmaLengthOut = lengthB; + + pIn -= moduloA; + *dmaLengthIn += moduloA; + *dmaLengthIn = (*dmaLengthIn+3) & 0xFFFC; + + pOut -= moduloB; + *dmaLengthOut += moduloB; + *dmaLengthOut = (*dmaLengthOut+3) & 0xFFFC; + + *pBufIn = pIn; + *pBufOut = pOut; + + return; +} + +#endif /* #if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.h new file mode 100644 index 00000000000..b9fed8782bb --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_common_crypto.h @@ -0,0 +1,29 @@ +/* + * Common interface for AES based algorithms for the CRYPTO hw module. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __SILICON_LABS_AESDRV_COMMON_CRYPTO_H +#define __SILICON_LABS_AESDRV_COMMON_CRYPTO_H + +#include "aesdrv_internal.h" + +void AESDRV_HwIoSetup(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + uint32_t authDataLength, + uint32_t textLength); + +#endif /* __SILICON_LABS_AESDRV_COMMON_CRYPTO_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_internal.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_internal.h new file mode 100644 index 00000000000..1be9e56e982 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/aesdrv_internal.h @@ -0,0 +1,1276 @@ +/* + * Internal interface for AES based functions + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __SILICON_LABS_AESDRV_INTERNAL_H +#define __SILICON_LABS_AESDRV_INTERNAL_H + +#include "em_device.h" + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aesdrv.h" +#include "ecode.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * @brief + * Initialize an AESDRV context. + * + * @details + * This function initializes an AESDRV context structure to default values. + * In case of CRYPTO HW module use CRYPTO(0) as default device (for parts + * with multiple CRYPTO instances), and set data I/O mode to + * @ref aesdrvIoModeCore (i.e. core cpu moves data, not DMA or BUFC). + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_Init(AESDRV_Context_t* pAesdrvContext); + +/***************************************************************************//** + * @brief + * DeInitializes AESDRV context. + * + * @details + * This function deinitializes an AESDRV context by clearing the values and + * releasing the resources in use. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_DeInit(AESDRV_Context_t* pAesdrvContext); + +/***************************************************************************//** + * @brief + * Set the device instance of an AESDRV context. + * + * @details + * This function sets the AES/CRYPTO device instance of an AESDRV context. + * Subsequent calls to AESDRV API functions with this context will use the + * new AES/CRYPTO device instance. + * + * @param[in] pAesdrvContext + * AESDRV device context. + * + * @param[in] devno + * AES/CRYPTO hardware device instance to use. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_SetDeviceInstance(AESDRV_Context_t* pAesdrvContext, + unsigned int devno); + +/***************************************************************************//** + * @brief + * Set the I/O mode of an AESDRV context. + * + * @details + * This function sets the data I/O mode of an AESDRV context. + * + * @param[in] pAesdrvContext + * AESDRV device context. + * + * @param[in] ioMode + * I/O mode (Core CPU, DMA or BUFC). + * + * @param[in] ioModeSpecific + * I/O mode specific configuration @ref AESDRV_IoModeSpecific_t. + * + * @warning + * If BUFC is selected (@ref aesdrvIoModeBufc), this function does not enable + * the BUFC clock and does not do any global BUFC initialization. I.e. the + * user is responsible for performing BUFC initialization prior to calling + * this function. + * If DMA is selected (@ref aesdrvIoModeDma), this function performs full + * DMA driver initialization by calling DMADRV_Init (non-destructive) and + * allocates DMA channel resources to be used by AESDRV. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_SetIoMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_IoMode_t ioMode, + AESDRV_IoModeSpecific_t* ioModeSpecific + ); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) +/***************************************************************************//** + * @brief + * Setup the asynchronous mode of an AESDRV context. + * + * @details + * This function enables or disables asynchronous (non-blocking) mode of an + * AESDRV context. + * In order to enable, the user must set the @p pAsynchContext parameter to + * point to an asynchronous data context structure, and set the corresponding + * @p cipherMode. All subsequent calls to AESDRV API functions with the + * specified context will behave asynchronously, i.e. initiate the hardware + * to execute the operation and return as soon as possible. The user may + * specify a callback function by setting the @p asynchCallback parameter + * which will called when the operation has completed. + * In order to disable, the user must set the @p pAsynchContext parameter + * to NULL. All subsequent calls to AESDRV API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * @param[in] pAesdrvContext + * AESDRV device context. + * + * @param[in] cipherMode + * Cipher mode corresponding to the intended asynchronous operation. + * + * @param[in] pAsynchContext + * Pointer to an asynchronous context structure corresponding to the + * cipher mode specified by @p cipherMode, or NULL in order to disable + * asynchronous mode. In order to enable asynchronous mode, @p pAsynchContext + * must be one of + * @li @ref AESDRV_BlockCipherAsynchContext_t + * @li @ref AESDRV_CCM_AsynchContext_t + * @li @ref AESDRV_GCM_AsynchContext_t + * @li @ref AESDRV_CMAC_AsynchContext_t. + * For BLE optimized CCM @ref AESDRV_CCMBLE, use + * @ref AESDRV_CCM_AsynchContext_t. + * + * @param[in] asynchCallback + * If non-NULL, this function will operate in asynchronous mode by starting + * the AES operation and return immediately (non-blocking API). When the AES + * operation has completed, the ascynchCallback function will be called. + * If NULL, this function will operate in synchronous mode, and block until + * the AES operation has completed. + * + * @param[in] asynchCallbackArgument + * User defined parameter to be sent to callback function. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_SetAsynchMode +( + AESDRV_Context_t* pAesdrvContext, + AESDRV_CipherMode_t cipherMode, + void* pAsynchContext, + AESDRV_AsynchCallback_t asynchCallback, + void* asynchCallbackArgument + ); +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +/***************************************************************************//** + * @brief + * Set the AES encryption key. + * + * @details + * This functions sets up a 128 or 256 bit key to use for encryption and + * decryption in subsequent calls to AESDRV. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pKey + * Pointer to buffer including the AES key. + * + * @param[in] keyLength + * The length (in bytes) of the AES key. I.e. 16 bytes = 128 bits, + * 32 bytes = 256 bits key length. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_SetKey(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pKey, + uint32_t keyLength); + +/***************************************************************************//** + * @brief + * Generate 128 bit decryption key from 128 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[out] pKeyOut + * Buffer to place 128 bit decryption key. Must be at least 16 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] pKeyIn + * Buffer holding 128 bit encryption key. Must be at least 16 bytes long. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_DecryptKey128(AESDRV_Context_t* pAesdrvContext, + uint8_t* pKeyOut, + const uint8_t* pKeyIn); + +/***************************************************************************//** + * @brief + * Generate 256 bit decryption key from 256 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[out] pKeyOut + * Buffer to place 256 bit decryption key. Must be at least 32 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] pKeyIn + * Buffer holding 256 bit encryption key. Must be at least 32 bytes long. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_DecryptKey256(AESDRV_Context_t* pAesdrvContext, + uint8_t* pKeyOut, + const uint8_t* pKeyIn); + +/***************************************************************************//** + * @brief + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Plaintext Plaintext + * | | + * V V + * InitVector ->XOR +-------------->XOR + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * |----------+ | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | decryption | | | decryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * InitVector ->XOR +-------------->XOR + * | | + * V V + * Plaintext Plaintext + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with AESDRV_DecryptKey128(). + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CBC128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AESDRV_CBC128() for CBC figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with AESDRV_DecryptKey256(). + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CBC256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * Plaintext ->XOR | Plaintext ->XOR + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * XOR<- Ciphertext XOR<- Ciphertext + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key is used for both encryption and decryption modes. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AESDRV_CFB128() for CFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key is used for both encryption and decryption modes. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Counter (CTR) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] ctr + * 128 bit initial counter value. + * If supported by the device (currently only EFM32 AES hardware module) the + * user can point @p ctrCallback to a function which will be called after each + * AES block encoding in order to update the counter. + * + * @param[in] ctrCallback + * Callback function used to update counter value. + * Currently only supported by EFM32 AES hardware module. If NULL then + * AES_CTRUpdate32Bit from emlib will be used. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CTR128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback + ); + +/***************************************************************************//** + * @brief + * Counter (CTR) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_CTR128() for CTR figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] ctr + * 128 bit initial counter value. + * If supported by the device (currently only EFM32 AES hardware module) the + * user can point @p ctrCallback to a function which will be called after each + * AES block encoding in order to update the counter. + * + * @param[in] ctrCallback + * Callback function used to update counter value. + * Currently only supported by EFM32 AES hardware module. If NULL then + * AES_CTRUpdate32Bit from emlib will be used. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CTR256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* ctr, + AESDRV_CtrCallback_t ctrCallback + ); + +/***************************************************************************//** + * @brief + * Electronic Codebook (ECB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Plaintext Plaintext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | decryption | | decryption | + * +--------------+ +--------------+ + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with AESDRV_DecryptKey128(). + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_ECB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Electronic Codebook (ECB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AESDRV_ECB128() for ECB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with AESDRV_DecryptKey256(). + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_ECB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + bool encrypt + ); + +/***************************************************************************//** + * @brief + * Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_OFB128(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv + ); + +/***************************************************************************//** + * @brief + * Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_OFB128() for OFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] pAesdrvContext + * Pointer to AES block cipher context structure. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in,out] iv + * 128 bit initalization vector. The updated vector value for the last block + * is returned. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_OFB256(AESDRV_Context_t* pAesdrvContext, + uint8_t* out, + const uint8_t* in, + unsigned int len, + const uint8_t* key, + uint8_t* iv + ); + +/***************************************************************************//** + * @brief + * Computes the length of the MIC (Message Integrity Code) + * for a given security level, as defined in IEEE Std 802.15.4-2006 table 95. + * + * @details + * The two LSBs of securityLevel encodes a MIC length of 0, 4, 8, or 16. + * + * @param[in] securityLevel + * Security level to use. + * + * @return + * The length of the MIC for the given @p securityLevel + ******************************************************************************/ +uint8_t AESDRV_CCMStar_LengthOfMIC(uint8_t securityLevel); + +/***************************************************************************//** + * @brief + * CCM block cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * Please see http://en.wikipedia.org/wiki/CCM_mode for a general description + * of CCM. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pDataInput + * If @p encrypt is true, pDataInput is the 'P' (payload) parameter in CCM. + * I.e. the Payload data to encrypt. + * If @p encrypt is false, pDataInput is the 'C' (ciphertext) parameter in CCM. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pDataOutput + * If @p encrypt is true, pOututData is the 'C' (ciphertext) parameter in CCM. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pDataOutput is the 'P' (payload) parameter in CCM. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param[in] dataLength + * Length of data to be encrypted/decrypted, referred to as 'p' in CCM. + * Note that this does not include the length of the MIC which is specified + * with @p authTagLength. + * + * @param[in] pHdr + * The 'A' parameter in CCM. + * Header is used for MIC calculation. + * Must be at least @p hdrLength long. + * + * @param[in] hdrLength + * The 'a' parameter in CCM. + * Length of header. + * + * @param[in] pKey + * The 'K' parameter in CCM. + * Pointer to security key. + * Currently only 128 bit keys (16 bytes) are supported. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] pNonce + * The 'N' parameter in CCM. + * Pointer to the nonce, which must have length 15-authTagLength + * See @p authTagLength + * + * @param[in] nonceLength + * The length in bytes, of the @p pNonce, i.e. the 'N' parameter in CCM. + * Currently only nonce size equal to 13 bytes is supported. + * + * @param[in/out] pAuthTag + * The 'MIC' parameter in CCM. + * Pointer to the MIC buffer, which must have length @p authTagLength. + * + * @param[in] authTagLength + * The 't' parameter in CCM. + * The number of bytes used for the authentication tag. + * Possible values are 0, 4, 6, 8, 10, 12, 14, 16. + * Note that 0 is not a legal value in CCM, but is used for CCM*. + * + * @param[in] encrypt + * Set to true to run the generation-encryption process, + * false to run the decryption-verification process. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CCM(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt + ); + +/***************************************************************************//** + * @brief + * CCM* block cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * Please see IEEE Std 802.15.4-2006 Annex B for a description of CCM*. + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pDataInput + * If @p encrypt is true, pDataInput is the plaintext. + * I.e. the payload data to encrypt. + * If @p encrypt is false, pDataInput is the ciphertext. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pDataOutput + * If @p encrypt is true, pDataOutput is the ciphertext. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pDataOutput is the plaintext. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param[in] dataLength + * Length of data to be encrypted/decrypted, referred to as l(m) in CCM*. + * Note that this does not include the length of the MIC, + * so for decryption there are + * l(c) = @p dataLength + CCM_LengthOfMIC(securityLevel) + * bytes available in the buffer. + * + * @param[in] pHdr + * The 'a' parameter in CCM*. + * Header is used for MIC calculation. + * Must be at least @p hdrLength long. + * + * @param[in] hdrLength + * Length of header. + * Referred to as l(a) in CCM* + * + * @param[in] pKey + * The 'K' parameter in CCM*. + * Pointer to security key. + * Currently only 128 bit keys (16 bytes) are supported. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM*. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] pNonce + * The 'N' parameter in CCM. + * Pointer to the nonce, which has length 13 bytes. + * + * @param[in] nonceLength + * The length in bytes, of the @p pNonce, i.e. the 'N' parameter in CCM*. + * + * @param[in/out] pAuthTag + * The 'MIC' parameter in CCM. + * Pointer to the MIC buffer, which must have length @p authTagLength. + * + * @param[in] securityLevel + * Security level to use. See table 95 in IEEE Std 802.15.4-2006 + * See also function CCM_LengthOfMIC + * Level 0: No encryption, no authentication + * Level 1: No encryption, M=4 bytes authentication tag + * Level 2: No encryption, M=8 bytes authentication tag + * Level 3: No encryption, M=16 bytes authentication tag + * Level 4: Encryption, no authentication + * Level 5: Encryption, M=4 bytes authentication tag + * Level 6: Encryption, M=8 bytes authentication tag + * Level 7: Encryption, M=16 bytes authentication tag + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_CCMStar(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pNonce, + const uint32_t nonceLength, + uint8_t* pAuthTag, + const uint8_t securityLevel, + const bool encrypt + ); + +/***************************************************************************//** + * @brief + * CCM optimized for BLE + * + * @details + * This function is an implementation of CCM optimized for Bluetooth Low Energy + * (BLE). This function assumes fixed header size (1 byte), + * fixed authentication tag (4bytes), fixed length field size (2 bytes) + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param pData + * Pointer to data + * + * @param dataLength + * length of data (max. 27) + * + * @param hdr + * 1 byte header + * + * @param pKey + * Pointer to 128 bits (16 byte) Security Key. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will used. The key can be explicitly set with + * @ref AESDRV_SetKey. + * + * @param pNonce + * 13 byte nonce + * + * @param[in/out] pAuthTag + * The 'MIC' parameter in CCM. + * Pointer to the MIC buffer, which must have length of 4 bytes. + * + * @param encrypt + * true - encrypt + * false - decrypt + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + */ +Ecode_t AESDRV_CCMBLE(AESDRV_Context_t* pAesdrvContext, + uint8_t* pData, + const uint32_t dataLength, + uint8_t hdr, + const uint8_t* pKey, + const uint8_t* pNonce, + uint8_t* pAuthTag, + const bool encrypt + ); + +/***************************************************************************//** + * @brief + * GCM block cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * This function implements GCM (Galois Counter Mode) block cipher mode + * encryption and decryption based on 128 bit AES. + * This function expects that pHdr and pData are consecutive. + * For a general description please see + * http://en.wikipedia.org/wiki/Galois/Counter_Mode + * or for detailed specification see + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pDataInput + * If @p encrypt is true, pDataInput is the plaintext. + * I.e. the payload data to encrypt. + * If @p encrypt is false, pDataInput is the ciphertext. + * I.e. the ciphertext data to decrypt. + * + * @param[out] pDataOutput + * If @p encrypt is true, pDataOutput is the ciphertext. + * I.e. the Ciphertext data as a result of encrypting the payload data. + * If @p encrypt is false, pDataOutput is the plaintext. + * I.e. the Payload data as a result of decrypting the ciphertext. + * + * @param[in] dataLength + * Length of plaintext to be encrypted, referred to as 'n' in GCM. + * Note that this does not include the length of the MIC, + * + * @param[in] pHdr + * The 'A' parameter in GCM. + * Header is used for MIC calculation. + * Must be @p hdrLength long. + * + * @param[in] hdrLength + * The 'm' parameter in GCM. + * Length of authentication data. + * + * @param[in] pKey + * The 'K' parameter in GCM. + * Pointer to security key buffer. + * Currently only 128 bit keys (16 bytes) are supported. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will be used. The key can be set explicitly with + * @ref AESDRV_SetKey. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in] pInitialVector + * The 'IV' parameter in GCM. + * Pointer to the initial vector, which must have length 12 bytes (=96 bits + * which is recommended by GCM for efficiency). + * + * @param[in/out] pAuthTag + * The 'MIC' parameter in CCM. + * Pointer to the MIC buffer, which must have length @p authTagLength. + * + * @param[in] authTagLength + * Length of authentication tag 0-16 bytes. + * + * @param[in] encrypt + * Set to true to run the generation-encryption process, + * false to run the decryption-verification process. + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + ******************************************************************************/ +Ecode_t AESDRV_GCM(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pDataInput, + uint8_t* pDataOutput, + const uint32_t dataLength, + const uint8_t* pHdr, + const uint32_t hdrLength, + const uint8_t* pKey, + const uint32_t keyLength, + const uint8_t* pInitialVector, + const uint32_t initialVectorLength, + uint8_t* pAuthTag, + const uint8_t authTagLength, + const bool encrypt); + +/***************************************************************************//** + * @brief + * CMAC cipher mode encryption/decryption based on 128 bit AES. + * + * @details + * This function implements CMAC (Cipher-based Message Authentication Code) + * cipher mode encryption/decryption based on 128 bit AES. + * For a general description please see + * https://en.wikipedia.org/wiki/CMAC + * or for detailed specification see + * http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf + * http://dl.acm.org/citation.cfm?id=2206249 + * + * @param[in] pAesdrvContext + * Pointer to AESDRV context structure. + * + * @param[in] pData + * Pointer to data (message) Be careful: this memory should be allocated on + * block-size (128-bit) boundaries! + * + * @param[in] dataLengthBits + * length of actual data in bits + * + * @param[in] pKey + * Pointer to key buffer for the AES algorithm. + * Currently only 128 bit keys (16 bytes) are supported. + * On devices supporting key buffering this argument can be NULL, and if so, + * the current key will used. The key can be explicitly set with + * @ref AESDRV_SetKey. + * + * @param[in] keyLength + * The length in bytes, of the @p pKey, i.e. the 'K' parameter in CCM. + * Currently only 128 bit keys (16 bytes) are supported. + * + * @param[in/out] pDigest + * 128-bit (maximum) digest. If encrypting, the digest will be stored there. + * If verifying, the calculated digest will be compared to the one stored in + * this place. + * Warning: regardless of digestLengthBits, 128 bits will get written here. + * + * @param[in] digestLengthBits + * Requested length of the message digest in bits. LSB's will be zeroed out. + * + * @param[in] encrypt + * true - Generate hash + * false - Verify hash + * + * @return + * ECODE_OK if success. Error code if failure, see @ref aesdrv.h. + */ +Ecode_t AESDRV_CMAC(AESDRV_Context_t* pAesdrvContext, + const uint8_t* pData, + uint32_t dataLengthBits, + const uint8_t* pKey, + const uint32_t keyLength, + uint8_t* pDigest, + uint16_t digestLengthBits, + const bool encrypt + ); + +#ifdef __cplusplus +} +#endif + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ + +#endif /* __SILICON_LABS_AESDRV_INTERNAL_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv.c new file mode 100644 index 00000000000..42069392fdc --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv.c @@ -0,0 +1,669 @@ +/* + * CRYPTO driver implementation including CRYPTO preemption and asynchronous + * (non-blocking) support. + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cryptodrv_internal.h" +#include "em_crypto.h" +#include "em_assert.h" +#include "em_core.h" +#include +#include +#include +#include +#if defined( CRYPTODRV_PAL_FREERTOS ) +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#define CRYPTO_IRQn_PRIORITY (configMAX_SYSCALL_INTERRUPT_PRIORITY-1) +#endif + +/******************************************************************************* + ******************************** MACROS *********************************** + ******************************************************************************/ +#if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) + +#define CRYPTODRV_CLOCK_ENABLE(clk) CMU->HFBUSCLKEN0 |= clk +#define CRYPTODRV_CLOCK_DISABLE(clk) CMU->HFBUSCLKEN0 &= ~(clk) + +#define RUNNING_AT_INTERRUPT_LEVEL (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) + +#if defined( _EFR32_MIGHTY_FAMILY ) || defined( _EFM32_PEARL_FAMILY ) +#define MAX_NVIC_ISER (2) /* FPUEH_IRQn = 33 is the highest IRQn + and all IRQns fits inside 2 ISERs + ISER[0] and ISER[1]. */ +#elif defined( _EFM32_JADE_FAMILY ) +#define MAX_NVIC_ISER (1) /* CRYOTIMER_IRQn = 31 is the highest IRQn + and all IRQns fits inside one ISER[0]. */ +#else +#error Device not supported. +#endif + +#endif /* #if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) */ + +/******************************************************************************* + ******************************** STATICS ********************************** + ******************************************************************************/ + +#if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) +/* Pointer to current owner context of the CRYPTO unit. The @ref cryptoOwner + pointer serves as the anchor to a double linked list of all current "active" + CRYPTODRV contexts. The @ref CRYPTODRV_Arbitrate function adds a new owner + if ownership is won, and CRYPTODRV_Release removes a context that is done.*/ +static struct CRYPTODRV_Context_t* cryptoOwner[CRYPTO_COUNT] = + { + NULL +#if CRYPTO_COUNT==2 + , NULL +#endif + }; + +/* Flag which indicates whether a CRYPTO critical region is active. */ +static uint32_t nvicIser[CRYPTO_COUNT][MAX_NVIC_ISER]; + +#endif + +/* CRYPTO device instance structures. */ +static const CRYPTO_Device_t cryptoDevice[CRYPTO_COUNT] = +{ +#if defined( CRYPTO0 ) + { + CRYPTO0, + CRYPTO0_IRQn, + CMU_HFBUSCLKEN0_CRYPTO0 +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) + , + (void*)&cryptoOwner[0], + nvicIser[0] +#endif +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + , + dmadrvPeripheralSignal_CRYPTO0_DATA0WR, + dmadrvPeripheralSignal_CRYPTO0_DATA0RD +#endif + } +#elif defined( CRYPTO ) + { + CRYPTO, + CRYPTO_IRQn, + CMU_HFBUSCLKEN0_CRYPTO +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) + , + (void*)&cryptoOwner[0], + nvicIser[0] +#endif +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + , + dmadrvPeripheralSignal_CRYPTO_DATA0WR, + dmadrvPeripheralSignal_CRYPTO_DATA0RD +#endif + } +#endif +#if defined( CRYPTO1 ) + , + { + CRYPTO1, + CRYPTO1_IRQn, + CMU_HFBUSCLKEN0_CRYPTO1 +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) + , + (void*)&cryptoOwner[1], + nvicIser[1] +#endif +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + , + dmadrvPeripheralSignal_CRYPTO1_DATA0WR, + dmadrvPeripheralSignal_CRYPTO1_DATA0RD +#endif + } +#endif +}; + +#if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) + +#if defined( CRYPTODRV_PAL_FREERTOS ) + +#define CRYPTODRV_PAL_THREADS_LOCK \ + if (false == RUNNING_AT_INTERRUPT_LEVEL) \ + vTaskSuspendAll(); +#define CRYPTODRV_PAL_THREADS_UNLOCK \ + if (false == RUNNING_AT_INTERRUPT_LEVEL) \ + xTaskResumeAll(); + +#define CRYPTODRV_PAL_THREAD_ID_GET (void*)xTaskGetCurrentTaskHandle() + +#define CRYPTODRV_PAL_THREAD_PRIORITY_GET \ + ((unsigned long)uxTaskPriorityGet(NULL)) + +#define CRYPTODRV_PAL_THREAD_RESUME(threadId) \ + xTaskResumeFromISR((TaskHandle_t)threadId) + +#define CRYPTODRV_PAL_WAIT_FOR_OWNERSHIP(pCryptodrvContext) \ + cryptodrvPalWaitForOwnership(pCryptodrvContext) + +__STATIC_INLINE void cryptodrvPalWaitForOwnership(CRYPTODRV_Context_t* pCryptodrvContext) +{ + CRYPTODRV_Context_t** pCryptoOwner = + (CRYPTODRV_Context_t**) pCryptodrvContext->device->pCryptoOwner; + while (pCryptodrvContext != *pCryptoOwner) + { + vTaskSuspend(xTaskGetCurrentTaskHandle()); + } +} + +#else /* #if defined( CRYPTODRV_PAL_FREERTOS ) */ + +#define CRYPTODRV_PAL_THREADS_LOCK +#define CRYPTODRV_PAL_THREADS_UNLOCK +#define CRYPTODRV_PAL_THREAD_ID_GET (0) +#define CRYPTODRV_PAL_THREAD_PRIORITY_GET (RUNNING_AT_INTERRUPT_LEVEL ? 1 : 0) +#define CRYPTODRV_PAL_THREAD_RESUME(threadId) +#define CRYPTODRV_PAL_WAIT_FOR_OWNERSHIP(pCryptodrvContext) + +#endif /* #if defined( CRYPTODRV_PAL_FREERTOS ) */ + +#endif /* #if defined(MBEDTLS_CRYPTO_DEVICE_PREEMPTION) */ + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) +/* Current callback function called from CRYPTO_IRQHandler. */ +static CRYPTODRV_AsynchCallback_t cryptoDrvAsynchCallback = 0; +static void* cryptoDrvAsynchCallbackArgument; +#endif + +/******************************************************************************* + ****************************** FUNCTIONS ********************************** + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Select which CRYPTO device instance to use in CRYPTO context. + * + * @param pCryptoContext + * Pointer to CRYPTO context. + * + * @param devno + * CRYPTO device instance number. + * + * @return + * 0 if OK, or -1 if device number is invalid. + ******************************************************************************/ +int cryptodrvSetDeviceInstance(CRYPTODRV_Context_t* pCryptodrvContext, + unsigned int devno) +{ + if (devno > CRYPTO_COUNT) + return( -1 ); + + pCryptodrvContext->device = &cryptoDevice[devno]; + return( 0 ); +} + +#if defined MBEDTLS_CRYPTO_DEVICE_PREEMPTION + +/***************************************************************************//** + * @brief + * Check state of a CRYPTO device instance. + * + * @details + * Checks if a CRYPTO device is idle and ready for new operation, or busy + * running an ongoing operation. + * + * @return + * MBEDTLS_ECODE_CRYPTODRV_BUSY if CRYPTO is busy running an ongoing operation. + * ECODE_OK if idle and ready for new operation. + ******************************************************************************/ +Ecode_t CRYPTODRV_CheckState( unsigned int devno ) +{ + /* The 'cryptoOwner' pointer indicates whether someone is already running a + CRYPTO operation. */ + return cryptoOwner[devno] ? MBEDTLS_ECODE_CRYPTODRV_BUSY : ECODE_OK; +} + +/***************************************************************************//** + * @brief + * Arbitrate for exclusive access to CRYPTO unit. + * + * @details + * This function will arbitrate for the ownership of the CRYPTO unit in order + * to execute CRYPTO operations. If the ownership is won and there is an + * ongoing CRYPTO operation, this function will preempt the ongoing operation + * by storing the full CRYPTODRV context inlcuding hardware context + * (register values) of the CRYPTO unit. When the caller is ready to release + * CRYPTO, the caller should call CRYPTODRV_Release in + * order to restore the context of the ongoing operation, in order for that to + * continue operation. The function call of the ongoing operation may try to + * restore and continue after the abort event, but may fail and return + * MBEDTLS_ECODE_CRYPTODRV_OPERATION_ABORTED. + * This function may be called from an interrupt handler in order to perform + * time critical CRYPTO operations. + * + * @param pCryptodrvContext + * Pointer to CRYPTODRV context which should be used in subsequent calls, + * like @ref CRYPTODRV_Release. + * + * @return + * MBEDTLS_ECODE_CRYPTODRV_OK if success. Error code if failure. + * MBEDTLS_ECODE_CRYPTODRV_BUSY if priority is lower than or equal to the + * pririty of the running thread. + */ +Ecode_t CRYPTODRV_Arbitrate (CRYPTODRV_Context_t* pCryptodrvContext) +{ + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; + CRYPTODRV_Context_t** pCryptoOwner = + (CRYPTODRV_Context_t**) pCryptodrvContext->device->pCryptoOwner; + CRYPTODRV_Context_t* cryptoOwner; + Ecode_t retval = ECODE_OK; + CORE_DECLARE_IRQ_STATE; + + CORE_ENTER_CRITICAL(); + CRYPTODRV_PAL_THREADS_LOCK; + + cryptoOwner = *pCryptoOwner; + + /* Check if someone is already running a CRYPTO operation. */ + if (cryptoOwner) + { + if (CRYPTODRV_PAL_THREAD_PRIORITY_GET <= cryptoOwner->threadPriority) + { + retval = MBEDTLS_ECODE_CRYPTODRV_BUSY; + } + else + { + CRYPTO_Context_t* pCryptoContext; + uint8_t* pExecCmd; + + /* We are running an ISR or thread of higher priority than the + current crypto owner. If crypto is running, stop it and mark + context as aborted. */ + if (crypto->STATUS + & (CRYPTO_STATUS_INSTRRUNNING | CRYPTO_STATUS_SEQRUNNING)) + { + crypto->CMD = CRYPTO_CMD_SEQSTOP; + cryptoOwner->aborted = true; + } + else + { + cryptoOwner->aborted = false; + } + + cryptoOwner->pContextPreemptor = pCryptodrvContext; + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + /* Store the asynch callback state */ + cryptoOwner->asynchCallback = cryptoDrvAsynchCallback; + cryptoOwner->asynchCallbackArgument = cryptoDrvAsynchCallbackArgument; +#endif + + /* Store the hardware state */ + pCryptoContext = &cryptoOwner->cryptoContext; + + pCryptoContext->CTRL = crypto->CTRL; + pCryptoContext->WAC = crypto->WAC; + pCryptoContext->SEQCTRL = crypto->SEQCTRL; + pCryptoContext->SEQCTRLB = crypto->SEQCTRLB; + pCryptoContext->IEN = crypto->IEN; + pCryptoContext->SEQ[0] = crypto->SEQ0; + pCryptoContext->SEQ[1] = crypto->SEQ1; + pCryptoContext->SEQ[2] = crypto->SEQ2; + pCryptoContext->SEQ[3] = crypto->SEQ3; + pCryptoContext->SEQ[4] = crypto->SEQ4; + + /* Search for possible EXEC commands and replace with END. */ + pExecCmd = (uint8_t*) memchr(&pCryptoContext->SEQ, + CRYPTO_CMD_INSTR_EXEC, + sizeof(pCryptoContext->SEQ)); + if (pExecCmd) + { + memset(pExecCmd, + (uint8_t) CRYPTO_CMD_INSTR_END, + sizeof(pCryptoContext->SEQ) - + ((uint32_t)pExecCmd-(uint32_t)&pCryptoContext->SEQ)); + } + CRYPTO_DDataRead(&crypto->DDATA0, pCryptoContext->DDATA[0]); + CRYPTO_DDataRead(&crypto->DDATA1, pCryptoContext->DDATA[1]); + CRYPTO_DDataRead(&crypto->DDATA2, pCryptoContext->DDATA[2]); + CRYPTO_DDataRead(&crypto->DDATA3, pCryptoContext->DDATA[3]); + CRYPTO_DDataRead(&crypto->DDATA4, pCryptoContext->DDATA[4]); + + retval = ECODE_OK; + } + } + else + { + CRYPTODRV_CLOCK_ENABLE(pCryptodrvContext->device->clk); + } + + if (ECODE_OK == retval) + { + pCryptodrvContext->pContextPreempted = cryptoOwner; + *pCryptoOwner = pCryptodrvContext; + pCryptodrvContext->pContextPreemptor = 0; + pCryptodrvContext->aborted = false; + pCryptodrvContext->threadPriority = CRYPTODRV_PAL_THREAD_PRIORITY_GET; + pCryptodrvContext->threadId = CRYPTODRV_PAL_THREAD_ID_GET; + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + CRYPTODRV_SetAsynchCallback(pCryptodrvContext, 0, 0); +#endif + } + + CRYPTODRV_PAL_THREADS_UNLOCK; + CORE_EXIT_CRITICAL(); + + return retval; +} + +/***************************************************************************//** + * @brief + * Release a CRYPTODRV context and possibly ownership of CRYPTO unit. + * + * @details + * This function removes a CRYPTODRV context from the CRYPTODRV context list + * (which includes current owner and preempted contexts). + * If the specified context is the owner of the CRYPTO unit, this function + * will release the ownership of the CRYPTO unit. If there is a preempted + * context in the context list, then the preempted context is restored + * by updating the hardware state of the CRYPTO unit. + * + * @param pCryptodrvContext + * The CRYPTODRV context to remove from CRYPTODRV context list. + * + * @return + * MBEDTLS_ECODE_CRYPTODRV_OK if success. Error code if failure. + */ +Ecode_t CRYPTODRV_Release (CRYPTODRV_Context_t* pCryptodrvContext) +{ + CRYPTODRV_Context_t* preempted = + (CRYPTODRV_Context_t*) pCryptodrvContext->pContextPreempted; + CRYPTODRV_Context_t* preemptor = + (CRYPTODRV_Context_t*) pCryptodrvContext->pContextPreemptor; + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; + CRYPTODRV_Context_t** pCryptoOwner = + (CRYPTODRV_Context_t**) pCryptodrvContext->device->pCryptoOwner; + CRYPTODRV_Context_t* cryptoOwner; + CORE_DECLARE_IRQ_STATE; + + CORE_ENTER_CRITICAL(); + CRYPTODRV_PAL_THREADS_LOCK; + + if ( (0==preempted) && (0==preemptor)) + { + *pCryptoOwner = NULL; + CRYPTODRV_CLOCK_DISABLE(pCryptodrvContext->device->clk); + } + else + { + cryptoOwner = *pCryptoOwner; + + /* If _this_ context was preempted, and the preemptor is still running, + then inform the preemptor that _this_ context is not valid any more + by linking to _this_ preempted context (which may be NULL). */ + if (preemptor) + { + preemptor->pContextPreempted = preempted; + } + + if (preempted) + { + /* Remove _this_ context from preemption list (double linked) by + replacing preempted preemptor (_this_) with preemptor of _this_ + context (may be NULL if _this_ is owner of crypto). */ + preempted->pContextPreemptor = preemptor; + + /* If _this_ conxtext is the owner of crypto, restore preempted + context and set it to owner. */ + if (cryptoOwner == pCryptodrvContext) + { + CRYPTO_Context_t* pCryptoContext = &preempted->cryptoContext; + + crypto->CTRL = pCryptoContext->CTRL; + crypto->WAC = pCryptoContext->WAC; + crypto->SEQCTRL = pCryptoContext->SEQCTRL; + crypto->SEQCTRLB = pCryptoContext->SEQCTRLB; + crypto->IEN = pCryptoContext->IEN; + crypto->SEQ0 = pCryptoContext->SEQ[0]; + crypto->SEQ1 = pCryptoContext->SEQ[1]; + crypto->SEQ2 = pCryptoContext->SEQ[2]; + crypto->SEQ3 = pCryptoContext->SEQ[3]; + crypto->SEQ4 = pCryptoContext->SEQ[4]; + CRYPTO_DDataWrite(&crypto->DDATA0, pCryptoContext->DDATA[0]); + CRYPTO_DDataWrite(&crypto->DDATA1, pCryptoContext->DDATA[1]); + CRYPTO_DDataWrite(&crypto->DDATA2, pCryptoContext->DDATA[2]); + CRYPTO_DDataWrite(&crypto->DDATA3, pCryptoContext->DDATA[3]); + CRYPTO_DDataWrite(&crypto->DDATA4, pCryptoContext->DDATA[4]); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + CRYPTODRV_SetAsynchCallback(pCryptodrvContext, + preempted->asynchCallback, + preempted->asynchCallbackArgument); +#endif + + cryptoOwner = *pCryptoOwner = preempted; + /* Resume new owner task (which may be suspended by now). */ + CRYPTODRV_PAL_THREAD_RESUME(cryptoOwner->threadId); + } + } + } + + CRYPTODRV_PAL_THREADS_UNLOCK; + CORE_EXIT_CRITICAL(); + + return ECODE_OK; +} + +#if !defined( MBEDTLS_CRYPTO_CRITICAL_REGION_ALT ) + +/***************************************************************************//** + * @brief + * Enter a critical CRYPTO region. + * + * @details + * This function enters a critical region of a CRYPTO operation by disabling + * all interrupts, except the CRYPTO interrupt. If a thread which is not the + * owner of CRYPTO tries to enter the critical region, it will be suspended. + * The thread will be resumed when the preemptor calls CRYPTODRV_Release. + * + * @return + * ECODE_OK +*/ +Ecode_t CRYPTODRV_EnterCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext) +{ + int i; + IRQn_Type irqn = pCryptodrvContext->device->irqn; + uint32_t* pNvicIser = pCryptodrvContext->device->pNvicIser; + CORE_DECLARE_IRQ_STATE; + + CRYPTODRV_PAL_WAIT_FOR_OWNERSHIP(pCryptodrvContext); + + CORE_ENTER_CRITICAL(); + CRYPTODRV_PAL_THREADS_LOCK; + + /* Disable all interrupts except the CRYPTO IRQ. Remember which interrupts + that was enabled in order to enable them when exiting the critical + region. */ + for (i=0; iISER[i]; + NVIC->ICER[i] = pNvicIser[i]; + } + NVIC->ISER[(uint32_t)((int32_t)irqn) >> 5] = + (uint32_t)(1 << ((uint32_t)((int32_t)irqn) & (uint32_t)0x1F)); + + CRYPTODRV_PAL_THREADS_UNLOCK; + CORE_EXIT_CRITICAL(); + + return ECODE_OK; +} + +/***************************************************************************//** + * @brief + * Exit a critical CRYPTO region. + * + * @details + * This function exits a critical region of a CRYPTO operation. + * This function will enable all interrupts that was enabled when the initial + * nested critical region was entered. + * + * @return + * ECODE_OK + */ +Ecode_t CRYPTODRV_ExitCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext) +{ + int i; + (void) pCryptodrvContext; /* remove compiler warning when pCryptodrvContext + is not used.*/ + uint32_t* pNvicIser = pCryptodrvContext->device->pNvicIser; + CORE_DECLARE_IRQ_STATE; + + CORE_ENTER_CRITICAL(); + CRYPTODRV_PAL_THREADS_LOCK; + + /* Enable all interrupts that was enabled when entering the critical + region. */ + for (i=0; iISER[i] |= pNvicIser[i]; + } + + CRYPTODRV_PAL_THREADS_UNLOCK; + CORE_EXIT_CRITICAL(); + + return ECODE_OK; +} + +#endif /* #if !defined( MBEDTLS_CRYPTO_CRITICAL_REGION_ALT ) */ + +#endif /* #if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) */ + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * Set asynchronous callback to be called when crypto operations complete. + * + * @details + * This function sets the asynchronous callback function to be called when + * crypto operations complete. This function should be called inside _the_ + * critical region of an asynchronous operation. + * + * @return + * N/A + */ +void CRYPTODRV_SetAsynchCallback +( + CRYPTODRV_Context_t* pCryptodrvContext, + CRYPTODRV_AsynchCallback_t asynchCallback, + void* callbackArgument + ) +{ + CRYPTO_TypeDef* crypto = pCryptodrvContext->device->crypto; + IRQn_Type irqn = pCryptodrvContext->device->irqn; + if (asynchCallback) + { + cryptoDrvAsynchCallback = asynchCallback; + cryptoDrvAsynchCallbackArgument = callbackArgument; + crypto->IFC = _CRYPTO_IFC_MASK; + crypto->IEN = CRYPTO_IEN_SEQDONE; + NVIC_ClearPendingIRQ(irqn); + NVIC_EnableIRQ(irqn); +#if defined( CRYPTODRV_PAL_FREERTOS ) + /* Set priority below the configured maximum system call priority */ + NVIC_SetPriority(irqn, CRYPTO_IRQn_PRIORITY); +#endif + } + else + { + cryptoDrvAsynchCallback = 0; + crypto->IEN = 0; + crypto->IFC = _CRYPTO_IFC_MASK; + NVIC_DisableIRQ(irqn); + } +} + +/***************************************************************************//** + * @brief + * Interrupt service routine for CRYPTO module instances. + * + * @details + * CRYPTO_IRQHandler, CRYPTO0_IRQHandler, etc are the first functions to be + * called when an interrupt from the respective CRYPTO instance is being + * serviced by the MCU. The function cryptoIrqHandlerGeneric is called with + * a pointer to the respective CRYPTO unit, and it will clear the interrupt + * and call the interrupt service routine associated with the operation that + * caused the interrupt. The operation specific ISR must be registered by + * calling @ref CRYPTODRV_SetAsynchCallback before the operation is started. + * + * @return + * N/A + */ +void cryptoIrqHandlerGeneric( const CRYPTO_Device_t* cryptoDevice ) +{ + CRYPTO_TypeDef* crypto = cryptoDevice->crypto; + uint32_t flags = crypto->IF; + + while (flags) + { + crypto->IFC = flags; + NVIC_ClearPendingIRQ(cryptoDevice->irqn); + + if (flags & CRYPTO_IF_SEQDONE) + { + if (cryptoDrvAsynchCallback) + { + cryptoDrvAsynchCallback (cryptoDrvAsynchCallbackArgument); + } + } + if (CMU->HFBUSCLKEN0 & cryptoDevice->clk) + flags = crypto->IF; + else + flags = 0; + } +} + +#if defined(CRYPTO) +void CRYPTO_IRQHandler(void) +{ + cryptoIrqHandlerGeneric( &cryptoDevice[0] ); +} +#endif + +#if defined(CRYPTO0) +void CRYPTO0_IRQHandler(void) +{ + cryptoIrqHandlerGeneric( &cryptoDevice[0] ); +} +#endif + +#if defined(CRYPTO1) +void CRYPTO1_IRQHandler(void) +{ + cryptoIrqHandlerGeneric( &cryptoDevice[1] ); +} +#endif + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv_internal.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv_internal.h new file mode 100644 index 00000000000..8d80bdcc4d2 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/cryptodrv_internal.h @@ -0,0 +1,337 @@ +/* + * CRYPTO driver internal definitions including CRYPTO preemption and + * asynchronous (non-blocking) support. + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __SILICON_LABS_CRYPTODRV_INTERNAL_H +#define __SILICON_LABS_CRYPTODRV_INTERNAL_H + +#include "em_device.h" + +#if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cryptodrv.h" +#include "ecode.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + ****************************** Functions ********************************** + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Select which CRYPTO device instance to use in CRYPTO context. + * + * @param pCryptoContext + * Pointer to CRYPTO context. + * + * @param devno + * CRYPTO device instance number. + * + * @return + * 0 if OK, or -1 if device number is invalid. + ******************************************************************************/ +int cryptodrvSetDeviceInstance(CRYPTODRV_Context_t* pCryptodrvContext, + unsigned int devno); + +/***************************************************************************//** + * @brief + * Write a 128 bit value (optionally unaligned) into a crypto register. + * + * @note + * This function provide a low-level api for writing to the multi-word + * registers in the crypto peripheral. Applications should prefer to use + * @ref CRYPTO_DataWrite, @ref CRYPTO_DDataWrite or @ref CRYPTO_QDataWrite + * for writing to the DATA, DDATA and QDATA registers. + * + * @param[in] reg + * Pointer to the crypto register. + * + * @param[in] val + * This is a pointer to 4 32 bit integers that contains the 128 bit value + * which will be written to the crypto register. + ******************************************************************************/ +__STATIC_INLINE void CRYPTODRV_DataWriteUnaligned(volatile uint32_t * reg, + const uint8_t * val) +{ + /* Check data is 32bit aligned, if not move to temporary buffer before + writing.*/ + if ((uint32_t)val & 0x3) + { + uint32_t temp[4]; + memcpy(temp, val, 16); + CRYPTO_DataWrite(reg, temp); + } + else + { + CRYPTO_DataWrite(reg, (uint32_t*)val); + } +} + +/***************************************************************************//** + * @brief + * Read a 128 bit value from a crypto register into optionally unaligned + * buffer. + * + * @note + * This function provide a low-level api for reading one of the multi-word + * registers in the crypto peripheral. Applications should prefer to use + * @ref CRYPTO_DataRead, @ref CRYPTO_DDataRead or @ref CRYPTO_QDataRead + * for reading the value of the DATA, DDATA and QDATA registers. + * + * @param[in] reg + * Pointer to the crypto register. + * + * @param[out] val + * This is a pointer to an array that is capable of holding 4 32 bit integers + * that will be filled with the 128 bit value from the crypto register. + ******************************************************************************/ +__STATIC_INLINE void CRYPTODRV_DataReadUnaligned(volatile uint32_t * reg, + uint8_t * val) +{ + /* Check data is 32bit aligned, if not, read into temporary buffer and + then move to user buffer. */ + if ((uint32_t)val & 0x3) + { + uint32_t temp[4]; + CRYPTO_DataRead(reg, temp); + memcpy(val, temp, 16); + } + else + { + CRYPTO_DataRead(reg, (uint32_t*)val); + } +} + +/***************************************************************************//** + * @brief + * Read a 256 bit value from a crypto register into optionally unaligned + * buffer. + * + * @note + * This function provide a low-level api for reading one of the multi-word + * registers in the crypto peripheral. Applications should prefer to use + * @ref CRYPTO_DataRead, @ref CRYPTO_DDataRead or @ref CRYPTO_QDataRead + * for reading the value of the DATA, DDATA and QDATA registers. + * + * @param[in] reg + * Pointer to the crypto register. + * + * @param[out] val + * This is a pointer to a byte array of at least 32 bytes + * that will be filled with the 256 bit value from the crypto register. + ******************************************************************************/ +__STATIC_INLINE void CRYPTODRV_DDataReadUnaligned(volatile uint32_t * reg, + uint8_t * val) +{ + /* Check data is 32bit aligned, if not, read into temporary buffer and + then move to user buffer. */ + if ((uint32_t)val & 0x3) + { + uint32_t temp[8]; + CRYPTO_DDataRead(reg, temp); + memcpy(val, temp, 32); + } + else + { + CRYPTO_DDataRead(reg, (uint32_t*)val); + } +} + +/***************************************************************************//** + * @brief + * Check status of CRYPTO operation. + * + * @details + * This function checks the status of a specific CRYPTO operation. + * + * @param pCryptoContext + * Pointer to CRYPTO context associated with operation. + * + * @return + * ECODE_OK if operation completed successfully. + * ECODE_CRYPTODRV_RUNNING if CRYPTO is executing operation. + * ECODE_CRYPTODRV_ABORTED if operation was aborted. + */ +Ecode_t CRYPTODRV_CheckStatus (CRYPTODRV_Context_t* pCryptoContext); + +#if defined(MBEDTLS_INCLUDE_ASYNCH_API) + +/***************************************************************************//** + * @brief + * Set asynchronous callback to be called when crypto operations complete. + * + * @details + * This function sets the asynchronous callback function to be called when + * crypto operations complete. + * + * @return + * N/A + */ +void CRYPTODRV_SetAsynchCallback +( + CRYPTODRV_Context_t* pCryptodrvContext, + CRYPTODRV_AsynchCallback_t asynchCallback, + void* callbackArgument + ); + +#else /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +__STATIC_INLINE void CRYPTODRV_SetAsynchCallback +( + CRYPTODRV_Context_t* pCryptodrvContext, + CRYPTODRV_AsynchCallback_t asynchCallback, + void* callbackArgument + ) +{ + (void) pCryptodrvContext; + (void) asynchCallback; + (void) callbackArgument; +} + +#endif /* #if defined(MBEDTLS_INCLUDE_ASYNCH_API) */ + +#if defined MBEDTLS_CRYPTO_DEVICE_PREEMPTION + + /***************************************************************************//** + * @brief + * Arbitrate for exclusive access to CRYPTO unit. + * + * @details + * This function will arbitrate for the ownership of the CRYPTO unit in order + * to execute CRYPTO operations. If the ownership is won and there is an + * ongoing CRYPTO operation, this function will preempt the ongoing operation + * by storing the full CRYPTODRV context inlcuding hardware context + * (register values) of the CRYPTO unit. When the caller is ready to release + * CRYPTO, the caller should call CRYPTODRV_Release in + * order to restore the context of the ongoing operation, in order for that to + * continue operation. The function call of the ongoing operation may try to + * restore and continue after the abort event, but may fail and return + * MBEDTLS_ECODE_CRYPTODRV_OPERATION_ABORTED. + * This function may be called from an interrupt handler in order to perform + * time critical CRYPTO operations. + * + * @param pCryptodrvContext + * Pointer to CRYPTODRV context which should be used in subsequent calls, + * like @ref CRYPTODRV_Release. + * + * @return + * ECODE_OK if success. Error code if failure. + * MBEDTLS_ECODE_CRYPTODRV_BUSY if priority is lower than or equal to running thread. + */ +Ecode_t CRYPTODRV_Arbitrate (CRYPTODRV_Context_t* pCryptodrvContext); + +/***************************************************************************//** + * @brief + * Release a CRYPTODRV context and possibly ownership of CRYPTO unit. + * + * @details + * This function removes a CRYPTODRV context from the CRYPTODRV context list + * (which includes current owner and preempted contexts). + * If the specified context is the owner of the CRYPTO unit, this function + * will release the ownership of the CRYPTO unit. If there is a preempted + * context in the context list, then the preempted context is restored + * by updating the hardware state of the CRYPTO unit. + * + * @param pCryptodrvContext + * The CRYPTODRV context to remove from CRYPTODRV context list. + * + * @return + * ECODE_OK if success. Error code if failure. + */ +Ecode_t CRYPTODRV_Release (CRYPTODRV_Context_t* pCryptodrvContext); + +/***************************************************************************//** + * @brief + * Enter critical CRYPTO operation region. + * + * @details + * This function will enter a critical region by disabling potential harmful + * interrupts and thread scheduling, in order to protect a CRYPTO operation + * from being interrupted and aborted by higher priority threads/ISRs. + * The implementation of this function is OS/runtime platform dependent and + * there should be one version per supported OS/runtime platform. + * + * @return + * ECODE_OK if success. Error code if failure. + */ +Ecode_t CRYPTODRV_EnterCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext); + + /***************************************************************************//** + * @brief + * Exit critical CRYPTO operation region. + * + * @details + * This function exits from a critical region by enabling interrupts and + * thread scheduling, in order to allow higher priority threads/ISRs to + * arbitrate for CRYPTO ownership. + * The implementation of this function is OS/runtime platform dependent and + * there should be one version per supported OS/runtime platform. + * + * @return + * ECODE_OK if success. Error code if failure. + */ +Ecode_t CRYPTODRV_ExitCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext); + +#else /* #if defined MBEDTLS_CRYPTO_DEVICE_PREEMPTION */ + +__STATIC_INLINE +Ecode_t CRYPTODRV_Arbitrate (CRYPTODRV_Context_t* pCryptodrvContext) +{ + CMU->HFBUSCLKEN0 |= pCryptodrvContext->device->clk; + return ECODE_OK; +} +__STATIC_INLINE +Ecode_t CRYPTODRV_Release (CRYPTODRV_Context_t* pCryptodrvContext) +{ + CMU->HFBUSCLKEN0 &= ~pCryptodrvContext->device->clk; + return ECODE_OK; +} +__STATIC_INLINE +Ecode_t CRYPTODRV_EnterCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext) +{ + (void) pCryptodrvContext; + return ECODE_OK; +} +__STATIC_INLINE +Ecode_t CRYPTODRV_ExitCriticalRegion (CRYPTODRV_Context_t* pCryptodrvContext) +{ + (void) pCryptodrvContext; + return ECODE_OK; +} + +#endif /* #if defined MBEDTLS_CRYPTO_DEVICE_PREEMPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* #if ( defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) ) || \ + ( defined(AES_COUNT) && (AES_COUNT > 0) ) */ + +#endif /* #ifndef __SILICON_LABS_CRYPTODRV_INTERNAL_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.c new file mode 100644 index 00000000000..50ab512fe90 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.c @@ -0,0 +1,433 @@ +/* + * Buffer Controller (BUFC) interface implementation. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "em_device.h" + +#if defined(BUFC_COUNT) && (BUFC_COUNT > 0) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "em_bufc.h" +#include "em_assert.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup BUFC + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************** ENUMS ************************************ + ******************************************************************************/ + + +/******************************************************************************* + ******************************* STRUCTS *********************************** + ******************************************************************************/ + + +/******************************************************************************* + *************************** GLOBAL FUNCTIONS ****************************** + ******************************************************************************/ + + +/***************************************************************************//** + * @brief + * Initialize the Buffer Controller (BUFC) of EFR. + * + * @details + * Use this function to initialize the 4 buffers controlled by the Buffer + * Controller (BUFC). + * Refer to EFR Reference Manual Chapter 5.8 and the configuration structure + * BUFC_Init_TypeDef for more details. + * + * @note + * Internal notes: + * Init should map all the buffers (/w starter address), set threshold mode, etc + * Init should use the BufferConfig() + * It would be important to enforce the use of Init() as it would be required + * (and safe) to initialize all the buffers in each RESET or WAKEUP cycle. + * => this shall be handled by higher layers (platform) + * Note: These kinda cases are not optimal for SPI access, (starter addr mixed + * with thrsh mode ("fragmentation") + * + * - BUFC_ThresholdOnPinSet() should be part of init? + * + * @param[in] init + * Pointer to initialization structure used to configure the buffers. + ******************************************************************************/ +void BUFC_Init(BUFC_Init_TypeDef const *init) +{ + uint32_t i; + + + /* Iterate through all the buffers. */ + for (i = 0U; i < 4U; i++) + { + BUFC_BufferConfig(i, &(init->buffer[i])); + /* BUFC_ThresholdOnPinSet() ? */ + } +} + + +/***************************************************************************//** + * @brief + * Reset BUFC registers to the hardware reset state. + * + * @details + * This function resets all the buffer configurations (incl. address, size, + * buffer pointers, etc.). + ******************************************************************************/ +void BUFC_Reset(void) +{ + uint32_t i; + + /* Reset all buffers (0-3). */ + for (i = 0U; i < 4U; i++) + { + /* Clear the buffer. */ + BUFC_Clear(i); + + /* Reset BUF[i] registers to their default values. */ + BUFC->BUF[i].CTRL = _BUFC_BUF_CTRL_RESETVALUE; + BUFC->BUF[i].ADDR = _BUFC_BUF_ADDR_RESETVALUE; + BUFC->BUF[i].WRITEOFFSET = _BUFC_BUF_WRITEOFFSET_RESETVALUE; + BUFC->BUF[i].READOFFSET = _BUFC_BUF_READOFFSET_RESETVALUE; + BUFC->BUF[i].WRITEDATA = _BUFC_BUF_WRITEDATA_RESETVALUE; + BUFC->BUF[i].THRESHOLDCTRL = _BUFC_BUF_THRESHOLDCTRL_RESETVALUE; + } +} + + +/***************************************************************************//** + * @brief + * Configures all parameters of the selected buffer. + * + * @details + * Use this function to initialize the 4 buffers controlled by the Buffer + * Controller (BUFC). + * Refer to EFR Reference Manual Chapter 5.8 and the configuration structure + * BUFC_Init_TypeDef for more details. + * + * @note + * Internal notes: + * This should not use the INLINEs provided below. + * Think with a MANAGEMENT sublayer in mind when designing this API. + * eg. single buffer manipulation could possibly be done by higher level + * using this function. Think of run-time services. + * - buffer size enums are used because its more consistent for higher level + * layers to handle allocated RAM size and BUFC buffer size with them + * + * @param[in] confPtr + * Pointer to configuration structure used to configure the buffers. + ******************************************************************************/ +void BUFC_BufferConfig(uint32_t bufId, + BUFC_BufferConf_TypeDef const *confPtr) +{ + uint32_t tmp; + + + /* Sanity check of bufId. */ + EFM_ASSERT(bufId < 4U); + EFM_ASSERT((confPtr->size == bufcSize64) || + (confPtr->size == bufcSize128) || + (confPtr->size == bufcSize256) || + (confPtr->size == bufcSize1024) || + (confPtr->size == bufcSize2048) || + (confPtr->size == bufcSize512)); + + + /* Get buffer size from configuration. */ + switch (confPtr->size) + { + case bufcSize64: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE64; + } break; + + case bufcSize128: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE128; + } break; + + case bufcSize256: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE256; + } break; + + case bufcSize512: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE512; + } break; + + case bufcSize1024: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE1024; + } break; + + case bufcSize2048: + { + tmp = BUFC_BUF_CTRL_SIZE_SIZE2048; + } break; + + default: + { + EFM_ASSERT(0); + return; /* Early return on error. */ + } + /* Note: intentionally missing "break;" from the end of the branch as it + * would be an unreachable statement due to the early return! */ + } + + /* Set buffer size. */ + BUFC->BUF[bufId].CTRL = tmp; + + /* Set the start address of the buffer. */ + BUFC->BUF[bufId].ADDR = (uint32_t)confPtr->addr; + + /* Set buffer threshold and threshold mode. */ + BUFC->BUF[bufId].THRESHOLDCTRL = (uint32_t)confPtr->threshMode | + ((uint32_t)confPtr->thresh << + _BUFC_BUF_THRESHOLDCTRL_THRESHOLD_SHIFT); +} + + +/***************************************************************************//** + * @brief + * Sets the address of the selected buffer. + * + * @details + * + * @note + * Internal notes: buffer address will be 32bit on the SoC. + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @param[in] addr + * Address to be set. + ******************************************************************************/ +void BUFC_AddrSet(uint32_t bufId, uint32_t addr) +{ + /* Set the start address of the buffer. */ + BUFC->BUF[bufId].ADDR = (uint32_t)addr; +} + + +/***************************************************************************//** + * @brief + * Sets the size of the selected buffer. + * + * @details + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @param[in] size + * Size to be set. + * @li bufcSize64 - Buffer size 64 bytes. + * @li bufcSize128 - Buffer size 128 bytes. + * @li bufcSize256 - Buffer size 256 bytes. + * @li bufcSize512 - Buffer size 512 bytes. + ******************************************************************************/ +void BUFC_SizeSet(uint32_t bufId, BUFC_Size_TypeDef size) +{ + /* Set buffer size. */ + BUFC->BUF[bufId].CTRL = (uint32_t)size; +} + + +/***************************************************************************//** + * @brief + * Sets the threshold options of the selected buffer. + * + * @details + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @param[in] thresh + * Threshold to be set. + * + * @param[in] threshMode + * Threshold mode to be set. + * @li false: THRESHOLDIF will be set if BYTES is larger than THRESHOLD + * @li true: THRESHOLDIF will be set if BYTES is less than or equal to THRESHOLD + ******************************************************************************/ +void BUFC_ThresholdSet(uint32_t bufId, + uint32_t thresh, + BUFC_ThreshMode_TypeDef threshMode) +{ + /* Set buffer threshold and threshold mode. */ + BUFC->BUF[bufId].THRESHOLDCTRL = (uint32_t)threshMode | + (thresh << _BUFC_BUF_THRESHOLDCTRL_THRESHOLD_SHIFT); +} + +/***************************************************************************//** + * @brief + * Clears the selected buffer, resets the offset pointers. + * + * @details + * ... + * + * @note + * Internal note: CMD register + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + ******************************************************************************/ +void BUFC_Clear(uint32_t bufId) +{ + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_CLEAR; +} + + +/***************************************************************************//** + * @brief + * Prefetch read data if the buffer was written outside of the buffer + * controller (BUFC). + * + * @details + * If a write to the location indicated by the READOFFSET is performed outside + * the BUFC, the prefetched value will not be updated. In this case use this + * function to update the prefetched value. + * + * @note + * Internal note: consider if its really necessary as an API function! + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + ******************************************************************************/ +void BUFC_Prefetch(uint32_t bufId) +{ + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_PREFETCH; +} + +#if defined(EFR4DFULL) +/***************************************************************************//** + * @brief + * Update the write start value to the value of the write offset. + * + * @details + * Use this function to set the write start value (WRITESTART) to the value of + * the write offset (WRITEOFFSET). This is normally done before receiving a + * new frame. The write start value is used to store the initial value of the + * write offset prior to receiving a frame. This value is basically used to + * remove a partly received frame which is to be removed. + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + ******************************************************************************/ +void BUFC_WriteStartUpdate(uint32_t bufId) +{ + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_UPDATEWRITESTART; +} + + +/***************************************************************************//** + * @brief + * Restore the write offset value to the value of the write start. + * + * @details + * Use this function to set the write offset value (WRITEOFFSET) to the value + * of the write start (WRITESTART). This is normally done before discarding a + * partly received frame. + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + ******************************************************************************/ +void BUFC_WriteOffsetRestore(uint32_t bufId) +{ + BUFC->BUF[bufId].CMD = BUFC_BUF_CMD_RESTOREWRITEOFFSET; +} +#endif + +/***************************************************************************//** + * @brief + * Gets the current number of bytes in the selected buffer. + * + * @details + * BYTES = (WRITEOFFSET - READOFFSET)modulo(SIZE) + * + * @note + * Internal note: BUFn_STATUS + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @return + * Number of bytes in the selected buffer. + ******************************************************************************/ +uint32_t BUFC_NumOfBytesGet(uint32_t bufId) +{ + return (BUFC->BUF[bufId].STATUS & _BUFC_BUF_STATUS_BYTES_MASK); +} + + +/***************************************************************************//** + * @brief + * Gets the current WriteOffset value of the selected buffer. + * + * @note + * Internal note: consider int16_t instead of int + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @return + * Current WriteOffset value of the selected buffer. + ******************************************************************************/ +int32_t BUFC_WriteOffsetGet(uint32_t bufId) +{ + /* Casting 2's complement offset value to int32_t. */ + return (int32_t)BUFC->BUF[bufId].WRITEOFFSET; +} + + +/***************************************************************************//** + * @brief + * Gets the current ReadOffset value of the selected buffer. + * + * @note + * Internal note: consider int16_t instead of int + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @return + * Current ReadOffset value of the selected buffer. + ******************************************************************************/ +int32_t BUFC_ReadOffsetGet(uint32_t bufId) +{ + /* Casting 2's complement offset value to int32_t. */ + return (int32_t)BUFC->BUF[bufId].READOFFSET; +} + + +/** @} (end addtogroup BUFC) */ +/** @} (end addtogroup EM_Library) */ + +#endif /* defined(BUFC_COUNT) && (BUFC_COUNT > 0) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.h new file mode 100644 index 00000000000..41fdb804bbc --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/em_bufc.h @@ -0,0 +1,403 @@ +/* + * Buffer Controller (BUFC) interface definition. + * + * Copyright (C) 2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __EM_BUFC_H +#define __EM_BUFC_H + +#include "em_device.h" + +#if defined(BUFC_COUNT) && (BUFC_COUNT > 0) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup BUFC + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************** ENUMS ************************************ + ******************************************************************************/ + +/** Buffer size options. */ +typedef enum +{ + /** Buffer size of 64 bytes. */ + bufcSize64 = 64, + + /** Buffer size of 128 bytes. */ + bufcSize128 = 128, + + /** Buffer size of 256 bytes. */ + bufcSize256 = 256, + + /** Buffer size of 512 bytes. */ + bufcSize512 = 512, + + bufcSize1024 = 1024, + bufcSize2048 = 2048 +} BUFC_Size_TypeDef; + + +/** Buffer threshold mode options. */ +typedef enum +{ + /** Set threshold interrupt flag (BUFn_IF_THRESHOLDIF) if the number of bytes + * in the buffer is larger than threshold value. */ + bufcThreshModeLarger = BUFC_BUF_THRESHOLDCTRL_THRESHOLDMODE_LARGER, + + /** Set threshold interrupt flag (BUFn_IF_THRESHOLDIF) if the number of bytes + * in the buffer is less or equal than threshold value. */ + bufcThreshModeLessOrEq = BUFC_BUF_THRESHOLDCTRL_THRESHOLDMODE_LESSOREQUAL +} BUFC_ThreshMode_TypeDef; + + +/******************************************************************************* + ******************************* STRUCTS *********************************** + ******************************************************************************/ + +/** Buffer configuration structure. */ +typedef struct +{ + /** Buffer size. + * Note: make sure the memory range is reserved for the buffer in RAM! */ + BUFC_Size_TypeDef size; + + /** Buffer address. + * Note: make sure the memory range is reserved for the buffer in RAM! */ + uint32_t addr; + + /** Buffer threshold (number of bytes). This value is used to trigger the + * threshold interrupt flag (BUFn_IF_THRESHOLDIF), the compare mode is + * defined by #threshMode. */ + uint32_t thresh; + + /** Buffer threshold mode. Defines how to compare the threshold value with the + * number of bytes in the buffer. + * number of bytes = (WRITEOFFSET - READOFFSET) mod (buffer size) */ + BUFC_ThreshMode_TypeDef threshMode; +} BUFC_BufferConf_TypeDef; + +/** Default configuration for BUFC_BufferConf_TypeDef structure. */ +#define BUFC_BUFFER_CONF_DEFAULT \ + { \ + bufcSize512, /* Buffer size is 512 bytes. */ \ + 0x0000U, /* Buffer start address is 0x00000. */ \ + 256U, /* Threshold set to 256 bytes. */ \ + bufcThreshModeLarger /* Threshold mode set to "larger". */ \ + } + + +/** Buffer controller (BUFC) initialization structure. */ +typedef struct +{ + /** Configuration structures for all buffers instances. */ + BUFC_BufferConf_TypeDef buffer[4U]; +} BUFC_Init_TypeDef; + +/** Default configuration for BUFC_Init_TypeDef structure. */ +#define BUFC_INIT_DEFAULT \ + { \ + { \ + BUFC_BUFFER_CONF_DEFAULT, /* Buffer 0 default configuration. */ \ + BUFC_BUFFER_CONF_DEFAULT, /* Buffer 1 default configuration. */ \ + BUFC_BUFFER_CONF_DEFAULT, /* Buffer 2 default configuration. */ \ + BUFC_BUFFER_CONF_DEFAULT /* Buffer 3 default configuration. */ \ + } \ + } + + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ + +void BUFC_Init(BUFC_Init_TypeDef const *init); +void BUFC_Reset(void); +void BUFC_BufferConfig(uint32_t bufId, + BUFC_BufferConf_TypeDef const *confPtr); + +/* Note: + * Consider if these should be really offered as API functions as reconfiguring + * only one buffer can mess up the others! */ +void BUFC_AddrSet(uint32_t bufId, uint32_t addr); +void BUFC_SizeSet(uint32_t bufId, BUFC_Size_TypeDef size); +void BUFC_ThresholdSet(uint32_t bufId, + uint32_t thresh, + BUFC_ThreshMode_TypeDef threshMode); + +void BUFC_Clear(uint32_t bufId); +void BUFC_Prefetch(uint32_t bufId); + +#if defined(EFR4DFULL) +void BUFC_WriteStartUpdate(uint32_t bufId); +void BUFC_WriteOffsetRestore(uint32_t bufId); +#endif + +uint32_t BUFC_NumOfBytesGet(uint32_t bufId); +int32_t BUFC_WriteOffsetGet(uint32_t bufId); +int32_t BUFC_ReadOffsetGet(uint32_t bufId); + +static __INLINE void BUFC_XORDataWrite(uint32_t bufId, uint8_t data); +static __INLINE void BUFC_DataWrite(uint32_t bufId, uint8_t data); +static __INLINE uint8_t BUFC_DataRead(uint32_t bufId); + +static __INLINE void BUFC_IntEnable(uint32_t flags); + /*, INT_IntLocation_TypeDef loc) */ +static __INLINE void BUFC_IntDisable(uint32_t flags); + /*, INT_IntLocation_TypeDef loc) */ + +static __INLINE void BUFC_IntClear(uint32_t flags); +static __INLINE void BUFC_IntSet(uint32_t flags); + +static __INLINE uint32_t BUFC_IntGet(void); /* INT_IntLocation_TypeDef loc); */ +static __INLINE uint32_t BUFC_IntGetEnabled(void); /* INT_IntLocation_TypeDef loc); */ + +/***************************************************************************//** + * @brief + * Writes data to the selected buffer with XOR. + * + * @details + * Using this function, the data is written to the buffer through + * BUFn_XWRITE resulting in a XOR write that means the data to be written + * XOR'ed with the data already in the buffer. + * When writing data to the buffer, the WRITEOFFSET is being incremented by 1 + * for each write. Refer to the Buffer Controller Chapter in EFR Reference + * Manual for more details. + * + * @note + * Internal note: 32bit value on SoC. + * +DataWriteOffsetGet()? - (would save one switch or if) + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @param[in] data + * Data to write to the selected buffer. + ******************************************************************************/ +static __INLINE void BUFC_XORDataWrite(uint32_t bufId, uint8_t data) +{ + BUFC->BUF[bufId].XWRITE = (uint8_t)data; +} + +/***************************************************************************//** + * @brief + * Writes data to the selected buffer. + * + * @details + * When writing data to the buffer, the WRITEOFFSET is being incremented by 1 + * for each write. Refer to the Buffer Controller Chapter in EFR Reference + * Manual for more details. + * + * @note + * Internal note: + * +DataWriteOffsetGet()? - (would save one switch or if) + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @param[in] data + * Data to write to the selected buffer. + ******************************************************************************/ +static __INLINE void BUFC_DataWrite(uint32_t bufId, uint8_t data) +{ + BUFC->BUF[bufId].WRITEDATA = (uint8_t)data; +} + + +/***************************************************************************//** + * @brief + * Reads from the selected buffer. + * + * @note + * ... + * + * @param[in] bufId + * Buffer ID, possible values: 0-3. + * + * @return + * + ******************************************************************************/ +static __INLINE uint8_t BUFC_DataRead(uint32_t bufId) +{ + return (uint8_t)BUFC->BUF[bufId].READDATA; +} + +/***************************************************************************//** + * @brief + * Enable one or more BUFC interrupts. + * + * @param[in] flags + * BUFC interrupt sources to enable. Use a set of interrupt flags OR-ed + * together to enable multiple interrupt sources of the BUFC module + * (IRH_BUFC_nIEN_nnn). + * Internal note: consider different scenarios, host vs M3, asserts + * + * @param[in] loc + * Interrupt flag location, possible values: + * (list of enum values of INT_IntLocation_TypeDef) + * (list of enum values of INT_IntLocation_TypeDef) + ******************************************************************************/ +static __INLINE void BUFC_IntEnable(uint32_t flags) + /*, INT_IntLocation_TypeDef loc) */ +{ + BUFC->IEN |= flags; +} + + +/***************************************************************************//** + * @brief + * Disable one or more BUFC interrupts. + * + * @param[in] flags + * BUFC interrupt sources to disable. Use a set of interrupt flags OR-ed + * together to disable multiple interrupt sources of the BUFC module + * (IRH_BUFC_nIEN_nnn). + * Internal note: consider different scenarios, host vs M3, asserts + * + * @param[in] loc + * Interrupt flag location, possible values: + * (list of enum values of INT_IntLocation_TypeDef) + * (list of enum values of INT_IntLocation_TypeDef) + ******************************************************************************/ +static __INLINE void BUFC_IntDisable(uint32_t flags) + /*, INT_IntLocation_TypeDef loc) */ +{ + BUFC->IEN &= ~(flags); +} + + +/***************************************************************************//** + * @brief + * Clear one or more pending BUFC interrupts. + * + * @param[in] flags + * BUFC interrupt sources to clear. Use a set of interrupt flags OR-ed together + * to clear multiple interrupt sources of the BUFC module (IRH_BUFC_FLAGCLEAR_nnn). + ******************************************************************************/ +static __INLINE void BUFC_IntClear(uint32_t flags) +{ + BUFC->IFC = flags; +} + + +/***************************************************************************//** + * @brief + * Set one or more pending BUFC interrupts from SW. + * + * @param[in] flags + * BUFC interrupt sources to set to pending. Use a set of interrupt + * flags OR-ed together to set multiple interrupt sources of the BUFC module + * (IRH_BUFC_FLAGSET_nnn). + ******************************************************************************/ +static __INLINE void BUFC_IntSet(uint32_t flags) +{ + BUFC->IFC = flags; +} + + +/***************************************************************************//** + * @brief + * Get pending BUFC interrupt flags. + * + * @note + * The effect of reading the interrupt flags is dependent on the configuration + * of the Interrupt Handler module (IRH) as reading the interrupt flags from + * an external host can clear the interrupt if the EIREADCLEAR bit is set + * in IRH_CTRL. Refer to EFR Reference Manual Chapter 13 and _irh.c for + * more details. + * Internal note: consider different scenarios, host vs M3, asserts + * + * @param[in] loc + * Interrupt flag location, possible values: + * (list of enum values of INT_IntLocation_TypeDef) + * (list of enum values of INT_IntLocation_TypeDef) + * (both should not be supported) + * + * @return + * Pending BUFC interrupt sources. The OR combination of valid interrupt flags + * of the BUFC module (IRH_BUFC_FLAG_nnn). + ******************************************************************************/ +static __INLINE uint32_t BUFC_IntGet(void) /* INT_IntLocation_TypeDef loc) */ +{ + return BUFC->IF; +} + + +/***************************************************************************//** + * @brief + * Get enabled and pending BUFC interrupt flags. + * + * @details + * Useful for handling more interrupt sources in the same interrupt handler. + * + * @note + * The effect of reading the interrupt flags is dependent on the configuration + * of the Interrupt Handler module (IRH) as reading the interrupt flags from + * an external host can clear the interrupt if the EIREADCLEAR bit is set + * in IRH_CTRL. Refer to EFR Reference Manual Chapter 13 and _irh.c for + * more details. + * Internal note: consider different scenarios, host vs M3, asserts + * + * @param[in] loc + * Interrupt flag location, possible values: + * (list of enum values of INT_IntLocation_TypeDef) + * (for external its the same as the simple xxxIntGet() as the external flag register only shows the enabled flags) + * (both should not be supported) + * + * @return + * Pending BUFC interrupt sources. + * The return value is the bitwise AND combination of + * - the OR combination of enabled interrupt sources in IRH_BUFC_xIEN register + * (IRH_BUFC_nIEN_nnn) and + * - the OR combination of valid interrupt flags of the BUFC module + * (IRH_BUFC_FLAG_nnn). + ******************************************************************************/ +static __INLINE uint32_t BUFC_IntGetEnabled(void) /* INT_IntLocation_TypeDef loc) */ +{ + uint32_t tmp = 0U; + + + /* Store BUFC->IEN in temporary variable in order to define explicit order + * of volatile accesses. */ + tmp = BUFC->IEN; + + /* Bitwise AND of pending and enabled interrupt flags. */ + return BUFC->IF & tmp; +} + + +/** @} (end addtogroup BUFC) */ +/** @} (end addtogroup EM_Library) */ + +#ifdef __cplusplus +} +#endif + +#endif /* defined(BUFC_COUNT) && (BUFC_COUNT > 0) */ + +#endif /* __EM_BUFC_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_aes.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_aes.c new file mode 100644 index 00000000000..cee43d92e36 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_aes.c @@ -0,0 +1,594 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2015-2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file includes alternative plugin implementations of various + * functions in aes.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ + +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#if defined(MBEDTLS_AES_ALT) + +#if !defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "cryptodrv_internal.h" +#include "em_crypto.h" + +#include "mbedtls/aes.h" + +#include + +#define CRYPTO_AES_BLOCKSIZE ( 16 ) + +#define MBEDTLS_RETVAL_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +#define CRYPTO_CLOCK_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; + +#define CRYPTO_CLOCK_DISABLE CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO; + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) +{ + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/** + * \brief Internal function for setting encryption key in CRYPTO. + * + * \param ctx AES context including key + */ +static inline int crypto_setkey_enc( mbedtls_aes_context *ctx ) +{ + uint32_t* _key = (uint32_t*) ctx->key; + + switch( ctx->keybits ) + { + case 128: + /* Set AES-128 mode */ + BUS_RegMaskedClear(&CRYPTO->CTRL, 1<<_CRYPTO_CTRL_AES_SHIFT); + /* Load key in KEYBUF register */ + CRYPTO->KEYBUF = _key[0]; + CRYPTO->KEYBUF = _key[1]; + CRYPTO->KEYBUF = _key[2]; + CRYPTO->KEYBUF = _key[3]; + return( 0 ); + case 256: + /* Set AES-256 mode */ + BUS_RegMaskedSet(&CRYPTO->CTRL, 1<<_CRYPTO_CTRL_AES_SHIFT); + /* Load key in KEYBUF register (= DDATA4) */ + CRYPTO_DDataWrite( &CRYPTO->DDATA4, _key ); + return( 0 ); + default: + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } +} + +/** + * \brief Internal function for setting decryption key in CRYPTO. + * + * \param ctx AES context including key + */ +static int crypto_setkey_dec( mbedtls_aes_context *ctx ) +{ + uint32_t* _key = (uint32_t*) ctx->key; + + switch( ctx->keybits ) + { + case 128: + /* Set AES-128 mode */ + BUS_RegMaskedClear(&CRYPTO->CTRL, 1<<_CRYPTO_CTRL_AES_SHIFT); + /* Load key in KEYBUF register */ + CRYPTO->KEYBUF = _key[0]; + CRYPTO->KEYBUF = _key[1]; + CRYPTO->KEYBUF = _key[2]; + CRYPTO->KEYBUF = _key[3]; + /* Do dummy encryption to generate decrypt key, and move result to + KEYBUF = DDATA4. */ + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DDATA1TODDATA4); + return( 0 ); + case 256: + /* Set AES-256 mode */ + BUS_RegMaskedSet(&CRYPTO->CTRL, 1<<_CRYPTO_CTRL_AES_SHIFT); + /* Load key in KEYBUF register (= DDATA4) */ + CRYPTO_DDataWrite( &CRYPTO->DDATA4, _key ); + /* Do dummy encryption to generate decrypt key, and move result to + KEYBUF = DDATA4. */ + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_AESENC, + CRYPTO_CMD_INSTR_DDATA1TODDATA4); + return( 0 ); + default: + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) || \ + defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Process multiple AES blocks using current CRYPTO + * instruction sequence. + * + * \param len Length of input buffer (in bytes) + * \param inReg Which CRYPTO register that expects input block + * \param in Input buffer + * \param outReg Which CRYPTO register where result ends up + * \param out Output buffer where result should be written + * \param iv If 'iv' is non-NULL, copy input to iv for + * subsequent iterative calls. + */ +static void crypto_aes_processloop(uint32_t len, + CRYPTO_DataReg_TypeDef inReg, + const uint8_t* in, + CRYPTO_DataReg_TypeDef outReg, + uint8_t* out, + uint8_t* iv) +{ + len /= CRYPTO_AES_BLOCKSIZE; + CRYPTO->SEQCTRL = 16 << _CRYPTO_SEQCTRL_LENGTHA_SHIFT; + + while (len--) + { + /* Save initial vector for last block */ + if (iv && 0==len) + memcpy(iv, in, 16); + + /* Load data and trigger encryption */ + CRYPTODRV_DataWriteUnaligned(inReg, in); + + CRYPTO->CMD = CRYPTO_CMD_SEQSTART; + + /* Save encrypted/decrypted data */ + CRYPTODRV_DataReadUnaligned(outReg, out); + + out += 16; + in += 16; + } +} +#endif /* #if defined(MBEDTLS_CIPHER_MODE_CBC) || \ + defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR) */ + +/* + * Initialize AES context + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +/* + * Clear AES context + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * AES key schedule (encryption) + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + if ( ( 128 != keybits ) && ( 256 != keybits ) ) + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + + ctx->keybits = keybits; + memcpy(ctx->key, key, keybits/8); + + return 0; +} + +/* + * AES key schedule (decryption) + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + if ( ( 128 != keybits ) && ( 256 != keybits ) ) + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + + ctx->keybits = keybits; + memcpy(ctx->key, key, keybits/8); + + return 0; +} + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ret = 0; + + /* Initialize CRYPTO */ + CRYPTO_CLOCK_ENABLE; + CRYPTO->CTRL = 0; + CRYPTO->WAC = 0; + CRYPTO->SEQCTRL = 0; + CRYPTO->SEQCTRLB = 0; + + if( mode == MBEDTLS_AES_ENCRYPT ) + { + /* Load plaintext */ + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA0, input ); + + /* Set encryption key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_enc (ctx) ); + + /* Trigger encryption */ + CRYPTO->CMD = CRYPTO_CMD_INSTR_AESENC; + } + else + { + /* Set/calculate decryption key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_dec (ctx) ); + + /* Load ciphertext. Must be done after decryption key calculation + which is destructive for value in DATA0. */ + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA0, input ); + + /* Trigger decryption */ + CRYPTO->CMD = CRYPTO_CMD_INSTR_AESDEC; + } + + /* Save encrypted/decrypted data */ + CRYPTODRV_DataReadUnaligned( &CRYPTO->DATA0, output); + + cleanup: + + CRYPTO_CLOCK_DISABLE; + + return ret; +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + + /* Input length must be a multiple of 16 bytes which is the AES block + length. */ + if( length & 0xf ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + + CRYPTO_CLOCK_ENABLE; + CRYPTO->CTRL = 0; + CRYPTO->WAC = 0; + CRYPTO->SEQCTRL = 0; + CRYPTO->SEQCTRLB = 0; + + if( mode == MBEDTLS_AES_ENCRYPT ) + { + /* Set encryption key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_enc (ctx) ); + + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA0, iv ); + + CRYPTO->SEQ0 = + CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR0_SHIFT | + CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT; + + crypto_aes_processloop( length, + &CRYPTO->DATA1, input, + &CRYPTO->DATA0, output, + 0 ); + /* Copy last output block to iv */ + memcpy (iv, &output[length-16], 16); + } + else + { + /* Set key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_dec (ctx) ); + + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA2, iv ); + + CRYPTO->SEQ0 = + CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT | + CRYPTO_CMD_INSTR_AESDEC << _CRYPTO_SEQ0_INSTR1_SHIFT | + CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT | + CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT; + + CRYPTO->SEQ1 = 0; + + /* The following call is equivalent to the last call in the + 'if( mode == MBEDTLS_AES_ENCRYPT )' branch. However moving this + call outside the conditional scope results in slightly poorer + performance for some compiler optimizations. */ + crypto_aes_processloop( length, + &CRYPTO->DATA1, input, + &CRYPTO->DATA0, output, + iv ); + } + + cleanup: + + CRYPTO_CLOCK_DISABLE; + + return( ret ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + if ( (iv_off && *iv_off) || ( length % 16 ) ) + { + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); + } + else + { + int ret = 0; + + CRYPTO_CLOCK_ENABLE; + CRYPTO->CTRL = 0; + CRYPTO->WAC = 0; + CRYPTO->SEQCTRL = 0; + CRYPTO->SEQCTRLB = 0; + + /* Set key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_enc (ctx) ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + /* Load IV */ + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA2, iv); + + /* Load instructions to CRYPTO sequencer. */ + CRYPTO->SEQ0 = + CRYPTO_CMD_INSTR_DATA2TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT | + CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT | + CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT | + CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT; + CRYPTO->SEQ1 = 0; + + crypto_aes_processloop(length, + &CRYPTO->DATA1, input, + &CRYPTO->DATA0, output, + iv ); + } + else + { + /* Load IV */ + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA0, iv); + + /* Load instructions to CRYPTO sequencer. */ + CRYPTO->SEQ0 = + CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR0_SHIFT | + CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR1_SHIFT; + + crypto_aes_processloop(length, + &CRYPTO->DATA1, input, + &CRYPTO->DATA0, output, + 0 ); + + /* Copy last output block to iv */ + memcpy (iv, &output[length-16], 16); + } + + cleanup: + CRYPTO_CLOCK_DISABLE; + + return( ret ); + } +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + int ret = 0; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + MBEDTLS_RETVAL_CHK( mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + cleanup: + + return( ret ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + if (( length & 0xf ) || (nc_off && *nc_off) ) + { + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) + { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); + } + else + { + int ret = 0; + + CRYPTO_CLOCK_ENABLE; + CRYPTO->CTRL = 0; + CRYPTO->WAC = 0; + CRYPTO->SEQCTRL = 0; + CRYPTO->SEQCTRLB = 0; + + /* Set key */ + MBEDTLS_RETVAL_CHK( crypto_setkey_enc (ctx) ); + + BUS_RegMaskedClear(&CRYPTO->CTRL, _CRYPTO_CTRL_INCWIDTH_MASK); + BUS_RegMaskedSet(&CRYPTO->CTRL, CRYPTO_CTRL_INCWIDTH_INCWIDTH4); + + CRYPTODRV_DataWriteUnaligned( &CRYPTO->DATA1, nonce_counter ); + + CRYPTO->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT | + CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT | + CRYPTO_CMD_INSTR_DATA0TODATA3 << _CRYPTO_SEQ0_INSTR2_SHIFT | + CRYPTO_CMD_INSTR_DATA1INC << _CRYPTO_SEQ0_INSTR3_SHIFT; + + CRYPTO->SEQ1 = CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ1_INSTR4_SHIFT; + + crypto_aes_processloop( length, + &CRYPTO->DATA2, input, + &CRYPTO->DATA0, output, + 0); + + CRYPTODRV_DataReadUnaligned( &CRYPTO->DATA1, nonce_counter ); + + cleanup: + + CRYPTO_CLOCK_DISABLE; + + return ret; + } +} +#endif /* #if defined(MBEDTLS_CIPHER_MODE_CTR) */ + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* #if defined(MBEDTLS_SLCL_PLUGINS) */ + +#endif /* #if defined(MBEDTLS_AES_ALT) */ + +#endif /* #if defined(MBEDTLS_AES_C) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_ecp.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_ecp.c new file mode 100644 index 00000000000..4442e7c0c87 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_ecp.c @@ -0,0 +1,1453 @@ +/* + * Elliptic curves over GF(p): CRYPTO hw acceleration functions + * + * Copyright (C) 2015-2016 Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes alternative plugin implementations of various + * functions in ecp.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined( MBEDTLS_ECP_C ) + +#if defined( MBEDTLS_ECP_DEVICE_ALT ) + +#if !defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" + +#if defined( CRYPTO_COUNT ) && ( CRYPTO_COUNT > 0 ) + +#include "em_crypto.h" + +#include "mbedtls/ecp.h" + +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#define CRYPTO_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; \ + CRYPTO->IFC = _CRYPTO_IFC_MASK; \ + CRYPTO->CMD = CRYPTO_CMD_SEQSTOP; \ + CRYPTO->CTRL = CRYPTO_CTRL_DMA0RSEL_DDATA0; \ + CRYPTO->SEQCTRL = 0; \ + CRYPTO->SEQCTRLB = 0 + +#define CRYPTO_DISABLE \ + CRYPTO->IEN = 0; \ + CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO; + +/** ECC big integer type. */ +#define ECC_BIGINT_SIZE_IN_BITS (256) +#define ECC_BIGINT_SIZE_IN_BYTES (ECC_BIGINT_SIZE_IN_BITS/8) +#define ECC_BIGINT_SIZE_IN_32BIT_WORDS (ECC_BIGINT_SIZE_IN_BYTES/sizeof(uint32_t)) +#define EC_BIGINT_COPY(X, Y) memcpy(X, Y, sizeof(ecc_bigint_t)); +typedef uint32_t ecc_bigint_t[ECC_BIGINT_SIZE_IN_32BIT_WORDS]; + +#if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) +#define MPI_TO_BIGINT(bigint, mpi) mpitobigint(bigint, mpi); + +/***************************************************************************//** + * @brief + * Convert an mpi number representation to a 32bit word array used by crypto. + ******************************************************************************/ +__STATIC_INLINE void mpitobigint( ecc_bigint_t bigint, const mbedtls_mpi* mpi ) +{ + uint32_t* bi = bigint; + + if ( mpi->n < 8 ) + { + memcpy(bigint, mpi->p, mpi->n * sizeof(uint32_t)); + memset(&bi[mpi->n], 0, sizeof(ecc_bigint_t) - mpi->n * sizeof(uint32_t)); + } + else + { + memcpy(bigint, mpi->p, 8 * sizeof(uint32_t)); + } +} + +/***************************************************************************//** + * @brief + * Returns true if the value of the DDATA0 register is equal to zero. + ******************************************************************************/ +__STATIC_INLINE bool crypto_ddata0_is_zero(uint32_t* status_reg) +{ + CRYPTO_EXECUTE_3(CRYPTO, + CRYPTO_CMD_INSTR_CCLR, + CRYPTO_CMD_INSTR_DEC, /* Decrement by one which will set + carry bit if DDATA0 is zero. */ + CRYPTO_CMD_INSTR_INC /* Increment in order to restore + original value. */ + ); + + *status_reg = CRYPTO->DSTATUS; + + return (*status_reg & CRYPTO_DSTATUS_CARRY) == CRYPTO_DSTATUS_CARRY; +} +#endif + +/***************************************************************************//** + * @brief + * Check if CRYPTO supports acceleration of given ecc curve. + ******************************************************************************/ +bool mbedtls_ecp_device_grp_capable( const mbedtls_ecp_group *grp ) +{ + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult256Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult256Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult260Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + return( false ); + } +} + +/***************************************************************************//** + * @brief + * Enable CRYPTO by setting up control registers for given ecc curve. + ******************************************************************************/ +int mbedtls_ecp_device_init( const mbedtls_ecp_group *grp ) +{ + /* CRYPTO specific setup */ + CRYPTO_ENABLE; + + CRYPTO->SEQCTRL = CRYPTO_SEQCTRL_BLOCKSIZE_32BYTES | 32; + + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + CRYPTO_ModulusSet( CRYPTO, cryptoModulusEccP192 ); + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult256Bits ); + return 0; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + CRYPTO_ModulusSet( CRYPTO, cryptoModulusEccP224 ); + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult256Bits ); + return 0; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + CRYPTO_ModulusSet( CRYPTO, cryptoModulusEccP256 ); + CRYPTO_MulOperandWidthSet( CRYPTO, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( CRYPTO, cryptoResult260Bits ); + return 0; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } +} + +/***************************************************************************//** + * @brief + * Disable CRYPTO by turning off clock (unless needed by mpi apis separately.) + ******************************************************************************/ +int mbedtls_ecp_device_deinit( const mbedtls_ecp_group *grp ) +{ + (void) grp; +#if !defined( MBEDTLS_MPI_MUL_MPI_ALT ) && \ + !defined( MBEDTLS_MPI_MUL_INT_ALT ) + CRYPTO_DISABLE; +#endif + return 0; +} + +/***************************************************************************//** + * @brief + * Write 256 bits of data to a DDATAX register in the CRYPTO module. + * + * @details + * Write 256 bits of data into a DDATAX (Double Data) register in the crypto + * module. + * + * @param[in] ddataReg Data register identifier + * @param[in] val Value of the data to write to the DDATA register. + ******************************************************************************/ +__STATIC_INLINE void ecp_crypto_ddata_write(CRYPTO_DDataReg_TypeDef ddataReg, + const mbedtls_mpi* mpi) +{ + uint32_t volatile* regPtr = (volatile uint32_t *) ddataReg; + uint32_t* pVal = mpi->p; + register uint32_t v0; + register uint32_t v1; + register uint32_t v2; + register uint32_t v3; + int i; + + if (mpi->n <4) + { + /* Non optimal write of data. */ + for (i=0; i<(int)mpi->n; i++) + *regPtr = *pVal++; + for (; i<8; i++) + *regPtr = 0; + } + else + { + if (mpi->n < 8) + { + /* Optimal write of first 4 words. */ + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + + /* Non optimal write of remaining words */ + for (i=4; i<(int)mpi->n; i++) + *regPtr = *pVal++; + for (; i<8; i++) + *regPtr = 0; + } + else + { + /* Optimal write of all data. */ + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + } + } +} + +/***************************************************************************//** + * @brief + * Read 256 bits of data from a DDATAX register in the CRYPTO module. + * + * @details + * Read 256 bits of data from a DDATAX (Double Data) register in the crypto + * module. + * + * @param[in] ddataReg Data register identifier + * @param[out] val Location where to store the value in memory. + ******************************************************************************/ + +__STATIC_INLINE int ecp_crypto_ddata_read(CRYPTO_DDataReg_TypeDef ddataReg, + mbedtls_mpi* mpi) +{ + CRYPTO_DData_TypeDef ddata; + uint32_t val32; + int i; + int used; + int ret = 0; + + if (mpi->n == 8) + { + CRYPTO_DDataRead(ddataReg, mpi->p); + } + else + { + if (mpi->n > 8) + { + CRYPTO_DDataRead(ddataReg, mpi->p); + memset(&mpi->p[8], 0, sizeof(uint32_t)*(mpi->n-8)); + } + else + { + uint32_t volatile* regPtr = (volatile uint32_t*) ddataReg; + used = 0; + for (i=0; i<8; i++) + { + ddata[i] = val32 = *regPtr; + if (val32) + used = i+1; + } + if (used > (int)mpi->n) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow(mpi, used) ); + memcpy(mpi->p, ddata, used*sizeof(uint32_t)); + mpi->s = 1; + } + else + { + memcpy(mpi->p, ddata, mpi->n*sizeof(uint32_t)); + } + } + } + cleanup: + return( ret ); +} + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +/* + * Alternative implementation of ecp_double_jac using CRYPTO hardware + * acceleration. + * + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on Section 3.2.4 in "Introduction to Identity-Based Encryption" + * by Martin Luther + * + * Cost: 1D := 4M + 4S (A == -3) + * + */ +int ecp_device_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + ecc_bigint_t _2YY; + int ret; + (void) grp; + + /* + STEP 1: + + Goals: + ZZ = Z^2 + R->Z = 2 * Y * Z + YY = Y^2 + 4YY = 4 * Y^2 + + Write Operations: + + R2 = Y + R3 = Z + + Instructions to be executed: + + 1. R0 = DMA = Z + 2. R1 = R0 = Z + 3. R2 = R0 = Z + 4. Select R1, R2 + 5. R0 = R1 * R2 = Z^2 = ZZ + 6. R3 = R0 = ZZ + + 7. R0 = DMA = Y + 8. R2 = R0 = Y + 9. R0 = R1 * R2 = Y * Z + 10. Select R0, R0 + 11. R0 = R0 + R0 = 2 * Y * Z = R->Z + + 12. DMA = R0 = R->Z + + 13. R1 = R2 = Y + 14. Select R1, R2 + 15. R0 = R1 * R2 = Y^2 = YY + 16. Select R0, R0 + 17. R0 = R0 + R0 = 2YY + + Read Operations: + + R->Z = R0 = 2 * Y * Z + 2YY = R0 + + Output State: + R0 = 2YY + R1 = FREE + R2 = FREE + R3 = ZZ + R4 = FREE + + STEP 1: + */ + CRYPTO_EXECUTE_17(CRYPTO, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DATATODMA0, + + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD + ); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &P->Z); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &P->Y); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->Z) ); + ecp_crypto_ddata_write(&CRYPTO->DDATA4, &P->X); + CRYPTO_DDataRead(&CRYPTO->DDATA0, _2YY); + + /* + STEP 2: + + Goals: + A = 4YY * X + C = 3(X - ZZ)(X + ZZ) + + Write Operations: + + R4 = X + + Input State: + R0 = 2YY + R1 = FREE + R2 = FREE + R3 = ZZ + R4 = X + + Instructions to be executed: + + 1. R0 = R0 + R0 = 4YY + 2. R1 = R0 = 4YY + 3. Select R1, R4 + 4. R0 = R1 * R4 = 4YY * X = A + 5. R2 = R0 = A + 6. Select R4, R3 + 7. R0 = R4 + R3 = X + ZZ + 8. R1 = R0 = X + ZZ + 9. R0 = R4 - R3 = X - ZZ + 0. R2 = R0 = X - ZZ + 11. Select R1, R2 + 12. R0 = R1 * R2 = (X + ZZ)(X - ZZ) + 13. R1 = R0 = (X + ZZ)(X - ZZ) + 14. Select R0, R1 + 15. R0 = R0 + R1 = 2(X + ZZ)(X - ZZ) + 16. R0 = R0 + R1 = 3(X + ZZ)(X - ZZ) = C + 17. R1 = R0 = C + + Output State: + R0 = FREE + R1 = C + R2 = A + R3 = FREE + R4 = FREE + + STEP 2: + */ + + CRYPTO_EXECUTE_17(CRYPTO, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA4DDATA3, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 + ); + /* + STEP 3: + + Goals: + R->X = C^2 - 2A + D = C(A - R->X) + + Input State: + R0 = FREE + R1 = C + R2 = A + R3 = FREE + R4 = FREE + + Instructions to be executed: + + 1. R4 = R1 = C + 2. Select R1, R4 + 3. R0 = R1 * R4 = C^2 + 4. Select R0, R2 + 5. R0 = R0 - R2 = C^2 - 2A = R->X + 6. R4 = R0 = R->X + 7. Select R3, R4 + 8. R0 = R3 - R4 = A - R->X + 9. R2 = R0 = A - R->X + 10 Select R1, R2 + 11. R0 = R1 * R2 = C(A - R->X) = D + + Read Operations: + + R->X = R4 = C^2 - 2A + + Output State: + R0 = D + R1 = FREE + R2 = FREE + R3 = FREE + R4 = FREE + + STEP 3: + */ + CRYPTO_EXECUTE_15(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_DDATA1TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL + ); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->X) ); + + /* + STEP 4: + + Goals: + B = 8 * Y^4 + R->Y = D - B + + Write Operations: + + R1 = YY + + Input State: + R0 = D + R1 = YY + R2 = FREE + R3 = FREE + R4 = FREE + + Instructions to be executed: + + 1. R3 = R0 = D + 2. R0 = DMA0 + 3. R1 = R0 = Y^2 + 4. R2 = R0 = Y^2 + 5. Select R1, R2 + 6. R0 = R1 * R2 = Y^4 + 7. Select R0, R0 + 8. R0 = R0 + R0 = 2 * Y^4 + 9. R0 = R0 + R0 = 4 * Y^4 + 10. R0 = R0 + R0 = 8 * Y^4 + 11. R2 = R0 + 12. Select R3, R2 + 13. R0 = R3 - R2 = D - B = R->Y + + Read Operations: + + R->Y = R0 = D - B + + STEP 4: + */ + CRYPTO_EXECUTE_11(CRYPTO, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + + CRYPTO_CMD_INSTR_SELDDATA3DDATA2, + CRYPTO_CMD_INSTR_MSUB + ); + CRYPTO_DDataWrite(&CRYPTO->DDATA0, _2YY); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->Y) ); + + cleanup: + return( ret ); +} +#endif /* #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */ + +#if defined(MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT) +/* + * Alternative implementation of ecp_add_mixed using CRYPTO hardware + * acceleration. + * + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +int ecp_device_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + (void) grp; + + /* + STEP 1: + + Goals: + A = Qx*Pz^2 + B = Qy*Pz^3 + + Write Operations: + + R0 = Pz + R0 = Qx + R0 = Qy + + Instructions to be executed: + + 1. R0 = DMA = Pz + 2. R1 = R0 = Pz + 3. R2 = R0 = Pz + 4. Select R1, R2 + 5. R0 = R1 * R2 = Pz^2 + 6. R1 = R0 = Pz^2 + + 7. R0 = DMA = Qx + 8. R3 = R0 = Qx + 9. Select R1, R3 + 10. R0 = R1 * R3 = Qx * Pz^2 + 11. R3 = R0 = Qx * Pz^2 + + 12. Select R1, R2 + 13. R0 = R1 * R2 = Pz^3 + 14. R1 = R0 = Pz^3 + + 15. R0 = DMA = Qy + 16. R4 = R0 = Qx + 17. Select R1, R4 + 18. R0 = R1 * R4 = Qy * Pz^3 + 19. Select R0, R1 (for MSUB in step 2) + + Output State: + R0 = B + R1 = FREE + R2 = FREE + R3 = A + R4 = Pz + + STEP 1: + */ + CRYPTO_EXECUTE_19(CRYPTO, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1 + ); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &P->Z); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &Q->X); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &Q->Y); + + /* + STEP 2: + + Goals: + C = A - Px + D = B - Py + R->Z = Pz * C + + Write Operations: + + R1 = Py + R0 = Px (via DMA) + + Input State: + R0 = B + R1 = Py + R2 = FREE + R3 = A + R4 = Pz + + Instructions to be executed: + + 1. R0 = R0 - R2 = B - Py = D + 2. R2 = R0 = D + 3. R1 = R3 = A + 4. R0 = DMA = Px + 5. R3 = R0 = Px + 6. Select R1, R3 + 7. R0 = R1 - R3 = A - Px = C + 8. R1 = R0 = C + 9. Select R1, R4 + 10. R0 = R1 * R4 = Pz * C = R->Z + 11. R4 = R1 = C + + Read Operations: + + R->Z = R0 = Pz * C + + Output State: + R0 = FREE + R1 = C + R2 = D + R3 = Px + R4 = FREE + + STEP 2: + */ + + ecp_crypto_ddata_write(&CRYPTO->DDATA1, &P->Y); + CRYPTO_EXECUTE_11(CRYPTO, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, /* R2 = D */ + + CRYPTO_CMD_INSTR_DDATA3TODDATA1, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, /* R1 = C */ + + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA1TODDATA4 + ); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &P->X); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->Z) ); + + /* + STEP 3: + + Goals: + X1C2 = Px * C^2 + C3 = C^3 + D2 = D^2 + + Input State: + R0 = FREE + R1 = C + R2 = D + R3 = Px + R4 = FREE + + Instructions to be executed: + + 1. R0 = R1 * R4 = C^2 + 2. R1 = R0 = C^2 + 3. R0 = R1 * R4 = C^3 + 4. R4 = R0 = C^3 + 5. Select R1, R3 + 6. R0 = R1 * R3 = Px * C^2 + 7. R3 = R0 = Px * C^2 + 8. R1 = R2 = D + 9. Select R1, R1 + 10. R0 = R1 * R1 = D^2 + 11. Select R0, R4 (for MSUB operation in next sequence) + + Output state: + + R0 = D2 + R1 = FREE + R2 = D + R3 = X1C2 = Px * C^2 + R4 = C3 = C^3 + + STEP 3: + */ + CRYPTO_EXECUTE_11(CRYPTO, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4 + ); + /* + STEP 3: + + Goals: + R->X = D2 - (C3 + 2 * X1C2) = D2 - C3 - X1C2- X1C2 + Y1C3 = Py * C3 + R->Y = D * (X1C2 - R->X) - Y1C3 + + Write Operations: + R1 = Py + + Input State: + R0 = D2 + R1 = FREE + R2 = D + R3 = X1C2 + R4 = C3 + + Instructions to be executed: + + 1. R0 = R0 - R4 = D2 - C3 + 2. Select R0, R3 + 3. R0 = R0 - R3 = D2 - C3 - X1C2 + 4. R0 = R0 - R3 = D2 - C3 - X1C2 - X1C2 = R->X + 5. DMA = R0 = R->X + 6. R1 = R0 = R->X + + 7. Select R3, R1 + 8. R0 = R3 - R1 = X1C2 - R->X + 9. R1 = R0 = X1C2 - R->X + 10. Select R1, R2 + 11. R0 = R1 * R2 = D *(X1C2 - R->X) + 12. R2 = R0 + + 13. R0 = DMA = Py + 14. R1 = R0 = Py + 15. Select R1, R4 + 16. R0 = R1 * R4 = Py * C3 = Y1C3 + 17. R4 = R0 = Y1C3 + + 18. Select R2, R4 + 19. R0 = R2 - R4 + + Read Operations: + + R->X = R2 = D2 - (C3 + 2 * X1C2) + R->Y = R0 = D * (X1C2 - R->X) - Y1C3 + + STEP 4: + */ + + CRYPTO_EXECUTE_19(CRYPTO, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_SELDDATA3DDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB + ); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->X) ); + ecp_crypto_ddata_write(&CRYPTO->DDATA0, &P->Y); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&CRYPTO->DDATA0, &R->Y) ); + + cleanup: + return( ret ); +} +#endif /* #if defined(MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT) */ + +#if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) +/***************************************************************************//** + * @brief + * Modular division using CRYPTO hardware acceleration. + * + * @details + * This function computes R = X/Y mod(N) using CRYPTO hardware acceleration. + * The implementation is not a direct replacement plugin, i.e. alternative + * implementation, of an existing mbedtls function. This function is used + * internally in other CRYPTO plugin functions indirectly replacing + * mbedtls_mpi_inv_mod. + * + * @param[in] X Dividend of modular division operation + * @param[in] Y Divisor of modular division operation + * @param[in] N Modulus + * @param[out] R The destination of the result + * + * @return N/A + ******************************************************************************/ +static void mbedtls_mpi_div_mod(ecc_bigint_t X, + ecc_bigint_t Y, + ecc_bigint_t N, + ecc_bigint_t R) +{ + uint32_t D[9]; + uint32_t status_reg; + uint8_t rdata; + uint8_t lsb_C; + uint8_t lsb_D; + uint8_t lsb_U; + int t; + int k; + + /************** Initialize and organize data in crypto module **************/ + + /* + ** Register usage: + ** + ** DDATA0 - holds temporary results and loads 260 bit variables in/out + ** DDATA1 - variable referred to as 'C' in the following algorithm + ** DDATA2 - variable referred to as 'U' in the following algorithm + ** DDATA3 - variable referred to as 'D' in the following algorithm + ** DDATA4 - variable referred to as 'W' in the following algorithm + */ + + EC_BIGINT_COPY(D, N); /* D will hold the modulus (n) initially */ + D[8]=0; /* Set MSWord of D to 0. */ + + CRYPTO_DDataWrite(&CRYPTO->DDATA1, Y); /* Set C to Y (divisor) initially */ + CRYPTO_DDataWrite(&CRYPTO->DDATA2, X); /* Set U to X (dividend)initially */ + + CRYPTO_DDataWrite(&CRYPTO->DDATA3, N); /* Set D to modulus p initially */ + + CRYPTO_EXECUTE_3(CRYPTO, + CRYPTO_CMD_INSTR_CLR, /* DDATA0 = 0 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA4, /* Set W to zero initially*/ + CRYPTO_CMD_INSTR_DDATA1TODDATA0);/* DDATA0 = C initially */ + + t = 0; + k = 1; + + /******************* Run main loop while 'C' is non-zero ********************/ + + /* while (C != 1024'd0) */ + while ( !crypto_ddata0_is_zero(&status_reg) ) + { + lsb_C = (status_reg & _CRYPTO_DSTATUS_DDATA0LSBS_MASK) >> _CRYPTO_DSTATUS_DDATA0LSBS_SHIFT; + if ((lsb_C & 0x1) == 0) + { + CRYPTO_EXECUTE_3(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA1DDATA1, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 + ); + t = t-1; + } + else + { + if (t<0) + { + CRYPTO_EXECUTE_6(CRYPTO, + CRYPTO_CMD_INSTR_DDATA2TODDATA0, + CRYPTO_CMD_INSTR_DDATA4TODDATA2, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_DDATA3TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA3); + CRYPTO_DDATA0_260_BITS_READ(CRYPTO, D); + t = -t; + } + + k = 1; + + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_ADD); + + rdata = CRYPTO_DData0_4LSBitsRead(CRYPTO); + + if((rdata & 0x3) != 0x0) + k = -1; + else + t = t-1; + + /* R1 = C >> 1 */ + CRYPTO->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; /* to get the lsb of C */ + + lsb_C = CRYPTO_DData0_4LSBitsRead(CRYPTO); + CRYPTO_EXECUTE_4(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA1DDATA1, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA3TODDATA0); /* to get the lsb of D(R3) */ + + /* R3 = D >> 1 */ + lsb_D = CRYPTO_DData0_4LSBitsRead(CRYPTO); + + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA3DDATA3, + CRYPTO_CMD_INSTR_SHRA); + + if(k == 1) + { + if (((lsb_C & 0x1)==0x1) && ((lsb_D & 0x1)==0x1)) + { + CRYPTO_EXECUTE_7(CRYPTO, + /* C = R1+R3+1 */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_ADDC, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2+R4,n) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + else + { + CRYPTO_EXECUTE_6(CRYPTO, + /* C = R1+R3 */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_ADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2+R4,n) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + } + else + { + if (k == -1) + { + if (((lsb_C & 0x1)==0x0) && ((lsb_D & 0x1)==0x1)) + { + CRYPTO_EXECUTE_8(CRYPTO, + /* C = R1-R3-1 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_SUBC, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2-R4,p) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + else + { + CRYPTO_EXECUTE_7(CRYPTO, + /* C = R1+R3 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_SUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2-R4,p) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + + CRYPTO_DDATA0_260_BITS_WRITE(CRYPTO, D); + CRYPTO->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA3; + + } /* if (k == -1) */ + } + } /* else: !if((C[31:0] & 0x1) == 0x0) */ + + CRYPTO->CMD = CRYPTO_CMD_INSTR_DDATA2TODDATA0; + + lsb_U = CRYPTO_DData0_4LSBitsRead(CRYPTO); + + /* if ((U[31:0] & 0x1) == 0x1) */ + if((lsb_U & 0x1) == 0x1) + { + CRYPTO_EXECUTE_10(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_DMA0TODATA, /* DDATA0 = N */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_SHR, + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_ADDC, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); + + CRYPTO_DDataWrite(&CRYPTO->DDATA0, N); + } + else + { + CRYPTO_EXECUTE_3(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); + } + + /* DDATA0 = C */ + CRYPTO->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; + + } /* End of main loop: while (C != 0) */ + + /* if (D == 1): */ + /* Decrement D by 1 and test if zero. */ + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_DDATA3TODDATA0, + CRYPTO_CMD_INSTR_DEC); + + if (crypto_ddata0_is_zero(&status_reg)) + { + CRYPTO_DDataRead(&CRYPTO->DDATA4, R); + } + else + { + CRYPTO_DDataWrite(&CRYPTO->DDATA0, N); + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_SUB + ); + CRYPTO_DDataRead(&CRYPTO->DDATA0, R); + } + + return; +} /* mbedtls_mpi_div_mod */ +#endif /* #if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) */ + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) +/* + * Alternative implementation of ecp_normalize_jac using CRYPTO hardware + * acceleration. + * + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + */ +int ecp_device_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret = 0; + +#if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) + + ecc_bigint_t one; + ecc_bigint_t Z; + ecc_bigint_t modulus; + ecc_bigint_t Z_inv; + + memset(one, 0, sizeof(one)); + one[0]=1; + + MPI_TO_BIGINT( Z, &P->Z ); + MPI_TO_BIGINT( modulus, &grp->P ); + + mbedtls_mpi_div_mod(one, Z, modulus, Z_inv); + + CRYPTO_DDataWrite(&CRYPTO->DDATA1, Z_inv); + +#else + + mbedtls_mpi Z_inv; + mbedtls_mpi_init( &Z_inv ); + + /* + * Z_inv = 1 / Z mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Z_inv, &P->Z, &grp->P ) ); + + ecp_crypto_ddata_write(&CRYPTO->DDATA1, &Z_inv); +#endif + + /* + + Goals: + R->X = P->X * Z_inv ^2 + R->Y = P->Y * Z_inv ^3 + + Write Operations: + + R1 = Z_inv + R3 = P->X + R4 = P->Y + + Instructions to be executed: + + 1. R2 = R1 = Z_inv + 2. Select R1, R2 + 3. R0 = R1 * R2 = Z_inv^2 + 4. R1 = R0 = Z_inv^2 + 5. Select R1, R3 + 6. R0 = R1 * R3 = P->X * Z_inv^2 = R->X + 7. R3 = R0 + 8. Select R1, R2 + 9. R0 = R1 * R2 = Z_inv^3 + 10. R1 = R0 = Z_inv^3 + 11. Select R1, R4 + 12. R0 = R1 * R4 = P->Y * Z_inv^3 = R->Y + + Read Operations: + + R->Y = R0 = P->Y * P->Z_inv^3 + R->X = R3 = P->X * P->Z_inv^2 + + */ + + ecp_crypto_ddata_write(&CRYPTO->DDATA3, &P->X); + ecp_crypto_ddata_write(&CRYPTO->DDATA4, &P->Y); + + CRYPTO_EXECUTE_12(CRYPTO, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + ecp_crypto_ddata_read(&CRYPTO->DDATA0, &P->Y); + ecp_crypto_ddata_read(&CRYPTO->DDATA3, &P->X); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + + cleanup: + +#if !defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) + mbedtls_mpi_free( &Z_inv ); +#endif /* #if !defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) */ + + return( ret ); +} +#endif /* #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) */ + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) +/* + * Alternative implementation of ecp_normalize_jac_many using + * CRYPTO hardware acceleration. + * + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + */ +int ecp_device_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ) +{ + int ret; + size_t i; + ecc_bigint_t* cc; + ecc_bigint_t uu; + ecc_bigint_t one; + ecc_bigint_t modulus; + + if( t_len < 2 ) + return( ecp_device_normalize_jac( grp, *T ) ); + + if( ( cc = mbedtls_calloc( t_len, sizeof( ecc_bigint_t ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MPI_TO_BIGINT( cc[0], &T[0]->Z ); + for( i = 1; i < t_len; i++ ) + { + ecp_crypto_ddata_write( &CRYPTO->DDATA1, &T[i]->Z ); + CRYPTO_DDataWrite( &CRYPTO->DDATA2, cc[i-1] ); + CRYPTO_EXECUTE_2(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_DDataRead( &CRYPTO->DDATA0, cc[i] ); + } + + memset(one, 0, sizeof(one)); + one[0]=1; + MPI_TO_BIGINT( modulus, &grp->P ); + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + mbedtls_mpi_div_mod(one, cc[t_len-1], modulus, uu); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) + { + /* Z_inv (DDATA2) = uu */ + CRYPTO_DDataWrite(&CRYPTO->DDATA2, uu); + } + else + { + /* Z_inv (DDATA1) = uu x cc[i-1] modulo p */ + /* uu = uu x T[i]->Z modulo p */ + CRYPTO_DDataWrite(&CRYPTO->DDATA1, uu); + CRYPTO_DDataWrite(&CRYPTO->DDATA2, cc[i-1]); + ecp_crypto_ddata_write( &CRYPTO->DDATA3, &T[i]->Z ); + CRYPTO_EXECUTE_5(CRYPTO, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, /* Z_inv (DDATA2) */ + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_DDataRead(&CRYPTO->DDATA0, uu); + } + + /* + * proceed as in normalize() + */ + ecp_crypto_ddata_write(&CRYPTO->DDATA3, &T[i]->X); + ecp_crypto_ddata_write(&CRYPTO->DDATA4, &T[i]->Y); + + /* Z_inv already in DDATA2 */ + CRYPTO_EXECUTE_12(CRYPTO, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + ecp_crypto_ddata_read(&CRYPTO->DDATA0, &T[i]->Y); + ecp_crypto_ddata_read(&CRYPTO->DDATA3, &T[i]->X); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + +cleanup: + + mbedtls_free( cc ); + + return( ret ); +} +#endif /* #if defined( MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT ) */ + +#endif /* #if defined( CRYPTO_COUNT ) && ( CRYPTO_COUNT > 0 ) */ + +#endif /* #if !defined( MBEDTLS_SLCL_PLUGINS ) */ + +#endif /* #if defined( MBEDTLS_ECP_DEVICE_ALT ) */ + +#endif /* #if defined( MBEDTLS_ECP_C ) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha1.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha1.c new file mode 100644 index 00000000000..d35d35f1439 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha1.c @@ -0,0 +1,258 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes alternative plugin implementations of various + * functions in sha1.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#if defined(MBEDTLS_SHA1_ALT) + +#if !defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "em_crypto.h" + +#include "mbedtls/sha1.h" + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define CRYPTO_CLOCK_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; +#define CRYPTO_CLOCK_DISABLE CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO; + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->state[5] = 0x0; + ctx->state[6] = 0x0; + ctx->state[7] = 0x0; + + ctx->total[0] = 0; + ctx->total[1] = 0; +} + +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + CRYPTO_CLOCK_ENABLE; + + /* Setup crypto module to do SHA-1. */ + CRYPTO->CTRL = CRYPTO_CTRL_SHA_SHA1 | + /* Set DMA0 source to DDATA0 and transfer mode */ + CRYPTO_CTRL_DMA0RSEL_DDATA0 | CRYPTO_CTRL_DMA0MODE_FULL | + /* Set DMA1 source to QDATA1BIG and transfer mode */ + CRYPTO_CTRL_DMA1RSEL_QDATA1BIG | CRYPTO_CTRL_DMA1MODE_FULL; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(CRYPTO, cryptoResult256Bits); + + /* Set sequence control registers */ + CRYPTO->SEQCTRL = 16 & _CRYPTO_SEQCTRL_LENGTHA_MASK; + CRYPTO->SEQCTRLB = 0; + + /* Initiate SHA instruction sequence. */ + CRYPTO_EXECUTE_6( CRYPTO, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_DMA1TODATA, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32); + + /* Write the state to crypto */ + CRYPTO_DDataWrite(&CRYPTO->DDATA0, ctx->state); + + /* Write block to QDATA1. */ + /* Check data is 32bit aligned, if not move to temporary buffer. */ + if ((uint32_t)data & 0x3) + { + uint32_t temp[16]; + memcpy(temp, data, 64); + CRYPTO_QDataWrite(&CRYPTO->QDATA1BIG, temp); + } + else + { + CRYPTO_QDataWrite(&CRYPTO->QDATA1BIG, (uint32_t*) data); + } + + /* Read the state from crypto. */ + CRYPTO_DDataRead(&CRYPTO->DDATA0, ctx->state); + +#if !defined( MBEDTLS_MPI_MUL_MPI_ALT ) + CRYPTO_CLOCK_DISABLE; +#endif +} + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + /* Read resulting digest (big endian) */ + CRYPTO_CLOCK_ENABLE; + ((uint32_t*)output)[0] = CRYPTO->DDATA0BIG; + ((uint32_t*)output)[1] = CRYPTO->DDATA0BIG; + ((uint32_t*)output)[2] = CRYPTO->DDATA0BIG; + ((uint32_t*)output)[3] = CRYPTO->DDATA0BIG; + ((uint32_t*)output)[4] = CRYPTO->DDATA0BIG; + { + /* Read 3 remaining 32-bit words from DDATA0BIG (shift register). */ + volatile uint32_t temp; + temp = CRYPTO->DDATA0BIG; + temp = CRYPTO->DDATA0BIG; + temp = CRYPTO->DDATA0BIG; + (void) temp; + } + +#if !defined( MBEDTLS_MPI_MUL_MPI_ALT ) + CRYPTO_CLOCK_DISABLE; +#endif +} + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* #if !defined(MBEDTLS_SLCL_PLUGINS) */ + +#endif /* #if defined(MBEDTLS_SHA1_ALT) */ + +#endif /* #if defined(MBEDTLS_SHA1_C) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha256.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha256.c new file mode 100644 index 00000000000..885703c811c --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_sha256.c @@ -0,0 +1,270 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2015-2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes alternative plugin implementations of various + * functions in sha256.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#if defined(MBEDTLS_SHA256_ALT) + +#if !defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "em_crypto.h" +#include "cryptodrv_internal.h" +#include "mbedtls/sha256.h" +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define CRYPTO_CLOCK_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; +#define CRYPTO_CLOCK_DISABLE CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO; + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + /* Create the init vector */ + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->is224 = is224; +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + CRYPTO_CLOCK_ENABLE; + + /* Setup crypto module to do SHA-2. */ + CRYPTO->CTRL = CRYPTO_CTRL_SHA_SHA2 | + /* Set DMA0 source to DDATA0 and transfer mode */ + CRYPTO_CTRL_DMA0RSEL_DDATA0 | CRYPTO_CTRL_DMA0MODE_FULL | + /* Set DMA1 source to QDATA1BIG and transfer mode */ + CRYPTO_CTRL_DMA1RSEL_QDATA1BIG | CRYPTO_CTRL_DMA1MODE_FULL; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(CRYPTO, cryptoResult256Bits); + + /* Set sequence control registers */ + CRYPTO->SEQCTRL = 16 & _CRYPTO_SEQCTRL_LENGTHA_MASK; + CRYPTO->SEQCTRLB = 0; + + /* Initiate SHA instruction sequence. */ + CRYPTO_EXECUTE_6( CRYPTO, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_DMA1TODATA, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32); + + /* Write the state to crypto */ + CRYPTO_DDataWrite(&CRYPTO->DDATA0, ctx->state); + + /* Write block to QDATA1. */ + /* Check data is 32bit aligned, if not move to temporary buffer. */ + if ((uint32_t)data & 0x3) + { + uint32_t temp[16]; + memcpy(temp, data, 64); + CRYPTO_QDataWrite(&CRYPTO->QDATA1BIG, temp); + } + else + { + CRYPTO_QDataWrite(&CRYPTO->QDATA1BIG, (uint32_t*) data); + } + + /* Read the state from crypto. */ + CRYPTO_DDataRead(&CRYPTO->DDATA0, ctx->state); + +#if !defined( MBEDTLS_MPI_MUL_MPI_ALT ) + CRYPTO_CLOCK_DISABLE; +#endif +} + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + /* Read resulting digest (big endian) */ + CRYPTO_CLOCK_ENABLE; + + /* Read the digest from crypto (big endian). */ + CRYPTODRV_DDataReadUnaligned(&CRYPTO->DDATA0BIG, output); + +#if !defined( MBEDTLS_MPI_MUL_MPI_ALT ) + CRYPTO_CLOCK_DISABLE; +#endif + + if( ctx->is224 ) + memset(&output[28], 0, 4); +} + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* #if !defined( MBEDTLS_SLCL_PLUGINS ) */ + +#endif /* #if defined(MBEDTLS_SHA256_ALT) */ + +#endif /* #if defined(MBEDTLS_SHA256_C) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_timing.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_timing.c new file mode 100644 index 00000000000..b3f62145a91 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/sl_timing.c @@ -0,0 +1,79 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_TIMING_C) + +#include "em_device.h" +#include "em_cmu.h" + +#include "mbedtls/timing.h" + +#if defined(MBEDTLS_TIMING_ALT) + +void mbedtls_timing_init( void ) +{ + if ((CMU->STATUS & _CMU_STATUS_AUXHFRCOENS_MASK) == 0) + { + /* Enable debug clock AUXHFRCO */ + CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true); + } + + if ((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0) + { + /* Enable trace in core debug */ + CoreDebug->DHCSR |= CoreDebug_DHCSR_C_DEBUGEN_Msk; + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + } + if ((ITM->TCR & ITM_TCR_DWTENA_Msk) == 0) + { + /* Unlock ITM and output data */ + ITM->LAR = 0xC5ACCE55; + ITM->TCR |= ITM_TCR_DWTENA_Msk; + } + if ((DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk) == 0) + { + /* Enable DWT bits */ + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + DWT->CYCCNT = 0; + } +} + +void mbedtls_timing_free( void ) +{ + /* Disable the DWT and debug clock */ + DWT->CTRL = 0; + CMU_OscillatorEnable( cmuOsc_AUXHFRCO, false, true ); +} + +#endif /* !MBEDTLS_TIMING_ALT */ + +#endif /* MBEDTLS_TIMING_C */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_aes.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_aes.c new file mode 100644 index 00000000000..a3e272676c4 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_aes.c @@ -0,0 +1,551 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file includes alternative plugin implementations of various + * functions in aes.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ + +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#if defined(MBEDTLS_AES_ALT) + +#if defined( MBEDTLS_SLCL_PLUGINS ) + +#include "mbedtls/aes.h" +#include "sl_crypto.h" +#include "aesdrv_internal.h" +#include "cryptodrv_internal.h" +#include + +#define AES_BLOCKSIZE ( 16 ) + +#define MBEDTLS_RETVAL_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) +{ + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize AES context + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); + + AESDRV_Init ( &ctx->aesdrv_ctx ); + AESDRV_SetDeviceInstance ( &ctx->aesdrv_ctx, 0 ); + AESDRV_SetIoMode ( &ctx->aesdrv_ctx, aesdrvIoModeCore, 0 ); +} + +/* + * Clear AES context + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + AESDRV_DeInit ( &ctx->aesdrv_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * Set the device instance of an AES context. + */ +int mbedtls_aes_set_device_instance(mbedtls_aes_context *ctx, + unsigned int devno) +{ +#if defined(AES_COUNT) && (AES_COUNT > 0) + (void) ctx; + if ((devno > AES_COUNT) || (devno != 0)) + return( MBEDTLS_ERR_AES_INVALID_PARAM ); + else + return( 0 ); +#endif + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_AES_INVALID_PARAM ); + + return cryptodrvSetDeviceInstance( &ctx->aesdrv_ctx.cryptodrvContext, + devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/* + * Set an AES context in asynchronous mode. + */ +int mbedtls_aes_set_asynch( mbedtls_aes_context *ctx, + mbedtls_aes_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* asynch_callback_user_arg ) +{ + Ecode_t status; + + AESDRV_BlockCipherAsynchContext_t *aesdrv_asynch_ctx = + asynch_ctx ? &asynch_ctx->aesdrv_asynch_ctx : 0; + + status = AESDRV_SetAsynchMode(&ctx->aesdrv_ctx, + cipherModeBlockCipher, + aesdrv_asynch_ctx, + (AESDRV_AsynchCallback_t) asynch_callback, + asynch_callback_user_arg); + if (status != ECODE_OK) + { + return (int)status; + } + + return( 0 ); +} +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/* + * Set the device I/O mode of an AES context. + */ +int mbedtls_aes_set_device_io_mode( mbedtls_aes_context *ctx, + mbedtls_device_io_mode mode, + mbedtls_device_io_mode_specific *specific ) +{ + return AESDRV_SetIoMode(&ctx->aesdrv_ctx, + (AESDRV_IoMode_t) mode, + (AESDRV_IoModeSpecific_t*) specific); +} + +/* + * AES key schedule (encryption) + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + if ( ( 128 != keybits ) && ( 256 != keybits ) ) + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + + ctx->keybits = keybits; + memcpy(ctx->key, key, keybits/8); + + return 0; +} + +/* + * AES key schedule (decryption) + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int ret = 0; + Ecode_t status; + + switch( keybits ) + { + case 128: + status = AESDRV_DecryptKey128( &ctx->aesdrv_ctx, + (uint8_t*)ctx->key, + key ); + if (status != ECODE_OK) + ret = status; + break; + + case 256: + status = AESDRV_DecryptKey256( &ctx->aesdrv_ctx, + (uint8_t*)ctx->key, + key ); + if (status != ECODE_OK) + ret = status; + break; + + default: + /* Unsupported key size */ + ret = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + break; + } + + ctx->keybits = keybits; + + return ret; +} + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ret = 0; + Ecode_t status; + + switch( ctx->keybits ) + { + case 128: + status = AESDRV_ECB128( &ctx->aesdrv_ctx, + output, + input, + 16, + (uint8_t*)ctx->key, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + case 256: + status = AESDRV_ECB256( &ctx->aesdrv_ctx, + output, + input, + 16, + (uint8_t*)ctx->key, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + default: + ret = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + break; + } + + return ret; +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + Ecode_t status; + + /* Input length must be a multiple of 16 bytes which is the AES block + length. */ + if( length & 0xf ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + + switch( ctx->keybits ) + { + case 128: + status = AESDRV_CBC128( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + case 256: + status = AESDRV_CBC256( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + default: + ret = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + break; + } + + return( ret ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n = iv_off ? *iv_off : 0; + + if ( n || ( length & 0xf ) ) + { + int c; + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + if (ctx->aesdrv_ctx.pAsynchContext) + { + /* Asynchronous calls are not supported when iv_off is non-zero. */ + return MBEDTLS_ERR_AES_NOT_SUPPORTED; + } +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + if (iv_off) + { + *iv_off = n; + } + return( 0 ); + } + else + { + int ret = 0; + Ecode_t status; + + switch( ctx->keybits ) + { + case 128: + status = AESDRV_CFB128( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? + true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + case 256: + status = AESDRV_CFB256( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? + true : false ); + + if (status != ECODE_OK) + ret = status; + break; + + default: + ret = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + break; + } + + return( ret ); + } +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + int ret = 0; + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + if (ctx->aesdrv_ctx.pAsynchContext) + { + /* Asynchronous calls are not supported by this function. */ + return MBEDTLS_ERR_AES_NOT_SUPPORTED; + } +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + + while( length-- ) + { + memcpy( ov, iv, 16 ); + MBEDTLS_RETVAL_CHK( mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + cleanup: + + return( ret ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n = nc_off ? *nc_off : 0; + + if ( n || ( length & 0xf ) ) + { + int c, i; + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + if (ctx->aesdrv_ctx.pAsynchContext) + { + /* Asynchronous calls are not supported when nc_off is non-zero. */ + return MBEDTLS_ERR_AES_NOT_SUPPORTED; + } +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + + while( length-- ) + { + if( n == 0 ) + { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + if (nc_off) + { + *nc_off = n; + } + return( 0 ); + } + else + { + int ret = 0; + Ecode_t status; + + switch( ctx->keybits ) + { + case 128: + status = AESDRV_CTR128( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + nonce_counter, + 0); + if (status != ECODE_OK) + ret = status; + break; + + case 256: + status = AESDRV_CTR256( &ctx->aesdrv_ctx, + output, + input, + length, + (uint8_t*)ctx->key, + nonce_counter, + 0); + if (status != ECODE_OK) + ret = status; + break; + + default: + ret = MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + break; + } + + return ret; + } +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* MBEDTLS_SLCL_PLUGINS */ + +#endif /* MBEDTLS_AES_ALT */ + +#endif /* MBEDTLS_AES_C */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ccm.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ccm.c new file mode 100644 index 00000000000..36009a677e7 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ccm.c @@ -0,0 +1,429 @@ +/* + * CCM cipher mode based on 128 bit AES and CRYPTO hw acceleration + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined( MBEDTLS_CCM_C ) + +#if defined( MBEDTLS_CCM_ALT ) + +#if defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" +#include "mbedtls/ccm.h" +#include "mbedtls/aes.h" +#include "sl_crypto.h" +#include "aesdrv_internal.h" +#include "cryptodrv_internal.h" +#include "em_assert.h" +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize context + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); + + AESDRV_Init ( &ctx->aesdrv_ctx ); + AESDRV_SetDeviceInstance ( &ctx->aesdrv_ctx, 0 ); + AESDRV_SetIoMode ( &ctx->aesdrv_ctx, aesdrvIoModeCore, 0 ); +} + +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + if ( cipher != MBEDTLS_CIPHER_ID_AES ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + switch( keybits ) + { + case 128: + break; + case 192: + case 256: + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + default: + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + } + + ctx->keybits = keybits; + memcpy(ctx->key, key, keybits/8); + + return( 0 ); +} + +/* + * Set the device instance of an CCM context. + */ +int mbedtls_ccm_set_device_instance(mbedtls_ccm_context *ctx, + unsigned int devno) +{ +#if defined(AES_COUNT) && (AES_COUNT > 0) + (void) ctx; + if ((devno > AES_COUNT) || (devno != 0)) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + else + return( 0 ); +#endif + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + return cryptodrvSetDeviceInstance( &ctx->aesdrv_ctx.cryptodrvContext, + devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + +/* + * Set an CCM context in asynchronous mode. + */ +int mbedtls_ccm_set_asynch( mbedtls_ccm_context *ctx, + mbedtls_ccm_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* asynch_callback_user_arg ) +{ + Ecode_t status; + AESDRV_CCM_AsynchContext_t *aesdrv_asynch_ctx = + asynch_ctx ? &asynch_ctx->aesdrv_asynch_ctx : 0; + + status = AESDRV_SetAsynchMode(&ctx->aesdrv_ctx, + cipherModeCcm, + aesdrv_asynch_ctx, + (AESDRV_AsynchCallback_t) asynch_callback, + asynch_callback_user_arg); + if (status != ECODE_OK) + { + return (int)status; + } + + return( 0 ); +} + +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/* + * Set the device I/O mode of an CCM context. + */ +int mbedtls_ccm_set_device_io_mode( mbedtls_ccm_context *ctx, + mbedtls_device_io_mode mode, + mbedtls_device_io_mode_specific *specific ) +{ + return AESDRV_SetIoMode(&ctx->aesdrv_ctx, + (AESDRV_IoMode_t) mode, + (AESDRV_IoModeSpecific_t*) specific); +} + +/* + * Free context + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) +{ + AESDRV_DeInit ( &ctx->aesdrv_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); +} + +/* + * Authenticated encryption + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + Ecode_t ecode; + + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + */ + if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + /* Also implies q is within bounds */ + if( iv_len < 7 || iv_len > 13 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( add_len > 0xFF00 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + ecode = AESDRV_CCM(&ctx->aesdrv_ctx, + input, output, length, + add, add_len, + (uint8_t*)ctx->key, 128/8, + iv, iv_len, + tag, tag_len, + true); + + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CCM_BAD_INPUT : (int)ecode + ) ); +} + +/* + * Authenticated decryption + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + Ecode_t ecode; + + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + */ + if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + /* Also implies q is within bounds */ + if( iv_len < 7 || iv_len > 13 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( add_len > 0xFF00 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + ecode = AESDRV_CCM(&ctx->aesdrv_ctx, + input, output, length, + add, add_len, + (uint8_t*)ctx->key, 128/8, + iv, iv_len, + (uint8_t*)tag, tag_len, + false); + + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == ecode ? + MBEDTLS_ERR_CCM_AUTH_FAILED : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CCM_BAD_INPUT : (int)ecode + ) ) ); +} + +/* + * CCM authenticated encryption optimized for BLE + */ +int mbedtls_ccm_encrypt_and_tag_ble( mbedtls_ccm_context *ctx, + unsigned char *data, + size_t length, + const unsigned char *iv, + unsigned char header, + unsigned char *tag ) +{ + Ecode_t ecode; + + ecode = AESDRV_CCMBLE(&ctx->aesdrv_ctx, + data, + length, + header, + (uint8_t*)ctx->key, + iv, + tag, + true); + + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CCM_BAD_INPUT : (int)ecode + ) ); +} + +/* + * CCM buffer authenticated decryption optimized for BLE + */ +int mbedtls_ccm_auth_decrypt_ble( mbedtls_ccm_context *ctx, + unsigned char *data, + size_t length, + const unsigned char *iv, + unsigned char header, + unsigned char *tag ) +{ + Ecode_t ecode; + + ecode = AESDRV_CCMBLE(&ctx->aesdrv_ctx, + data, + length, + header, + (uint8_t*)ctx->key, + iv, + tag, + false ); + + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == ecode ? + MBEDTLS_ERR_CCM_AUTH_FAILED : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CCM_BAD_INPUT : (int)ecode + ) ) ); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 + +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char msg[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +}; + +static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res[NB_TESTS][32] = { + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, + { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } +}; + +int mbedtls_ccm_self_test( int verbose ) +{ + mbedtls_ccm_context ctx; + unsigned char out[32]; + size_t i; + int ret; + + mbedtls_ccm_init( &ctx ); + + if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM: setup failed" ); + + return( 1 ); + } + + for( i = 0; i < NB_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); + + ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + msg, out, + out + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + res[i], out, + res[i] + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, msg, msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + mbedtls_ccm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_SLCL_PLUGINS */ + +#endif /* MBEDTLS_CCM_ALT */ + +#endif /* MBEDTLS_CCM_C */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_cmac.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_cmac.c new file mode 100644 index 00000000000..5da89038194 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_cmac.c @@ -0,0 +1,435 @@ +/** + * CMAC cipher mode based on 128 bit AES and CRYPTO hw acceleration + * + * Copyright (C) 2016, Silicon Labs, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements CMAC (Cipher-based Message Authentication Code) + * cipher mode encryption/decryption based on 128 bit AES. + * For a general description please see + * https://en.wikipedia.org/wiki/CMAC + * or for detailed specification see + * http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf + * http://dl.acm.org/citation.cfm?id=2206249 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined( MBEDTLS_CMAC_C ) + +#if defined( MBEDTLS_CMAC_ALT ) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#if defined( MBEDTLS_SLCL_PLUGINS ) + +#include "mbedtls/cmac.h" +#include "mbedtls/aes.h" +#include "sl_crypto.h" +#include "aesdrv_internal.h" +#include "cryptodrv_internal.h" +#include "em_assert.h" +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize context + */ +void mbedtls_cmac_init( mbedtls_cmac_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_cmac_context ) ); + + AESDRV_Init ( &ctx->aesdrv_ctx ); + AESDRV_SetDeviceInstance ( &ctx->aesdrv_ctx, 0 ); + AESDRV_SetIoMode ( &ctx->aesdrv_ctx, aesdrvIoModeCore, 0 ); +} + +/* + * CMAC key setup + */ +int mbedtls_cmac_setkey( mbedtls_cmac_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + if ( cipher != MBEDTLS_CIPHER_ID_AES ) + return( MBEDTLS_ERR_CMAC_BAD_INPUT ); + + switch( keybits ) + { + case 128: + break; + case 192: + case 256: + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + default: + return( MBEDTLS_ERR_CMAC_BAD_INPUT ); + } + + ctx->keybits = keybits; + memcpy(ctx->key, key, keybits/8); + + return( 0 ); +} + +/* + * Set the device instance of an CMAC context. + */ +int mbedtls_cmac_set_device_instance(mbedtls_cmac_context *ctx, + unsigned int devno) +{ +#if defined(AES_COUNT) && (AES_COUNT > 0) + (void) ctx; + if ((devno > AES_COUNT) || (devno != 0)) + return( MBEDTLS_ERR_CMAC_BAD_INPUT ); + else + return( 0 ); +#endif + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_CMAC_BAD_INPUT ); + + return cryptodrvSetDeviceInstance( &ctx->aesdrv_ctx.cryptodrvContext, + devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) +/* + * Set an CMAC context in asynchronous mode. + */ +int mbedtls_cmac_set_asynch( mbedtls_cmac_context *ctx, + mbedtls_cmac_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* asynch_callback_user_arg ) +{ + Ecode_t status; + + AESDRV_CMAC_AsynchContext_t *aesdrv_asynch_ctx = + asynch_ctx ? &asynch_ctx->aesdrv_asynch_ctx : 0; + + status = AESDRV_SetAsynchMode(&ctx->aesdrv_ctx, + cipherModeCmac, + aesdrv_asynch_ctx, + (AESDRV_AsynchCallback_t) asynch_callback, + asynch_callback_user_arg); + if (status != ECODE_OK) + { + return (int)status; + } + + return( 0 ); +} +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + +/* + * Free context + */ +void mbedtls_cmac_free( mbedtls_cmac_context *ctx ) +{ + AESDRV_DeInit ( &ctx->aesdrv_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_cmac_context ) ); +} + +/* + * Generate CMAC tag + */ +int mbedtls_cmac_generate_tag( mbedtls_cmac_context *ctx, + const unsigned char *data, + size_t data_len, + unsigned char *tag, + size_t tag_len ) +{ + Ecode_t ecode = AESDRV_CMAC(&ctx->aesdrv_ctx, + data, data_len, + (uint8_t*)ctx->key, 128/8, + tag, tag_len, + true); + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CMAC_BAD_INPUT : (int)ecode + ) ); +} + +/* + * Verify CMAC tag + * + */ +int mbedtls_cmac_verify_tag( mbedtls_cmac_context *ctx, + const unsigned char *data, + size_t data_len, + unsigned char *tag, + size_t tag_len ) +{ + Ecode_t ecode = AESDRV_CMAC(&ctx->aesdrv_ctx, + data, data_len, + (uint8_t*)ctx->key, 128/8, + tag, tag_len, + false); + return ( ECODE_OK == ecode ? 0 : + ( MBEDTLS_ECODE_AESDRV_AUTHENTICATION_FAILED == ecode ? + MBEDTLS_ERR_CMAC_AUTH_FAILED : + ( MBEDTLS_ECODE_AESDRV_INVALID_PARAM == ecode ? + MBEDTLS_ERR_CMAC_BAD_INPUT : (int)ecode + ) ) ); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CMAC_C) + +/* + * CMAC self test + */ + +#include "timing.h" +#include + +#define ASYNCH_TEST_LEVEL (1) +#define ASYNCH_TEST_INIT(asynch_type) while (false) +#define ASYNCH_TEST_SET_READY while (false) +#define ASYNCH_TEST_HANDLE_COMPLETION while (false) + +typedef struct { + char* key; + int keylen; + char* plaintext; + int plaintextlen; + char* authtag; + int authtaglen; +} cmac_test_vector_t; + +static const cmac_test_vector_t cmac_test_vectors []; +static int hex2uint8array(uint8_t* u8a, int u8alen, const char* hex); + +/* Test the CMAC algorithm. */ +static int test_single_cmac (const cmac_test_vector_t* tv, + int verbose ) +{ + uint8_t* key = (uint8_t*) malloc (tv->keylen); + uint8_t* message = (uint8_t*) malloc (tv->plaintextlen+16); + uint8_t* authTagExpected = (uint8_t*) malloc (16); + uint8_t* authTag = (uint8_t*) malloc (16); + int ret; + int cycles; + mbedtls_cmac_context ctx; + int asynchTest; +#if defined( MBEDTLS_INCLUDE_ASYNCH_API ) + ASYNCH_TEST_INIT(mbedtls_cmac_asynch_context); +#endif /* #if defined( MBEDTLS_INCLUDE_ASYNCH_API ) */ + + mbedtls_cmac_init( &ctx ); + + if ( (NULL==key) || + (NULL==message) || + (NULL==authTag) || + (NULL==authTagExpected) ) + { + if (verbose) + mbedtls_printf("ERROR %s, %d: Unable to allocate memory buffers.\n", + __FILE__, __LINE__); + return -1; + } + + mbedtls_timing_init(); + + for (asynchTest=0; asynchTestkeylen, tv->key); + hex2uint8array(message, tv->plaintextlen, tv->plaintext); + hex2uint8array(authTagExpected, tv->authtaglen, tv->authtag); + + /* Set key */ + ret = mbedtls_cmac_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, 128); + if (0 != ret) + { + mbedtls_printf("mbedtls_cmac_setkey returned error code 0x%x.\n", ret); + ret = -1; + goto exit; + } + + ASYNCH_TEST_SET_READY; + cycles = mbedtls_timing_hardclock(); + + /* Perform the CMAC */ + ret = mbedtls_cmac_generate_tag(&ctx, + message, + tv->plaintextlen*8, + authTag, + tv->authtaglen*8); + + ASYNCH_TEST_HANDLE_COMPLETION; + + if (0 != ret) + { + mbedtls_printf("mbedtls_cmac_encrypt_tag returned error code 0x%x.\n", ret); + ret = -1; + goto exit; + } + + if (0 != memcmp(authTagExpected, authTag, tv->authtaglen)) + { + mbedtls_printf("mbedtls_cmac_encrypt_tag failed to produce expected tag.\n"); + ret = -1; + goto exit; + } + + if (verbose) + mbedtls_printf("%10d %12d %6d %s\n", + tv->authtaglen, tv->plaintextlen, cycles, + asynchTest? "Yes" : "No"); + } + exit: + mbedtls_cmac_free( &ctx ); + + if (key) free(key); + if (message) free(message); + if (authTag) free(authTag); + if (authTagExpected) free(authTagExpected); + + return( ret ); +} + +int mbedtls_cmac_self_test( int verbose ) +{ + const cmac_test_vector_t* tv = cmac_test_vectors; + + mbedtls_printf("\nCMAC Hashing Test AES-128\n" + "AuthTagLen PlaintextLen Cycles Asynch?\n"); + while (tv->key) + { + if (test_single_cmac( tv, verbose ) != 0) + return -1; + tv++; + } + return 0; +} + +static int hex2uint8array(uint8_t* u8a, int u8alen, const char* hex) +{ + int i, j, k, c; + int num; + + if ((hex == NULL) || (*hex == '\0')) return(0); + + for (i=0; isxdigit((unsigned char) hex[i]); i++) + ; + + num=i; + + if (num % 2) + /* hex array must be a multiple of 2 */ + return -1; + + if (u8a == NULL) return(num); + + if (u8alen != num/2) + /* size of uint8 array must be half the size of the hex array. */ + return -1; + + memset(u8a, 0, u8alen); + + for (i = 0; i < num/2; i++) + { + for (j=0; j<2; j++) + { + c=hex[i*2+j]; + if ((c >= '0') && (c <= '9')) k=c-'0'; + else if ((c >= 'a') && (c <= 'f')) k=c-'a'+10; + else if ((c >= 'A') && (c <= 'F')) k=c-'A'+10; + else k=0; /* paranoia */ + u8a[i]=(u8a[i]<<4)|k; + } + } + return(num); +} + +/* +** From file CMACGenAES128.rsp : + +# CAVS 14.0 +# CMAC Encrypt with keysize 128 test information +# Generated on Fri Aug 31 11:23:06 2012 +*/ +static const cmac_test_vector_t cmac_test_vectors [] = +{ + { "2b7e151628aed2a6abf7158809cf4f3c", + 16, + "", + 0, + "bb1d6929e95937287fa37d129b756746", + 16 + }, + { "8eeca0d146fd09ffbbe0d47edcddfcec", + 16, + "", + 0, + "c3642ce5", + 4 + }, + { "f7f922c86706277a4e98d28e1197413b", + 16, + "33ce44bdb1ea6fffe5a29004e2cbf66c", + 16, + "b8768355644df5a9fdff2def763f63", + 15 + }, + { "6533780fc328a88d605268d62f295dc6", + 16, + "02749f4f9ad82fa7ba41d935a6f1aa6376b30b8775b6445ac89b3eac50cd8d56", + 32, + "0bfa134a", + 4 + }, + { "e4abe343f98a2df09413c3defb85b56a", + 16, + "f799876d19ac1b849a1a43fe9912bcaf6e1e3896ea58bcb2dfdc4716e379b440", + 32, + "e08428dbbc13ff9432048c0ad95731", + 15 + }, + {0} +}; + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_CMAC_C */ + +#endif /* MBEDTLS_SLCL_PLUGINS */ + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* MBEDTLS_CMAC_ALT */ + +#endif /* MBEDTLS_CMAC_C */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ecp.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ecp.c new file mode 100644 index 00000000000..aa90627d6a8 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_ecp.c @@ -0,0 +1,2088 @@ +/* + * Elliptic curves over GF(p): CRYPTO hw acceleration functions + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes alternative plugin implementations of various + * functions in ecp.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined( MBEDTLS_ECP_C ) + +#if defined( MBEDTLS_ECP_DEVICE_ALT ) + +#if defined( MBEDTLS_SLCL_PLUGINS ) + +#include "em_device.h" + +#if defined( CRYPTO_COUNT ) && ( CRYPTO_COUNT > 0 ) + +#include "mbedtls/ecp.h" +#include "cryptodrv_internal.h" +#include "em_crypto.h" +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/** ECC big integer type. */ +#define ECC_BIGINT_SIZE_IN_BITS (256) +#define ECC_BIGINT_SIZE_IN_BYTES (ECC_BIGINT_SIZE_IN_BITS/8) +#define ECC_BIGINT_SIZE_IN_32BIT_WORDS (ECC_BIGINT_SIZE_IN_BYTES/sizeof(uint32_t)) +#define EC_BIGINT_COPY(X, Y) memcpy(X, Y, sizeof(ecc_bigint_t)); +typedef uint32_t ecc_bigint_t[ECC_BIGINT_SIZE_IN_32BIT_WORDS]; + +#if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) +#define MPI_TO_BIGINT(bigint, mpi) mpitobigint(bigint, mpi); + +/***************************************************************************//** + * @brief + * Convert an mpi number representation to a 32bit word array used by crypto. + ******************************************************************************/ +__STATIC_INLINE void mpitobigint( ecc_bigint_t bigint, const mbedtls_mpi* mpi ) +{ + uint32_t* bi = bigint; + + if ( mpi->n < 8 ) + { + memcpy(bigint, mpi->p, mpi->n * sizeof(uint32_t)); + memset(&bi[mpi->n], 0, sizeof(ecc_bigint_t) - mpi->n * sizeof(uint32_t)); + } + else + { + memcpy(bigint, mpi->p, 8 * sizeof(uint32_t)); + } +} + +/***************************************************************************//** + * @brief + * Returns true if the value of the DDATA0 register is equal to zero. + ******************************************************************************/ +__STATIC_INLINE bool crypto_ddata0_is_zero(CRYPTO_TypeDef* crypto, + uint32_t* status_reg) +{ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_CCLR, + CRYPTO_CMD_INSTR_DEC, /* Decrement by one which will set + carry bit if DDATA0 is zero. */ + CRYPTO_CMD_INSTR_INC /* Increment in order to restore + original value. */ + ); + + *status_reg = crypto->DSTATUS; + + return (*status_reg & CRYPTO_DSTATUS_CARRY) == CRYPTO_DSTATUS_CARRY; +} +#endif + +#if defined( MBEDTLS_ECP_GROUP_INIT_ALT ) +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) +{ + if( grp == NULL ) + return; + + memset( grp, 0, sizeof( mbedtls_ecp_group ) ); +} +#endif /* #if !defined( MBEDTLS_ECP_GROUP_INIT_ALT ) */ + +#if defined( MBEDTLS_ECP_GROUP_LOAD_ALT ) +int _mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ); + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + int ret = _mbedtls_ecp_group_load( grp, id ); + + if (ret == 0) + { + /* Set device instance to 0 by default. */ + ret = mbedtls_ecp_set_device_instance(grp, 0); + } + return ret; +} +#endif /* #if defined( MBEDTLS_ECP_GROUP_LOAD_ALT ) */ + +/* + * Set the device instance of an ECP group context. + */ +int mbedtls_ecp_set_device_instance(mbedtls_ecp_group *grp, + unsigned int devno) +{ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return cryptodrvSetDeviceInstance( &grp->cryptodrv_ctx, + devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +/** + * @brief + * Check if CRYPTO supports acceleration of given ecc curve. + ******************************************************************************/ +bool mbedtls_ecp_device_grp_capable( const mbedtls_ecp_group *grp ) +{ +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; +#endif + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult256Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult256Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: +#if defined( MBEDTLS_MPI_MUL_MPI_ALT ) || defined( MBEDTLS_MPI_MUL_INT_ALT ) + /* Need to reset operand width and result width if CRYPTO has been + used for MPI acceleration since initialization. */ + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult260Bits ); +#endif + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + return( false ); + } +} + +/***************************************************************************//** + * @brief + * Enable CRYPTO by setting up control registers for given ecc curve. + ******************************************************************************/ +int mbedtls_ecp_device_init( const mbedtls_ecp_group *grp ) +{ + int ret = 0; + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; + Ecode_t status = CRYPTODRV_Arbitrate(p_cryptodrv_ctx); + if (ECODE_OK != status) + return status; + + CRYPTODRV_EnterCriticalRegion(p_cryptodrv_ctx); + + /* Setup CRYPTO registers for ECC operation */ +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + crypto->CTRL = 0; + crypto->SEQCTRL = 0; +#else + crypto->CTRL = CRYPTO_CTRL_DMA0RSEL_DDATA0; + crypto->SEQCTRL = CRYPTO_SEQCTRL_BLOCKSIZE_32BYTES | 32; +#endif + crypto->SEQCTRLB = 0; + + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + CRYPTO_ModulusSet( crypto, cryptoModulusEccP192 ); + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult256Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + CRYPTO_ModulusSet( crypto, cryptoModulusEccP224 ); + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult256Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + CRYPTO_ModulusSet( crypto, cryptoModulusEccP256 ); + CRYPTO_MulOperandWidthSet( crypto, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( crypto, cryptoResult260Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + break; + } + + CRYPTODRV_ExitCriticalRegion(p_cryptodrv_ctx); + + return ret; +} + +/***************************************************************************//** + * @brief + * Disable CRYPTO by turning off clock (unless needed by mpi apis separately.) + ******************************************************************************/ +int mbedtls_ecp_device_deinit( const mbedtls_ecp_group *grp ) +{ + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + Ecode_t status = CRYPTODRV_Release(p_cryptodrv_ctx); + return ECODE_OK != status ? status : 0; +} + +/***************************************************************************//** + * @brief + * Write 256 bits of data to a DDATAX register in the CRYPTO module. + * + * @details + * Write 256 bits of data into a DDATAX (Double Data) register in the crypto + * module. + * + * @param[in] ddataReg Data register identifier + * @param[in] val Value of the data to write to the DDATA register. + ******************************************************************************/ +__STATIC_INLINE void ecp_crypto_ddata_write(CRYPTO_DDataReg_TypeDef ddataReg, + const mbedtls_mpi* mpi) +{ + uint32_t volatile* regPtr = (volatile uint32_t *) ddataReg; + uint32_t* pVal = mpi->p; + register uint32_t v0; + register uint32_t v1; + register uint32_t v2; + register uint32_t v3; + int i; + + if (mpi->n <4) + { + /* Non optimal write of data. */ + for (i=0; i<(int)mpi->n; i++) + *regPtr = *pVal++; + for (; i<8; i++) + *regPtr = 0; + } + else + { + if (mpi->n < 8) + { + /* Optimal write of first 4 words. */ + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + + /* Non optimal write of remaining words */ + for (i=4; i<(int)mpi->n; i++) + *regPtr = *pVal++; + for (; i<8; i++) + *regPtr = 0; + } + else + { + /* Optimal write of all data. */ + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + + v0 = *pVal++; + v1 = *pVal++; + v2 = *pVal++; + v3 = *pVal++; + *regPtr = v0; + *regPtr = v1; + *regPtr = v2; + *regPtr = v3; + } + } +} + +/***************************************************************************//** + * @brief + * Read 256 bits of data from a DDATAX register in the CRYPTO module. + * + * @details + * Read 256 bits of data from a DDATAX (Double Data) register in the crypto + * module. + * + * @param[in] ddataReg Data register identifier + * @param[out] val Location where to store the value in memory. + ******************************************************************************/ + +__STATIC_INLINE int ecp_crypto_ddata_read(CRYPTO_DDataReg_TypeDef ddataReg, + mbedtls_mpi* mpi) +{ + CRYPTO_DData_TypeDef ddata; + uint32_t val32; + int i; + int used; + int ret = 0; + + if (mpi->n == 8) + { + CRYPTO_DDataRead(ddataReg, mpi->p); + } + else + { + if (mpi->n > 8) + { + CRYPTO_DDataRead(ddataReg, mpi->p); + memset(&mpi->p[8], 0, sizeof(uint32_t)*(mpi->n-8)); + } + else + { + uint32_t volatile* regPtr = (volatile uint32_t*) ddataReg; + used = 0; + for (i=0; i<8; i++) + { + ddata[i] = val32 = *regPtr; + if (val32) + used = i+1; + } + if (used > (int)mpi->n) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow(mpi, used) ); + memcpy(mpi->p, ddata, used*sizeof(uint32_t)); + mpi->s = 1; + } + else + { + memcpy(mpi->p, ddata, mpi->n*sizeof(uint32_t)); + } + } + } + cleanup: + return( ret ); +} + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +/* + * Alternative implementation of ecp_double_jac using CRYPTO hardware + * acceleration. + * + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on Section 3.2.4 in "Introduction to Identity-Based Encryption" + * by Martin Luther + * + * Cost: 1D := 4M + 4S (A == -3) + * + */ +int ecp_device_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; + CRYPTODRV_EnterCriticalRegion(p_cryptodrv_ctx); + +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + + ecc_bigint_t _2YY; + /* + STEP 1: + + Goals: + ZZ = Z^2 + R->Z = 2 * Y * Z + YY = Y^2 + 4YY = 4 * Y^2 + + Write Operations: + + R2 = Y + R3 = Z + + Instructions to be executed: + + 1. R0 = DMA = Z + 2. R1 = R0 = Z + 3. R2 = R0 = Z + 4. Select R1, R2 + 5. R0 = R1 * R2 = Z^2 = ZZ + 6. R3 = R0 = ZZ + + 7. R0 = DMA = Y + 8. R2 = R0 = Y + 9. R0 = R1 * R2 = Y * Z + 10. Select R0, R0 + 11. R0 = R0 + R0 = 2 * Y * Z = R->Z + + 12. DMA = R0 = R->Z + + 13. R1 = R2 = Y + 14. Select R1, R2 + 15. R0 = R1 * R2 = Y^2 = YY + 16. Select R0, R0 + 17. R0 = R0 + R0 = 2YY + + Read Operations: + + R->Z = R0 = 2 * Y * Z + 2YY = R0 + + Output State: + R0 = 2YY + R1 = FREE + R2 = FREE + R3 = ZZ + R4 = FREE + + STEP 1: + */ + CRYPTO_EXECUTE_17(crypto, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DATATODMA0, + + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD + ); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z) ); + ecp_crypto_ddata_write(&crypto->DDATA4, &P->X); + CRYPTO_DDataRead(&crypto->DDATA0, _2YY); + + /* + STEP 2: + + Goals: + A = 4YY * X + C = 3(X - ZZ)(X + ZZ) + + Write Operations: + + R4 = X + + Input State: + R0 = 2YY + R1 = FREE + R2 = FREE + R3 = ZZ + R4 = X + + Instructions to be executed: + + 1. R0 = R0 + R0 = 4YY + 2. R1 = R0 = 4YY + 3. Select R1, R4 + 4. R0 = R1 * R4 = 4YY * X = A + 5. R2 = R0 = A + 6. Select R4, R3 + 7. R0 = R4 + R3 = X + ZZ + 8. R1 = R0 = X + ZZ + 9. R0 = R4 - R3 = X - ZZ + 0. R2 = R0 = X - ZZ + 11. Select R1, R2 + 12. R0 = R1 * R2 = (X + ZZ)(X - ZZ) + 13. R1 = R0 = (X + ZZ)(X - ZZ) + 14. Select R0, R1 + 15. R0 = R0 + R1 = 2(X + ZZ)(X - ZZ) + 16. R0 = R0 + R1 = 3(X + ZZ)(X - ZZ) = C + 17. R1 = R0 = C + + Output State: + R0 = FREE + R1 = C + R2 = A + R3 = FREE + R4 = FREE + + STEP 2: + */ + + CRYPTO_EXECUTE_17(crypto, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA4DDATA3, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 + ); + /* + STEP 3: + + Goals: + R->X = C^2 - 2A + D = C(A - R->X) + + Input State: + R0 = FREE + R1 = C + R2 = A + R3 = FREE + R4 = FREE + + Instructions to be executed: + + 1. R4 = R1 = C + 2. Select R1, R4 + 3. R0 = R1 * R4 = C^2 + 4. Select R0, R2 + 5. R0 = R0 - R2 = C^2 - 2A = R->X + 6. R4 = R0 = R->X + 7. Select R3, R4 + 8. R0 = R3 - R4 = A - R->X + 9. R2 = R0 = A - R->X + 10 Select R1, R2 + 11. R0 = R1 * R2 = C(A - R->X) = D + + Read Operations: + + R->X = R4 = C^2 - 2A + + Output State: + R0 = D + R1 = FREE + R2 = FREE + R3 = FREE + R4 = FREE + + STEP 3: + */ + CRYPTO_EXECUTE_15(crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_DDATA1TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL + ); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->X) ); + + /* + STEP 4: + + Goals: + B = 8 * Y^4 + R->Y = D - B + + Write Operations: + + R1 = YY + + Input State: + R0 = D + R1 = YY + R2 = FREE + R3 = FREE + R4 = FREE + + Instructions to be executed: + + 1. R3 = R0 = D + 2. R0 = DMA0 + 3. R1 = R0 = Y^2 + 4. R2 = R0 = Y^2 + 5. Select R1, R2 + 6. R0 = R1 * R2 = Y^4 + 7. Select R0, R0 + 8. R0 = R0 + R0 = 2 * Y^4 + 9. R0 = R0 + R0 = 4 * Y^4 + 10. R0 = R0 + R0 = 8 * Y^4 + 11. R2 = R0 + 12. Select R3, R2 + 13. R0 = R3 - R2 = D - B = R->Y + + Read Operations: + + R->Y = R0 = D - B + + STEP 4: + */ + CRYPTO_EXECUTE_11(crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + + CRYPTO_CMD_INSTR_SELDDATA3DDATA2, + CRYPTO_CMD_INSTR_MSUB + ); + CRYPTO_DDataWrite(&crypto->DDATA0, _2YY); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y) ); + +#else /* #if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + + ecc_bigint_t A; + ecc_bigint_t B; + ecc_bigint_t _2A; /* Represents 2A */ + + /* + + Goals: + B = 8 * Y1^4 + Y1Y1 = Y1² + + Write Operations: + + R1 = Y1 + + Instructions to be executed: + + 1. R2 = R1 = Y1 + 2. Select R1, R2 + 3. R0 = R1 * R2 = Y1² = Y1Y1 + 4. R1 = R0 = Y1² + 5. R2 = R0 = Y1² + 6. R0 = R1 * R2 = Y1^4 + 7. Select R0, R0 + 8. R0 = R0 + R0 = 2 * Y1^4 + 9. R0 = R0 + R0 = 4 * Y1^4 + 10 R0 = R0 + R0 = 8 * Y1^4 + + Read Operations: + + B = R0 = 8 * Y1^4 + Y1Y1 = R1 = Y1² + + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, &P->Y); + + CRYPTO_EXECUTE_10(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD + ); + + CRYPTO_DDataRead(&crypto->DDATA0, B); + + /* + Goals: + A = 4P1->X * Y1Y1 + _2A = 2A + + Write Operations: + + R0 = P1->X + R1 = Y1Y1 R1 already contains Y1Y1 + + Instructions to be executed: + + 1. Select R0, R0 + 2. R0 = R0 + R0 = 2P1->X + 3. R0 = R0 + R0 = 4P1->X + 4. R3 = R0 = 4P1->X + 5. Select R1, R3 + 6. R0 = R1 * R3 = 4P1->X * Y1Y1 = A + 7. R3 = R0 + 8. Select R0, R3 + 9. R0 = R0 + R3 = 2A = _2A + + Read Operations: + + A = R3 = 4P1->X + Y1Y1 + _2A = R0 = 2A + + */ + + ecp_crypto_ddata_write(&crypto->DDATA0, &P->X); + + CRYPTO_EXECUTE_9(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MADD + ); + + CRYPTO_DDataRead(&crypto->DDATA3, A); + CRYPTO_DDataRead(&crypto->DDATA0, _2A); + + /* + Goals: Z1Z1 = P1->Z² + + Write Operations: + + R1 = P1->Z + + Instructions to be executed: + + 1. R2 = R1 = P1->Z + 2. Select R1, R2 + 3. R0 = R1 * R2 = P1->Z^² = Z1Z1 + 4. R3 = R0 = Z1Z1 + + Read Operations: + + Z1Z1 = R0 = P1->Z² + + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, &P->Z); + + CRYPTO_EXECUTE_4(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3 + ); + + /* + Goal: C = 3(P1->X - Z1Z1)(P1->X + Z1Z1) + + Write Operations: + + R2 = P1->X + R3 = Z1Z1 Z1Z1 is already in R3 + + Instructions to be executed: + + 1. Select R2, R3 + 2. R0 = R2 + R3 = P1->X + Z1Z1 + 3. R1 = R0 = P1->X + Z1Z1 + 4. R0 = R2 - R3 = P1->X - Z1Z1 + 5. R2 = R0 = P1->X - Z1Z1 + 6. Select R1, R2 + 7. R0 = R1 * R2 = (P1->X + Z1Z1)(P1->X - Z1Z1) + 8. R1 = R0 = (P1->X + Z1Z1)(P1->X - Z1Z1) + 9. Select R0, R1 + 10. R0 = R0 + R1 = 2(P1->X + Z1Z1)(P1->X - Z1Z1) + 11. R0 = R0 + R1 = 3(P1->X + Z1Z1)(P1->X - Z1Z1) = C + 12. R1 = R0 = C + + Read Operations: + + C = R1 = 3(P1->X - Z1Z1)(P1->X + Z1Z1) + + */ + + ecp_crypto_ddata_write(&crypto->DDATA2, &P->X); + + CRYPTO_EXECUTE_12(crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA3, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 + ); + + /* + Goals: R->X = C² - _2A + D = C(A - R->X) + + Write Operations: + + R1 = C R1 already contains C + R2 = _2A + R3 = A + R4 = C + + Instructions to be executed: + + 1. R4 = R1 = C + 2. Select R1, R4 + 3. R0 = R1 * R4 = C² + 4. Select R0, R2 + 5. R0 = R0 - R2 = C² - _2A = R->X + 6. R4 = R0 = R->X + 7. Select R3, R4 + 8. R0 = R3 - R4 = A - R->X + 9. R2 = R0 = A - R->X + 10 Select R1, R2 + 11. R0 = R1 * R2 = C(A - R->X) = D + + Read Operations: + + D = R0 = C(A - R->X) + R->X = R4 = C² - _2A + + */ + + CRYPTO_DDataWrite(&crypto->DDATA2, _2A); + CRYPTO_DDataWrite(&crypto->DDATA3, A); + + CRYPTO_EXECUTE_11(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA3DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL + ); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA4, &R->X) ); + + /* + Goals: R->Y = D - B + R->Z = 2 * Y1 * P1->Z + + Write Operations: + + R0 = D R0 already contains D + R1 = Y1 + R2 = P1->Z + R3 = B + + Instructions to be executed: + + 1. Select R0, R3 + 2. R0 = R0 - R3 = D - B = R->Y + 3. R3 = R0 = R->Y + 4. Select R1, R2 + 5. R0 = R1 * R2 = Y1 * P1->Z + 6. Select R0, R0 + 7. R0 = R0 + R0 = 2 * Y1 * P1->Z = R->Z + + Read Operations: + + R->Z = R0 = 2*Y1*P1->Z + R->Y = R3 = D - B + + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, &P->Y); + ecp_crypto_ddata_write(&crypto->DDATA2, &P->Z); + CRYPTO_DDataWrite(&crypto->DDATA3, B); + + CRYPTO_EXECUTE_7(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD + ); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z) ); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA3, &R->Y) ); + +#endif /* #if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + + cleanup: + + CRYPTODRV_ExitCriticalRegion(p_cryptodrv_ctx); + + return( ret ); +} +#endif /* #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */ + +#if defined(MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT) +/* + * Alternative implementation of ecp_add_mixed using CRYPTO hardware + * acceleration. + * + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +int ecp_device_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; + CRYPTODRV_EnterCriticalRegion(p_cryptodrv_ctx); + +#if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + + /* + STEP 1: + + Goals: + A = Qx*Pz^2 + B = Qy*Pz^3 + + Write Operations: + + R0 = Pz + R0 = Qx + R0 = Qy + + Instructions to be executed: + + 1. R0 = DMA = Pz + 2. R1 = R0 = Pz + 3. R2 = R0 = Pz + 4. Select R1, R2 + 5. R0 = R1 * R2 = Pz^2 + 6. R1 = R0 = Pz^2 + + 7. R0 = DMA = Qx + 8. R3 = R0 = Qx + 9. Select R1, R3 + 10. R0 = R1 * R3 = Qx * Pz^2 + 11. R3 = R0 = Qx * Pz^2 + + 12. Select R1, R2 + 13. R0 = R1 * R2 = Pz^3 + 14. R1 = R0 = Pz^3 + + 15. R0 = DMA = Qy + 16. R4 = R0 = Qx + 17. Select R1, R4 + 18. R0 = R1 * R4 = Qy * Pz^3 + 19. Select R0, R1 (for MSUB in step 2) + + Output State: + R0 = B + R1 = FREE + R2 = FREE + R3 = A + R4 = Pz + + STEP 1: + */ + CRYPTO_EXECUTE_19(crypto, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1 + ); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z); + ecp_crypto_ddata_write(&crypto->DDATA0, &Q->X); + ecp_crypto_ddata_write(&crypto->DDATA0, &Q->Y); + + /* + STEP 2: + + Goals: + C = A - Px + D = B - Py + R->Z = Pz * C + + Write Operations: + + R1 = Py + R0 = Px (via DMA) + + Input State: + R0 = B + R1 = Py + R2 = FREE + R3 = A + R4 = Pz + + Instructions to be executed: + + 1. R0 = R0 - R2 = B - Py = D + 2. R2 = R0 = D + 3. R1 = R3 = A + 4. R0 = DMA = Px + 5. R3 = R0 = Px + 6. Select R1, R3 + 7. R0 = R1 - R3 = A - Px = C + 8. R1 = R0 = C + 9. Select R1, R4 + 10. R0 = R1 * R4 = Pz * C = R->Z + 11. R4 = R1 = C + + Read Operations: + + R->Z = R0 = Pz * C + + Output State: + R0 = FREE + R1 = C + R2 = D + R3 = Px + R4 = FREE + + STEP 2: + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, &P->Y); + CRYPTO_EXECUTE_11(crypto, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, /* R2 = D */ + + CRYPTO_CMD_INSTR_DDATA3TODDATA1, + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, /* R1 = C */ + + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA1TODDATA4 + ); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->X); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z) ); + + /* + STEP 3: + + Goals: + X1C2 = Px * C^2 + C3 = C^3 + D2 = D^2 + + Input State: + R0 = FREE + R1 = C + R2 = D + R3 = Px + R4 = FREE + + Instructions to be executed: + + 1. R0 = R1 * R4 = C^2 + 2. R1 = R0 = C^2 + 3. R0 = R1 * R4 = C^3 + 4. R4 = R0 = C^3 + 5. Select R1, R3 + 6. R0 = R1 * R3 = Px * C^2 + 7. R3 = R0 = Px * C^2 + 8. R1 = R2 = D + 9. Select R1, R1 + 10. R0 = R1 * R1 = D^2 + 11. Select R0, R4 (for MSUB operation in next sequence) + + Output state: + + R0 = D2 + R1 = FREE + R2 = D + R3 = X1C2 = Px * C^2 + R4 = C3 = C^3 + + STEP 3: + */ + CRYPTO_EXECUTE_11(crypto, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4 + ); + /* + STEP 3: + + Goals: + R->X = D2 - (C3 + 2 * X1C2) = D2 - C3 - X1C2- X1C2 + Y1C3 = Py * C3 + R->Y = D * (X1C2 - R->X) - Y1C3 + + Write Operations: + R1 = Py + + Input State: + R0 = D2 + R1 = FREE + R2 = D + R3 = X1C2 + R4 = C3 + + Instructions to be executed: + + 1. R0 = R0 - R4 = D2 - C3 + 2. Select R0, R3 + 3. R0 = R0 - R3 = D2 - C3 - X1C2 + 4. R0 = R0 - R3 = D2 - C3 - X1C2 - X1C2 = R->X + 5. DMA = R0 = R->X + 6. R1 = R0 = R->X + + 7. Select R3, R1 + 8. R0 = R3 - R1 = X1C2 - R->X + 9. R1 = R0 = X1C2 - R->X + 10. Select R1, R2 + 11. R0 = R1 * R2 = D *(X1C2 - R->X) + 12. R2 = R0 + + 13. R0 = DMA = Py + 14. R1 = R0 = Py + 15. Select R1, R4 + 16. R0 = R1 * R4 = Py * C3 = Y1C3 + 17. R4 = R0 = Y1C3 + + 18. Select R2, R4 + 19. R0 = R2 - R4 + + Read Operations: + + R->X = R2 = D2 - (C3 + 2 * X1C2) + R->Y = R0 = D * (X1C2 - R->X) - Y1C3 + + STEP 4: + */ + + CRYPTO_EXECUTE_19(crypto, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DATATODMA0, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + + CRYPTO_CMD_INSTR_SELDDATA3DDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + + CRYPTO_CMD_INSTR_DMA0TODATA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB + ); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->X) ); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y); + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y) ); + +#else /* #if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + + const mbedtls_mpi* Px = &P->X; + const mbedtls_mpi* Py = &P->Y; + const mbedtls_mpi* Pz = &P->Z; + const mbedtls_mpi* Qx = &Q->X; + const mbedtls_mpi* Qy = &Q->Y; + ecc_bigint_t D; + + /* + + Goals: + A = Qx*Pz^2 + B = Qy*Pz^3 + + Write Operations: + + R1 = Pz + R3 = Qx + R4 = Qy + + Instructions to be executed: + + 1. R2 = R1 = Pz + 2. Select R1, R2 + 2. R0 = R1 * R2 = Pz^2 + 3. R1 = R0 = Pz^2 + 4. Select R1, R3 + 5. R0 = R1 * R3 = Qx * Pz^2 + 6. R3 = R0 = Qx * Pz^2 + 7. Select R1, R2 + 8. R0 = R1 * R2 = Pz^3 + 1 9. R1 = R0 = Pz^3 + 10.Select R1, R4 + 11.R0 = R1 * R4 = Qy * Pz^3 + + Read Operations: + + B = R0 = Qy*Pz^3 + A = R3 = Qx*Pz^2 + + STEP 1: + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, Pz); + ecp_crypto_ddata_write(&crypto->DDATA3, Qx); + ecp_crypto_ddata_write(&crypto->DDATA4, Qy); + + CRYPTO_EXECUTE_12(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + /* + + Goals: C = A - Px + D = B - Py + R->Z = Pz * C + + Write Operations: + + R0 = B B is already in R0 + R1 = Px + R2 = Py + R3 = A A is already in R3 + R4 = Pz + + Instructions to be executed: + + 1. Select R0, R2 + 2. R0 = R0 - R2 = B - Py = D + 3. R2 = R0 = D + 4. Select R3, R1 + 5. R0 = R3 - R1 = A - Px = C + 6. R1 = R0 = C + 7. Select R1, R4 + 8. R0 = R1 * R4 = Pz * C = R->Z + + Read Operations: + + R->Z = R0 = Pz * C + C = R1 = A - Px + D = R2 = B - Py + + STEP 2: + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, Px); + ecp_crypto_ddata_write(&crypto->DDATA2, Py); + ecp_crypto_ddata_write(&crypto->DDATA4, Pz); + + CRYPTO_EXECUTE_8(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA3DDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z) ); + CRYPTO_DDataRead(&crypto->DDATA2, D); + + /* + + Goals: X1C2 = Px * C² + C3 = C³ + D2 = D² + + Write Operations: + + R1 = C C is already in R1 + R2 = D D is already in R2 + R3 = Px + + R4 = C + + Instructions to be executed: + + 1. Select R1, R4 + 2. R0 = R1 * R4 = C² + 3. R1 = R0 = C² + 4. R0 = R1 * R4 = C³ + 5. R4 = R0 = C³ + 6. Select R1, R3 + 7. R0 = R1 * R3 = Px * C^² + 8. R3 = R0 = Px * C² + 9. R1 = R2 = D + 10. Select R1, R1 + 11. R0 = R1 * R1 = D² + + Read Operations: + + D2 = R0 = D² + X1C2 = R3 = Px * C² + C3 = R4 = C³ + + STEP 3: + */ + + ecp_crypto_ddata_write(&crypto->DDATA3, Px); + CRYPTO_EXECUTE_12(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL + ); + + /* + Goals: R->X = D2 - (C3 + 2 * X1C2) = D2 - C3 - X1C2- X1C2 + Y1C3 = Py * C3 + + Write Operations: + + R0 = D2 D2 is already in R0 + R1 = Py + R3 = X1C2 X1C2 is already in R3 + R4 = C3 C3 is already in R4 + + Instructions to be executed: + + 1. Select R0, R4 + 2. R0 = R0 - R4 = D2 - C3 + 3. Select R0, R3 + 4. R0 = R0 - R3 = D2 - C3 - X1C2 + 5. R0 = R0 - R3 = D2 - C3 - X1C2 - X1C2 = R->X + 6. R2 = R0 = R->X + 7. Select R1, R4 + 8. R0 = R1 * R4 = Py * C3 = Y1C3 + + Read Operations: + + Y1C3 = R0 = Py * C³ + R->X = R2 = D2 - (C3 + 2 * X1C2) + + STEP 4: + */ + + ecp_crypto_ddata_write(&crypto->DDATA1, Py); + + CRYPTO_EXECUTE_8(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA2, &R->X) ); + + /* + Goal: R->Y = D * (X1C2 - R->X) - Y1C3 + + Write Operations: + + R1 = D + R2 = R->X R->X is already in R2 + R3 = X1C2 X1C2 is already in R3 + R4 = Y1C3 + + Instructions to be executed: + + 1. Select R3, R2 + 2. R0 = R3 - R2 = X1C2 - R->X + 3. R2 = R0 = X1C2 - R->X + 4. Select R1, R2 + 5. R0 = R1 * R2 = D *(X1C2 - R->X) + 6. Select R0, R4 + 7. R0 = R0 - R4 + + Read Operations: + + R->Y= R0 = D * (X1C2 - R->X) - Y1C3 + + STEP 5: + */ + + CRYPTO_DDataWrite(&crypto->DDATA1, D); + CRYPTO_EXECUTE_8(crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA3DDATA2, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_MSUB + ); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y) ); + +#endif /* #if !defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + + cleanup: + + CRYPTODRV_ExitCriticalRegion(p_cryptodrv_ctx); + + return( ret ); +} +#endif /* #if defined(MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT) */ + +#if defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) +/***************************************************************************//** + * @brief + * Modular division using CRYPTO hardware acceleration. + * + * @details + * This function computes R = X/Y mod(N) using CRYPTO hardware acceleration. + * The implementation is not a direct replacement plugin, i.e. alternative + * implementation, of an existing mbedtls function. This function is used + * internally in other CRYPTO plugin functions indirectly replacing + * mbedtls_mpi_inv_mod. + * + * @param[in] X Dividend of modular division operation + * @param[in] Y Divisor of modular division operation + * @param[in] N Modulus + * @param[out] R The destination of the result + * + * @return N/A + ******************************************************************************/ +static void mbedtls_mpi_div_mod(CRYPTO_TypeDef* crypto, + ecc_bigint_t X, + ecc_bigint_t Y, + ecc_bigint_t N, + ecc_bigint_t R) +{ + uint32_t D[9]; + uint32_t status_reg; + uint8_t rdata; + uint8_t lsb_C; + uint8_t lsb_D; + uint8_t lsb_U; + int t; + int k; + + /************** Initialize and organize data in crypto module **************/ + + /* + ** Register usage: + ** + ** DDATA0 - holds temporary results and loads 260 bit variables in/out + ** DDATA1 - variable referred to as 'C' in the following algorithm + ** DDATA2 - variable referred to as 'U' in the following algorithm + ** DDATA3 - variable referred to as 'D' in the following algorithm + ** DDATA4 - variable referred to as 'W' in the following algorithm + */ + + EC_BIGINT_COPY(D, N); /* D will hold the modulus (n) initially */ + D[8]=0; /* Set MSWord of D to 0. */ + + CRYPTO_DDataWrite(&crypto->DDATA1, Y); /* Set C to Y (divisor) initially */ + CRYPTO_DDataWrite(&crypto->DDATA2, X); /* Set U to X (dividend)initially */ + + CRYPTO_DDataWrite(&crypto->DDATA3, N); /* Set D to modulus p initially */ + + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_CLR, /* DDATA0 = 0 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA4, /* Set W to zero initially*/ + CRYPTO_CMD_INSTR_DDATA1TODDATA0);/* DDATA0 = C initially */ + + t = 0; + k = 1; + + /******************* Run main loop while 'C' is non-zero ********************/ + + /* while (C != 1024'd0) */ + while ( !crypto_ddata0_is_zero(crypto, &status_reg) ) + { + lsb_C = (status_reg & _CRYPTO_DSTATUS_DDATA0LSBS_MASK) >> _CRYPTO_DSTATUS_DDATA0LSBS_SHIFT; + if ((lsb_C & 0x1) == 0) + { + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA1, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 + ); + t = t-1; + } + else + { + if (t<0) + { + CRYPTO_EXECUTE_6(crypto, + CRYPTO_CMD_INSTR_DDATA2TODDATA0, + CRYPTO_CMD_INSTR_DDATA4TODDATA2, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_DDATA3TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA3); + CRYPTO_DDATA0_260_BITS_READ(crypto, D); + t = -t; + } + + k = 1; + + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_ADD); + + rdata = CRYPTO_DData0_4LSBitsRead(crypto); + + if((rdata & 0x3) != 0x0) + k = -1; + else + t = t-1; + + /* R1 = C >> 1 */ + crypto->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; /* to get the lsb of C */ + + lsb_C = CRYPTO_DData0_4LSBitsRead(crypto); + CRYPTO_EXECUTE_4(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA1, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA3TODDATA0); /* to get the lsb of D(R3) */ + + /* R3 = D >> 1 */ + lsb_D = CRYPTO_DData0_4LSBitsRead(crypto); + + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA3DDATA3, + CRYPTO_CMD_INSTR_SHRA); + + if(k == 1) + { + if (((lsb_C & 0x1)==0x1) && ((lsb_D & 0x1)==0x1)) + { + CRYPTO_EXECUTE_7(crypto, + /* C = R1+R3+1 */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_ADDC, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2+R4,n) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + else + { + CRYPTO_EXECUTE_6(crypto, + /* C = R1+R3 */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_ADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2+R4,n) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MADD, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + } + else + { + if (k == -1) + { + if (((lsb_C & 0x1)==0x0) && ((lsb_D & 0x1)==0x1)) + { + CRYPTO_EXECUTE_8(crypto, + /* C = R1-R3-1 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_SUBC, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2-R4,p) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + else + { + CRYPTO_EXECUTE_7(crypto, + /* C = R1+R3 */ + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_SUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + /* U = mod(R2-R4,p) */ + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + } + + CRYPTO_DDATA0_260_BITS_WRITE(crypto, D); + crypto->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA3; + + } /* if (k == -1) */ + } + } /* else: !if((C[31:0] & 0x1) == 0x0) */ + + crypto->CMD = CRYPTO_CMD_INSTR_DDATA2TODDATA0; + + lsb_U = CRYPTO_DData0_4LSBitsRead(crypto); + + /* if ((U[31:0] & 0x1) == 0x1) */ + if((lsb_U & 0x1) == 0x1) + { +#if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); + + CRYPTO_DDataWrite(&crypto->DDATA0, N); + CRYPTO_EXECUTE_6(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_SHR, + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_ADDC, + CRYPTO_CMD_INSTR_DDATA0TODDATA2 + ); +#else /* #if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + CRYPTO_EXECUTE_10(crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_DMA0TODATA, /* DDATA0 = N */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_SHR, + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_CSET, + CRYPTO_CMD_INSTR_ADDC, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); + + CRYPTO_DDataWrite(&crypto->DDATA0, N); +#endif /* #if defined( MBEDTLS_INCLUDE_IO_MODE_DMA ) */ + } + else + { + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); + } + + /* DDATA0 = C */ + crypto->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; + + } /* End of main loop: while (C != 0) */ + + /* if (D == 1): */ + /* Decrement D by 1 and test if zero. */ + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_DDATA3TODDATA0, + CRYPTO_CMD_INSTR_DEC); + + if (crypto_ddata0_is_zero(crypto, &status_reg)) + { + CRYPTO_DDataRead(&crypto->DDATA4, R); + } + else + { + CRYPTO_DDataWrite(&crypto->DDATA0, N); + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_SUB + ); + CRYPTO_DDataRead(&crypto->DDATA0, R); + } + + return; +} /* mbedtls_mpi_div_mod */ +#endif /* #if defined( MBEDTLS_MPI_MODULAR_DIVISION_ALT ) */ + +#if defined( MBEDTLS_ECP_NORMALIZE_JAC_ALT ) +/* + * Alternative implementation of ecp_normalize_jac using CRYPTO hardware + * acceleration. + * + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + */ +int ecp_device_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret = 0; + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; + CRYPTODRV_EnterCriticalRegion(p_cryptodrv_ctx); + +#if defined( MBEDTLS_MPI_MODULAR_DIVISION_ALT ) + + ecc_bigint_t one; + ecc_bigint_t Z; + ecc_bigint_t modulus; + ecc_bigint_t Z_inv; + + memset(one, 0, sizeof(one)); + one[0]=1; + + MPI_TO_BIGINT( Z, &P->Z ); + MPI_TO_BIGINT( modulus, &grp->P ); + + mbedtls_mpi_div_mod(crypto, one, Z, modulus, Z_inv); + + CRYPTO_DDataWrite(&crypto->DDATA1, Z_inv); + +#else + + mbedtls_mpi Z_inv; + mbedtls_mpi_init( &Z_inv ); + + /* + * Z_inv = 1 / Z mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Z_inv, &P->Z, &grp->P ) ); + + ecp_crypto_ddata_write(&crypto->DDATA1, &Z_inv); +#endif + + /* + + Goals: + R->X = P->X * Z_inv ^2 + R->Y = P->Y * Z_inv ^3 + + Write Operations: + + R1 = Z_inv + R3 = P->X + R4 = P->Y + + Instructions to be executed: + + 1. R2 = R1 = Z_inv + 2. Select R1, R2 + 3. R0 = R1 * R2 = Z_inv^2 + 4. R1 = R0 = Z_inv^2 + 5. Select R1, R3 + 6. R0 = R1 * R3 = P->X * Z_inv^2 = R->X + 7. R3 = R0 + 8. Select R1, R2 + 9. R0 = R1 * R2 = Z_inv^3 + 10. R1 = R0 = Z_inv^3 + 11. Select R1, R4 + 12. R0 = R1 * R4 = P->Y * Z_inv^3 = R->Y + + Read Operations: + + R->Y = R0 = P->Y * P->Z_inv^3 + R->X = R3 = P->X * P->Z_inv^2 + + */ + + ecp_crypto_ddata_write(&crypto->DDATA3, &P->X); + ecp_crypto_ddata_write(&crypto->DDATA4, &P->Y); + + CRYPTO_EXECUTE_12(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + ecp_crypto_ddata_read(&crypto->DDATA0, &P->Y); + ecp_crypto_ddata_read(&crypto->DDATA3, &P->X); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + + cleanup: + + CRYPTODRV_ExitCriticalRegion(p_cryptodrv_ctx); + +#if !defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) + mbedtls_mpi_free( &Z_inv ); +#endif /* #if !defined(MBEDTLS_MPI_MODULAR_DIVISION_ALT) */ + + return( ret ); +} +#endif /* #if defined( MBEDTLS_ECP_NORMALIZE_JAC_ALT ) */ + +#if defined( MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT ) +/* + * Alternative implementation of ecp_normalize_jac_many using + * CRYPTO hardware acceleration. + * + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + */ +int ecp_device_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ) +{ + int ret; + size_t i; + ecc_bigint_t* cc; + ecc_bigint_t uu; + ecc_bigint_t one; + ecc_bigint_t modulus; + CRYPTODRV_Context_t* p_cryptodrv_ctx = + (CRYPTODRV_Context_t*)&grp->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = p_cryptodrv_ctx->device->crypto; + + if( t_len < 2 ) + return( ecp_device_normalize_jac( grp, *T ) ); + + if( ( cc = mbedtls_calloc( t_len, sizeof( ecc_bigint_t ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + CRYPTODRV_EnterCriticalRegion(p_cryptodrv_ctx); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MPI_TO_BIGINT( cc[0], &T[0]->Z ); + for( i = 1; i < t_len; i++ ) + { + ecp_crypto_ddata_write( &crypto->DDATA1, &T[i]->Z ); + CRYPTO_DDataWrite( &crypto->DDATA2, cc[i-1] ); + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_DDataRead( &crypto->DDATA0, cc[i] ); + } + + memset(one, 0, sizeof(one)); + one[0]=1; + MPI_TO_BIGINT( modulus, &grp->P ); + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + mbedtls_mpi_div_mod(crypto, one, cc[t_len-1], modulus, uu); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) + { + /* Z_inv (DDATA2) = uu */ + CRYPTO_DDataWrite(&crypto->DDATA2, uu); + } + else + { + /* Z_inv (DDATA1) = uu x cc[i-1] modulo p */ + /* uu = uu x T[i]->Z modulo p */ + CRYPTO_DDataWrite(&crypto->DDATA1, uu); + CRYPTO_DDataWrite(&crypto->DDATA2, cc[i-1]); + ecp_crypto_ddata_write( &crypto->DDATA3, &T[i]->Z ); + CRYPTO_EXECUTE_5(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, /* Z_inv (DDATA2) */ + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_DDataRead(&crypto->DDATA0, uu); + } + + /* + * proceed as in normalize() + */ + ecp_crypto_ddata_write(&crypto->DDATA3, &T[i]->X); + ecp_crypto_ddata_write(&crypto->DDATA4, &T[i]->Y); + + /* Z_inv already in DDATA2 */ + CRYPTO_EXECUTE_12(crypto, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL + ); + + ecp_crypto_ddata_read(&crypto->DDATA0, &T[i]->Y); + ecp_crypto_ddata_read(&crypto->DDATA3, &T[i]->X); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + + cleanup: + + CRYPTODRV_ExitCriticalRegion(p_cryptodrv_ctx); + + mbedtls_free( cc ); + + return( ret ); +} +#endif /* #if defined( MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT ) */ + +#endif /* #if defined( CRYPTO_COUNT ) && ( CRYPTO_COUNT > 0 ) */ + +#endif /* #if defined( MBEDTLS_SLCL_PLUGINS ) */ + +#endif /* #if defined( MBEDTLS_ECP_DEVICE_ALT ) */ + +#endif /* #if defined( MBEDTLS_ECP_C ) */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha1.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha1.c new file mode 100644 index 00000000000..e74d4194623 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha1.c @@ -0,0 +1,387 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes an alternative implementation of the standard + * mbedtls/libary/sha1.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#if defined(MBEDTLS_SHA1_ALT) + +#if defined(MBEDTLS_SLCL_PLUGINS) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "mbedtls/sha1.h" +#include "cryptodrv_internal.h" +#include "em_assert.h" +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); + + /* Set device instance to 0 by default. */ + mbedtls_sha1_set_device_instance(ctx, 0); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +/* + * Set the device instance of an SHA context. + */ +int mbedtls_sha1_set_device_instance(mbedtls_sha1_context *ctx, + unsigned int devno) +{ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_SHA1_BAD_INPUT ); + + return cryptodrvSetDeviceInstance( &ctx->cryptodrv_ctx, devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +/** + * \brief SHA-1 asynchronous context structure + */ +typedef struct +{ + mbedtls_asynch_callback asynch_callback; /*!< Completion callback + function pointer. */ + void* asynch_callback_user_arg; /*!< User defined parameter to + completion callback. */ +} +mbedtls_sha1_asynch_context; + +/** + * \brief Set an SHA1 context in asynchronous mode. + * + * \details + * This function enables or disables asynchronous (non-blocking) mode of an + * SHA1 context. In order to enable, the user must set the + * @p asynch_ctx parameter to point to an asynchronous sha1 context structure + * @ref mbedtls_sha1_asynch_context. Subsequent calls to the SHA1 API + * functions with the specified context will behave asynchronously, i.e. + * initiate the hardware to execute the operation and return as soon as + * possible. The user may specify a callback function by setting the + * @p asynch_callback parameter which will called when the operation has + * completed. + * In order to disable, the user must set the @p asynch_context parameter + * to NULL. All subsequent calls to SHA1 API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * \param ctx SHA1 context + * \param asynch_ctx SHA1 asynchronous context structure + * \param asynch_callback Asynchronous callback + * \param user_arg User specific argument which will be + * sent to callback. + * + * \return 0 if successful, or error code + */ +int mbedtls_sha1_set_asynch( mbedtls_sha1_context *ctx, + mbedtls_sha1_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* asynch_callback_user_arg ) +{ + (void) ctx; + (void) asynch_ctx; + (void) asynch_callback; + (void) asynch_callback_user_arg; + + /* Asynchronous mode is not supported yet. */ + while(1); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + (void) dst; + (void) src; + + /* Cloning a SHA256 CRYPTODRV context is not supported. */ + while(1); +} + +/* + * SHA-1 context setup + */ +int mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + uint32_t init_state[8]; + Ecode_t ecode; + + /* Request CRYPTO usage. */ + ecode = CRYPTODRV_Arbitrate(cryptodrv_ctx); + if (ECODE_OK != ecode) + { + return ecode; + } + + /* Enter critial crypto region in order to initialize crypto for + SHA operation. */ + ecode = CRYPTODRV_EnterCriticalRegion(cryptodrv_ctx); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Setup CRYPTO for SHA-1 operation: */ + crypto->CTRL = CRYPTO_CTRL_SHA_SHA1; + crypto->WAC = 0; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits); + + /* Clear sequence control registers */ + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Setup the initial sha digest state */ + init_state[0] = 0x67452301; + init_state[1] = 0xEFCDAB89; + init_state[2] = 0x98BADCFE; + init_state[3] = 0x10325476; + init_state[4] = 0xC3D2E1F0; + init_state[5] = 0x0; + init_state[6] = 0x0; + init_state[7] = 0x0; + + /* Push init vector to crypto module */ + CRYPTO_DDataWrite(&crypto->DDATA1, init_state); + + /* Initialize CRYPTO sequencer to execute main SHA instruction + sequence. */ + CRYPTO_EXECUTE_3( crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1 ); + + /* Load main SHA instruction sequence */ + CRYPTO_SEQ_LOAD_3( crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 ); + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ + + ctx->total[0] = 0; + ctx->total[1] = 0; + + return ( ECODE_OK == ecode ? 0 : (int)ecode ); +} + +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + Ecode_t ecode; + + ecode = CRYPTODRV_EnterCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Write block to QDATA1. */ + /* Check data is 32bit aligned, if not move via aligned buffer before writing. */ + if ((uint32_t)data & 0x3) + { + uint32_t temp[16]; + memcpy(temp, data, 64); + CRYPTO_QDataWrite(&crypto->QDATA1BIG, temp); + } + else + { + CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t*) data); + } + + /* Execute SHA */ + crypto->CMD |= CRYPTO_CMD_SEQSTART; + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ +} + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + Ecode_t ecode; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + /* Enter critical CRYPTO region in order to read final SHA digest/state. */ + ecode = CRYPTODRV_EnterCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Read the digest from crypto (big endian). */ + ((uint32_t*)output)[0] = crypto->DDATA0BIG; + ((uint32_t*)output)[1] = crypto->DDATA0BIG; + ((uint32_t*)output)[2] = crypto->DDATA0BIG; + ((uint32_t*)output)[3] = crypto->DDATA0BIG; + ((uint32_t*)output)[4] = crypto->DDATA0BIG; + { + /* Read 3 remaining 32-bit words from DDATA0BIG (shift register). */ + volatile uint32_t temp; + temp = crypto->DDATA0BIG; + temp = crypto->DDATA0BIG; + temp = crypto->DDATA0BIG; + (void) temp; + } + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ + + /* Finally release CRYPTO since SHA operation has completed. */ + ecode = CRYPTODRV_Release( cryptodrv_ctx ); + + EFM_ASSERT(ECODE_OK == ecode); /* Assert crypto release is ok. */ +} + +/* + * output = SHA-1( input buffer ) + */ +int mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + mbedtls_sha1_context ctx; + int ret; + + mbedtls_sha1_init( &ctx ); + + ret = mbedtls_sha1_starts( &ctx ); + if (ret != 0) + return ret; + + mbedtls_sha1_update( &ctx, input, ilen ); + mbedtls_sha1_finish( &ctx, output ); + mbedtls_sha1_free( &ctx ); + + return( 0 ); +} + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* #if defined(MBEDTLS_SLCL_PLUGINS) */ + +#endif /* MBEDTLS_SHA1_ALT */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha256.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha256.c new file mode 100644 index 00000000000..3636670643e --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/sl_crypto/src/slcl_sha256.c @@ -0,0 +1,398 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This file includes an alternative implementation of the standard + * mbedtls/libary/sha256.c using the CRYPTO hardware accelerator incorporated + * in MCU devices from Silicon Laboratories. + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#if defined(MBEDTLS_SHA256_ALT) + +#if defined(MBEDTLS_SLCL_PLUGINS) + +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "mbedtls/sha256.h" +#include "cryptodrv_internal.h" +#include "em_assert.h" +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); + + /* Set device instance to 0 by default. */ + mbedtls_sha256_set_device_instance(ctx, 0); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +/* + * Set the device instance of an SHA context. + */ +int mbedtls_sha256_set_device_instance(mbedtls_sha256_context *ctx, + unsigned int devno) +{ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + if (devno > CRYPTO_COUNT) + return( MBEDTLS_ERR_SHA256_BAD_INPUT ); + + return cryptodrvSetDeviceInstance( &ctx->cryptodrv_ctx, devno ); +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ +} + +/** + * \brief SHA-256 asynchronous context structure + */ +typedef struct +{ + mbedtls_asynch_callback asynch_callback; /*!< Completion callback + function pointer. */ + void* asynch_callback_user_arg; /*!< User defined parameter to + completion callback. */ +} +mbedtls_sha256_asynch_context; + +/** + * \brief Set an SHA256 context in asynchronous mode. + * + * \details + * This function enables or disables asynchronous (non-blocking) mode of an + * SHA256 context. In order to enable, the user must set the + * @p asynch_ctx parameter to point to an asynchronous sha256 context + * structure @ref mbedtls_sha256_asynch_context. Subsequent calls to the + * SHA256 API functions with the specified context will behave asynchronously, + * i.e. initiate the hardware to execute the operation and return as soon as + * possible. The user may specify a callback function by setting the + * @p asynch_callback parameter which will called when the operation has + * completed. + * In order to disable, the user must set the @p asynch_context parameter + * to NULL. All subsequent calls to SHA256 API functions with the specified + * context will block until the corresponding operation has completed, and + * then return. + * + * \param ctx SHA256 context + * \param asynch_ctx SHA256 asynchronous context structure + * \param asynch_callback Asynchronous callback + * \param user_arg User specific argument which will be + * sent to callback. + * + * \return 0 if successful, or error code + */ +int mbedtls_sha256_set_asynch( mbedtls_sha256_context *ctx, + mbedtls_sha256_asynch_context *asynch_ctx, + mbedtls_asynch_callback asynch_callback, + void* asynch_callback_user_arg ) +{ + (void) ctx; + (void) asynch_ctx; + (void) asynch_callback; + (void) asynch_callback_user_arg; + + /* Asynchronous mode is not supported yet. */ + while(1); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + (void) dst; + (void) src; + + /* Cloning a SHA256 CRYPTODRV context is not supported. */ + while(1); +} + +/* + * SHA-256 context setup + */ +int mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + uint32_t init_state[8]; + Ecode_t ecode; + + /* Request CRYPTO usage. */ + ecode = CRYPTODRV_Arbitrate(cryptodrv_ctx); + if (ECODE_OK != ecode) + { + return ecode; + } + + /* Enter critial crypto region in order to initialize crypto for + SHA operation. */ + ecode = CRYPTODRV_EnterCriticalRegion(cryptodrv_ctx); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Setup CRYPTO for SHA-2 operation: */ + crypto->CTRL = CRYPTO_CTRL_SHA_SHA2; + crypto->WAC = 0; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits); + + /* Clear sequence control registers */ + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Setup the initial sha digest state */ + if( is224 == 0 ) + { + /* SHA-256 */ + init_state[0] = 0x6A09E667; + init_state[1] = 0xBB67AE85; + init_state[2] = 0x3C6EF372; + init_state[3] = 0xA54FF53A; + init_state[4] = 0x510E527F; + init_state[5] = 0x9B05688C; + init_state[6] = 0x1F83D9AB; + init_state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + init_state[0] = 0xC1059ED8; + init_state[1] = 0x367CD507; + init_state[2] = 0x3070DD17; + init_state[3] = 0xF70E5939; + init_state[4] = 0xFFC00B31; + init_state[5] = 0x68581511; + init_state[6] = 0x64F98FA7; + init_state[7] = 0xBEFA4FA4; + } + + /* Push init vector to crypto module */ + CRYPTO_DDataWrite(&crypto->DDATA1, init_state); + + /* Initialize CRYPTO sequencer to execute main SHA instruction + sequence. */ + CRYPTO_EXECUTE_3( crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1 ); + + /* Load main SHA instruction sequence */ + CRYPTO_SEQ_LOAD_3( crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 ); + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ + + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->is224 = is224; + + return ( ECODE_OK == ecode ? 0 : (int)ecode ); +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + Ecode_t ecode; + + ecode = CRYPTODRV_EnterCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Write block to QDATA1. */ + /* Check data is 32bit aligned, if not move via aligned buffer before writing. */ + if ((uint32_t)data & 0x3) + { + uint32_t temp[16]; + memcpy(temp, data, 64); + CRYPTO_QDataWrite(&crypto->QDATA1BIG, temp); + } + else + { + CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t*) data); + } + + /* Execute SHA */ + crypto->CMD |= CRYPTO_CMD_SEQSTART; + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ +} + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + CRYPTODRV_Context_t* cryptodrv_ctx = &ctx->cryptodrv_ctx; + CRYPTO_TypeDef* crypto = cryptodrv_ctx->device->crypto; + Ecode_t ecode; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + /* Enter critical CRYPTO region in order to read final SHA digest/state. */ + ecode = CRYPTODRV_EnterCriticalRegion( cryptodrv_ctx ); + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region entry is ok. */ + + /* Read the digest from crypto (big endian). */ + CRYPTODRV_DDataReadUnaligned(&crypto->DDATA0BIG, output); + + ecode = CRYPTODRV_ExitCriticalRegion( cryptodrv_ctx ); + + EFM_ASSERT(ECODE_OK == ecode); /* Assert critical region exit is ok. */ + + /* Finally release CRYPTO since SHA operation has completed. */ + ecode = CRYPTODRV_Release( cryptodrv_ctx ); + + EFM_ASSERT(ECODE_OK == ecode); /* Assert crypto release is ok. */ + + if( ctx->is224 ) + memset(&output[28], 0, 4); +} + +/* + * output = SHA-256( input buffer ) + */ +int mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_sha256_context ctx; + int ret; + + mbedtls_sha256_init( &ctx ); + + ret = mbedtls_sha256_starts( &ctx, is224 ); + if (ret != 0) + return ret; + + mbedtls_sha256_update( &ctx, input, ilen ); + mbedtls_sha256_finish( &ctx, output ); + mbedtls_sha256_free( &ctx ); + + return( 0 ); +} + +#endif /* #if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ + +#endif /* #if defined(MBEDTLS_SLCL_PLUGINS) */ + +#endif /* #if defined(MBEDTLS_SHA256_ALT) */ + +#endif /* #if defined(MBEDTLS_SHA256_C) */