diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/aes_aes.c b/features/mbedtls/targets/TARGET_Silicon_Labs/aes_aes.c new file mode 100644 index 00000000000..822c7e6f468 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/aes_aes.c @@ -0,0 +1,466 @@ +/* + * Hardware-accelerated AES implementation for Silicon Labs devices + * containing an AES peripheral. + * + * Copyright 2017, Silicon Laboratories, Inc. + * 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 "mbedtls/aes.h" +#include "em_device.h" + +#if defined(AES_PRESENT) && (AES_COUNT == 1) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_AES_ALT) +#include "em_aes.h" +#include "em_cmu.h" +#include "em_bus.h" +#include + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#include "em_core.h" +/* Mutex for protecting access to the AES instance */ +static mbedtls_threading_mutex_t aes_mutex; +static volatile bool aes_mutex_inited = false; +#endif + +static void aes_lock( void ) +{ +#if defined(MBEDTLS_THREADING_C) + if ( !aes_mutex_inited ) { + /* Turn off interrupts that can cause preemption */ + CORE_irqState_t critical_irq_state = CORE_EnterCritical(); + if ( !aes_mutex_inited ) { + mbedtls_mutex_init(&aes_mutex); + aes_mutex_inited = true; + } + CORE_ExitCritical(critical_irq_state); + } + mbedtls_mutex_lock(&aes_mutex); +#endif + BUS_RegBitWrite(&(CMU->HFCORECLKEN0), _CMU_HFCORECLKEN0_AES_SHIFT, 1); + return; +} + +static void aes_unlock( void ) +{ +#if defined(MBEDTLS_THREADING_C) + if ( aes_mutex_inited ) { + mbedtls_mutex_unlock(&aes_mutex); + } +#endif + BUS_RegBitWrite(&(CMU->HFCORECLKEN0), _CMU_HFCORECLKEN0_AES_SHIFT, 0); + return; +} + +/* + * Initialize AES context + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +/* + * Clear AES context + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + memset( ctx, 0, 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; + switch (keybits) + { + case 128: + aes_lock(); + AES_DecryptKey128( ctx->key, key ); + aes_unlock(); + break; + case 256: + aes_lock(); + AES_DecryptKey256( ctx->key, key ); + aes_unlock(); + break; + default: + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + return 0; +} + +/* + * AES-ECB block encryption + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, input, output); +} + +/* + * AES-ECB block decryption + */ +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_DECRYPT, input, output); +} + +/* + * 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] ) +{ + switch ( ctx->keybits ) + { + case 128: + aes_lock(); + AES_ECB128( output, + input, + 16, + ctx->key, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + case 256: + aes_lock(); + AES_ECB256( output, + input, + 16, + ctx->key, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + default: + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + return( 0 ); +} + +#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 ) +{ + uint8_t tmpIv[16]; + + if( length % 16 ) + { + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( mode == MBEDTLS_AES_DECRYPT ) + { + if ( length >= 16 ) + memcpy( tmpIv, &input[length-16], 16 ); + } + + switch ( ctx->keybits ) + { + case 128: + aes_lock(); + AES_CBC128( output, + input, + length, + ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + case 256: + aes_lock(); + AES_CBC256( output, + input, + length, + ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + default: + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( length >= 16 ) + { + if ( mode == MBEDTLS_AES_ENCRYPT ) + memcpy( iv, &output[length-16], 16 ); + else + memcpy( iv, tmpIv, 16 ); + } + + return( 0 ); +} +#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 != NULL ) ? *iv_off : 0; + + if ( ( n > 0 ) || ( length & 0xf ) ) + { + // IV offset or length not aligned to block size + int c; + + 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 + { + switch( ctx->keybits ) + { + case 128: + aes_lock(); + AES_CFB128(output, + input, + length, + ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + + case 256: + aes_lock(); + AES_CFB256(output, + input, + length, + ctx->key, + iv, + mode == MBEDTLS_AES_ENCRYPT ? true : false ); + aes_unlock(); + break; + + default: + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + return( 0 ); + } +} + +/* + * 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]; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + 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 ); + } + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR Nonce update function + */ +static void aes_ctr_update_nonce( uint8_t *nonce_counter ) +{ + for( size_t i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; +} + +/* + * 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 != NULL ) ? *nc_off : 0; + + if ( ( n > 0 ) || ( length & 0xf ) ) + { + // IV offset or length not aligned to block size + int c, i; + + 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 + { + switch( ctx->keybits ) + { + case 128: + aes_lock(); + AES_CTR128( output, + input, + length, + ctx->key, + nonce_counter, + &aes_ctr_update_nonce ); + aes_unlock(); + break; + + case 256: + aes_lock(); + AES_CTR256( output, + input, + length, + ctx->key, + nonce_counter, + &aes_ctr_update_nonce ); + aes_unlock(); + break; + + default: + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + break; + } + + return( 0 ); + } +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* MBEDTLS_AES_ALT */ +#endif /* MBEDTLS_AES_C */ +#endif /* AES_PRESENT && (AES_COUNT == 1) */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/aes_alt.h b/features/mbedtls/targets/TARGET_Silicon_Labs/aes_alt.h new file mode 100644 index 00000000000..6b18a334e64 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/aes_alt.h @@ -0,0 +1,318 @@ +/* + * AES block cipher + * + * Copyright (C) 2015-2017, 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 + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_aes AES block cipher + * \brief Hardware accelerated AES block cipher. + * \{ + ******************************************************************************/ + +#if defined(MBEDTLS_AES_ALT) +/* SiliconLabs CRYPTO hardware acceleration implementation */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES context structure + */ +typedef struct +{ + unsigned int keybits; /*!< size of key */ + unsigned char key[32]; /*!< 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 ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128 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 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 + * + * \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 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 */ + +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + * + * \return 0 if successful + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + * + * \return 0 if successful + */ +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \deprecated Superseded by mbedtls_aes_encrypt_ext() in 2.5.0 + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + */ +MBEDTLS_DEPRECATED static inline void mbedtls_aes_encrypt( + mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_encrypt( ctx, input, output ); +} + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \deprecated Superseded by mbedtls_aes_decrypt_ext() in 2.5.0 + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + */ +MBEDTLS_DEPRECATED static inline void mbedtls_aes_decrypt( + mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_decrypt( ctx, input, output ); +} + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_AES_ALT */ + +/** \} (end addtogroup sl_crypto_aes) */ +/** \} (end addtogroup sl_crypto) */ + +#endif /* MBEDTLS_AES_ALT_H */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_aes.c b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_aes.c new file mode 100644 index 00000000000..8b3c75aba58 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_aes.c @@ -0,0 +1,557 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2017, 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 + */ + +#include "mbedtls/aes.h" +#include "em_device.h" + +#if defined(CRYPTO_PRESENT) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_AES_ALT) + +#include "crypto_management.h" +#include "em_crypto.h" +#include "em_core.h" +#include + +__STATIC_INLINE void CRYPTO_DataReadUnaligned(volatile uint32_t * reg, + uint8_t * const 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* const)val); + } +} + +__STATIC_INLINE void CRYPTO_DataWriteUnaligned(volatile uint32_t * reg, + uint8_t * const 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* const)val); + } +} + +/* + * Initialize AES context + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +/* + * Clear AES context + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + + memset( ctx, 0, 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( ctx == NULL || key == NULL ) { + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ( 128UL != keybits ) && ( 256UL != 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 ) +{ + CORE_DECLARE_IRQ_STATE; + + if( ctx == NULL || key == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ( 128UL != keybits ) && ( 256UL != keybits ) ) { + /* Unsupported key size */ + return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + ctx->keybits = keybits; + + CRYPTO_TypeDef *device = crypto_management_acquire(); + device->WAC = 0; + device->CTRL = 0; + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyBufWrite(device, (uint32_t*)key, (keybits == 128) ? cryptoKey128Bits : cryptoKey256Bits); + CORE_EXIT_CRITICAL(); + + /* Busy-wait here to allow context-switching to occur */ + device->CMD = CRYPTO_CMD_INSTR_AESENC; + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyRead(device, (uint32_t*)ctx->key, (keybits == 128) ? cryptoKey128Bits : cryptoKey256Bits); + CORE_EXIT_CRITICAL(); + + crypto_management_release(device); + + return 0; +} + +/* TODO: underneath these, we should swap out the em_crypto-provided library + * functions with in-place implemented functions, to get much shorter + * critical sections */ + +/* + * AES-ECB block encryption + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, input, output); +} + +/* + * AES-ECB block decryption + */ +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_DECRYPT, input, output); +} + +/* + * 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; + CORE_DECLARE_IRQ_STATE; + + if( ctx == NULL || input == NULL || output == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ctx->keybits != 128UL && ctx->keybits != 256UL) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + CRYPTO_TypeDef *device = crypto_management_acquire(); + device->WAC = 0; + device->CTRL = 0; + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyBufWrite(device, (uint32_t*)ctx->key, (ctx->keybits == 128UL) ? cryptoKey128Bits : cryptoKey256Bits); + CRYPTO_DataWriteUnaligned(&device->DATA0, (uint8_t *)input); + CORE_EXIT_CRITICAL(); + + if ( mode == MBEDTLS_AES_ENCRYPT ) { + device->CMD = CRYPTO_CMD_INSTR_AESENC; + } else { + device->CMD = CRYPTO_CMD_INSTR_AESDEC; + } + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)output); + CORE_EXIT_CRITICAL(); + + crypto_management_release(device); + + 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; + CORE_DECLARE_IRQ_STATE; + size_t processed = 0; + + if( ctx == NULL || input == NULL || output == NULL || iv == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + /* 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 ); + } + + if ( ctx->keybits != 128UL && ctx->keybits != 256UL) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + CRYPTO_TypeDef *device = crypto_management_acquire(); + device->WAC = 0; + device->CTRL = 0; + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyBufWrite(device, (uint32_t*)ctx->key, (ctx->keybits == 128UL) ? cryptoKey128Bits : cryptoKey256Bits); + if ( mode == MBEDTLS_AES_ENCRYPT ) { + CRYPTO_DataWriteUnaligned(&device->DATA0, (uint8_t *)iv); + } else { + CRYPTO_DataWriteUnaligned(&device->DATA2, (uint8_t *)iv); + } + CORE_EXIT_CRITICAL(); + + while ( processed < length ) { + if ( mode == MBEDTLS_AES_ENCRYPT ) { + CORE_ENTER_CRITICAL(); + CRYPTO_DataWriteUnaligned(&device->DATA0XOR, (uint8_t *)(&input[processed])); + device->CMD = CRYPTO_CMD_INSTR_AESENC; + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)(&output[processed])); + CORE_EXIT_CRITICAL(); + } else { + /* Decrypt input block, XOR IV to decrypted text, set ciphertext as next IV */ + CORE_ENTER_CRITICAL(); + CRYPTO_DataWriteUnaligned(&device->DATA0, (uint8_t *)(&input[processed])); + CRYPTO_EXECUTE_4( device, + CRYPTO_CMD_INSTR_DATA0TODATA1, + CRYPTO_CMD_INSTR_AESDEC, + CRYPTO_CMD_INSTR_DATA2TODATA0XOR, + CRYPTO_CMD_INSTR_DATA1TODATA2); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)(&output[processed])); + CORE_EXIT_CRITICAL(); + } + processed += 16; + } + + if ( processed >= 16 ) { + if ( mode == MBEDTLS_AES_ENCRYPT ) { + memcpy(iv, &output[processed-16], 16); + } else { + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA2, (uint8_t *)(iv)); + CORE_EXIT_CRITICAL(); + } + } + + crypto_management_release(device); + + 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; + size_t processed = 0; + int ret = 0; + CORE_DECLARE_IRQ_STATE; + + if( ctx == NULL || input == NULL || output == NULL || iv == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ctx->keybits != 128UL && ctx->keybits != 256UL) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + while ( processed < length ) { + if ( n > 0 ) { + /* start by filling up the IV */ + if( mode == MBEDTLS_AES_ENCRYPT ) { + iv[n] = output[processed] = (unsigned char)( iv[n] ^ input[processed] ); + } else { + int c = input[processed]; + output[processed] = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + } + n = ( n + 1 ) & 0x0F; + processed++; + continue; + } else { + /* process one ore more blocks of data */ + CRYPTO_TypeDef *device = crypto_management_acquire(); + device->WAC = 0; + device->CTRL = 0; + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyBufWrite(device, (uint32_t*)ctx->key, (ctx->keybits == 128UL) ? cryptoKey128Bits : cryptoKey256Bits); + CRYPTO_DataWriteUnaligned(&device->DATA0, (uint8_t *)iv); + CORE_EXIT_CRITICAL(); + + /* Encryption: encrypt IV, encIV xor input -> output and IV */ + /* Decryption: encrypt IV, encIV xor input -> output, input -> IV */ + size_t iterations = (length - processed) / 16; + for (size_t i = 0; i < iterations; i++ ) { + device->CMD = CRYPTO_CMD_INSTR_AESENC; + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + + CORE_ENTER_CRITICAL(); + if ( mode == MBEDTLS_AES_ENCRYPT ) { + CRYPTO_DataWriteUnaligned(&device->DATA0XOR, (uint8_t *)(&input[processed])); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)(&output[processed])); + } else { + CRYPTO_DataWriteUnaligned(&device->DATA1, (uint8_t *)(&input[processed])); + device->CMD = CRYPTO_CMD_INSTR_DATA1TODATA0XOR; + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)(&output[processed])); + device->CMD = CRYPTO_CMD_INSTR_DATA1TODATA0; + } + CORE_EXIT_CRITICAL(); + processed += 16; + } + + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)iv); + CORE_EXIT_CRITICAL(); + + while ( length - processed > 0 ) { + if ( n == 0 ) { + device->CMD = CRYPTO_CMD_INSTR_AESENC; + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)iv); + CORE_EXIT_CRITICAL(); + } + /* Save remainder to iv */ + if( mode == MBEDTLS_AES_ENCRYPT ) { + iv[n] = output[processed] = (unsigned char)( iv[n] ^ input[processed] ); + } else { + int c = input[processed]; + output[processed] = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + } + n = ( n + 1 ) & 0x0F; + processed++; + } + + crypto_management_release(device); + } + } + + if ( iv_off ) { + *iv_off = n; + } + + 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( ctx == NULL || input == NULL || output == NULL || iv == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ctx->keybits != 128UL && ctx->keybits != 256UL) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + while( length-- ) + { + memcpy( ov, iv, 16 ); + if ( (ret = mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ) != 0 ) { + return ret; + } + + 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 ); + } + + 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; + size_t processed = 0; + int ret = 0; + CORE_DECLARE_IRQ_STATE; + + if( ctx == NULL || input == NULL || output == NULL || nonce_counter == NULL || stream_block == NULL ) { + return ( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + } + + if ( ctx->keybits != 128UL && ctx->keybits != 256UL) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + while ( processed < length ) { + if ( n > 0 ) { + /* start by filling up the IV */ + output[processed] = (unsigned char)( input[processed] ^ stream_block[n] ); + n = ( n + 1 ) & 0x0F; + processed++; + continue; + } else { + /* process one ore more blocks of data */ + CRYPTO_TypeDef *device = crypto_management_acquire(); + device->WAC = 0; + device->CTRL = CRYPTO_CTRL_INCWIDTH_INCWIDTH4; + + CORE_ENTER_CRITICAL(); + CRYPTO_KeyBufWrite(device, (uint32_t*)ctx->key, (ctx->keybits == 128UL) ? cryptoKey128Bits : cryptoKey256Bits); + CRYPTO_DataWriteUnaligned(&device->DATA1, (uint8_t *)nonce_counter); + CORE_EXIT_CRITICAL(); + + /* strategy: encrypt nonce, encNonce xor input -> output, inc(nonce) */ + size_t iterations = (length - processed) / 16; + for (size_t i = 0; i < iterations; i++ ) { + device->CMD = CRYPTO_CMD_INSTR_DATA1TODATA0; + device->CMD = CRYPTO_CMD_INSTR_AESENC; + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + device->CMD = CRYPTO_CMD_INSTR_DATA1INC; + + CORE_ENTER_CRITICAL(); + CRYPTO_DataWriteUnaligned(&device->DATA0XOR, (uint8_t *)(&input[processed])); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)(&output[processed])); + CORE_EXIT_CRITICAL(); + processed += 16; + } + + while ( length - processed > 0 ) { + if ( n == 0 ) { + device->CMD = CRYPTO_CMD_INSTR_DATA1TODATA0; + device->CMD = CRYPTO_CMD_INSTR_AESENC; + while ((device->STATUS & CRYPTO_STATUS_INSTRRUNNING) != 0); + device->CMD = CRYPTO_CMD_INSTR_DATA1INC; + + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA0, (uint8_t *)stream_block); + CORE_EXIT_CRITICAL(); + } + /* Save remainder to iv */ + output[processed] = (unsigned char)( input[processed] ^ stream_block[n] ); + n = ( n + 1 ) & 0x0F; + processed++; + } + + CORE_ENTER_CRITICAL(); + CRYPTO_DataReadUnaligned(&device->DATA1, (uint8_t *)nonce_counter); + CORE_EXIT_CRITICAL(); + + crypto_management_release(device); + } + } + + if ( nc_off ) { + *nc_off = n; + } + + return ret; +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* MBEDTLS_AES_ALT */ +#endif /* MBEDTLS_AES_C */ +#endif /* CRYPTO_PRESENT */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c new file mode 100644 index 00000000000..48fe271e8fc --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c @@ -0,0 +1,1725 @@ +/* + * 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 + +#include "em_device.h" + +#if defined( CRYPTO_PRESENT ) + +#if defined( MBEDTLS_ECP_C ) +#if defined( MBEDTLS_ECP_INTERNAL_ALT ) + +#include "mbedtls/ecp.h" +#include "mbedtls/ecp_internal.h" +#include "mbedtls/platform.h" +#include "em_crypto.h" +#include "em_core.h" +#include "crypto_management.h" + +#include +#include + +/** 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]; + +#define SLCL_ECP_CHK(f) do { if( ( ret = (f) ) != 0 ) goto cleanup; } while( 0 ) + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) || defined(MBEDTLS_ECP_NORMALIZE_JAC_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 < ECC_BIGINT_SIZE_IN_32BIT_WORDS ) + { + memcpy(bigint, mpi->p, mpi->n * sizeof(uint32_t)); + memset(&bi[mpi->n], + 0, + ECC_BIGINT_SIZE_IN_BYTES - ( mpi->n * sizeof(uint32_t) ) ); + } + else + { + /* mpi has more room than bigint, so only store up to sizeof(bigint) */ + memcpy(bigint, mpi->p, ECC_BIGINT_SIZE_IN_BYTES); + } +} + +/***************************************************************************//** + * @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) +{ + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_CRITICAL(); + 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; + CORE_EXIT_CRITICAL(); + + return (*status_reg & CRYPTO_DSTATUS_CARRY) == CRYPTO_DSTATUS_CARRY; +} + +/***************************************************************************//** + * @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 crypto_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; + CORE_DECLARE_IRQ_STATE; + + /************** 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. */ + + CORE_ENTER_CRITICAL(); + 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 */ + CORE_EXIT_CRITICAL(); + + 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); + CORE_ENTER_CRITICAL(); + CRYPTO_DDATA0_260_BITS_READ(crypto, D); + CORE_EXIT_CRITICAL(); + 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_3( crypto, + CRYPTO_CMD_INSTR_SELDDATA2DDATA2, + CRYPTO_CMD_INSTR_SHRA, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); + + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA0, N); + CORE_EXIT_CRITICAL(); + + 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 + { + 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)) + { + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(&crypto->DDATA4, R); + CORE_EXIT_CRITICAL(); + } + else + { + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA0, N); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_SUB + ); + + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(&crypto->DDATA0, R); + CORE_EXIT_CRITICAL(); + } + return; +} /* crypto_mpi_div_mod */ +#endif /* MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT || MBEDTLS_ECP_NORMALIZE_JAC_ALT */ + +/***************************************************************************//** + * @brief + * Enable CRYPTO by setting up control registers for given ecc curve. + ******************************************************************************/ +static int crypto_device_init( CRYPTO_TypeDef *device, const mbedtls_ecp_group *grp) +{ + int ret = 0; + + /* Setup CRYPTO registers for ECC operation */ + device->CTRL = 0; + device->SEQCTRL = CRYPTO_SEQCTRL_BLOCKSIZE_32BYTES | 32; + device->SEQCTRLB = 0; + + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + CRYPTO_ModulusSet( device, cryptoModulusEccP192 ); + CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( device, cryptoResult256Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + CRYPTO_ModulusSet( device, cryptoModulusEccP224 ); + CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( device, cryptoResult256Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + CRYPTO_ModulusSet( device, cryptoModulusEccP256 ); + CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits ); + CRYPTO_ResultWidthSet( device, cryptoResult260Bits ); + break; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + break; + } + + return( ret ); +} + +/***************************************************************************//** + * @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; + CORE_DECLARE_IRQ_STATE; + + if (mpi->n == 8) + { + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(ddataReg, mpi->p); + CORE_EXIT_CRITICAL(); + } + else + { + if (mpi->n > 8) + { + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(ddataReg, mpi->p); + CORE_EXIT_CRITICAL(); + 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) + { + SLCL_ECP_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 ); +} + +/** + * \brief Indicate if the Elliptic Curve Point module extension can + * handle the group. + * + * \param grp The pointer to the elliptic curve group that will be the + * basis of the cryptographic computations. + * + * \return Non-zero if successful. + */ +unsigned char mbedtls_internal_ecp_grp_capable( const mbedtls_ecp_group *grp ) +{ + switch( grp->id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + return( true ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + + default: + return( false ); + } +} + +/** + * \brief Initialise the Elliptic Curve Point module extension. + * + * If mbedtls_internal_ecp_grp_capable returns true for a + * group, this function has to be able to initialise the + * module for it. + * + * This module can be a driver to a crypto hardware + * accelerator, for which this could be an initialise function. + * + * \param grp The pointer to the group the module needs to be + * initialised for. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) +{ + /* Crypto operations are atomic, so no need to setup any context here */ + (void) grp; + return 0; +} + +/** + * \brief Frees and deallocates the Elliptic Curve Point module + * extension. + * + * \param grp The pointer to the group the module was initialised for. + */ +void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) +{ + /* Crypto operations are atomic, so no need to free any context here */ + (void) grp; +} + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) +/** + * \brief Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l. + * + * \param grp Pointer to the group representing the curve. + * + * \param pt The point on the curve to be randomised, given with Jacobian + * coordinates. + * + * \param f_rng A function pointer to the random number generator. + * + * \param p_rng A pointer to the random number generator state. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_randomize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + ecc_bigint_t l; + CORE_DECLARE_IRQ_STATE; + CRYPTO_TypeDef *crypto; + + /* Strategy: + * 1) Generate l such that 1 < l < p + * 2) Z = l (R1) * Z (R4) + * 3) ll (R1) = l (R4) * l + * 4) X = ll (R1) * X (R2) + * 5) lll (R1) = ll (R1) * l (R4) + * 6) Y = lll (R1) * Y (R3) + */ + + /* Acquire entropy before grabbing crypto, since the entropy function might use crypto */ + /* Generate l such that 1 < l < p */ + ret = f_rng(p_rng, (unsigned char *)l, sizeof(l)); + if ( ret != 0 ) { + return( ret ); + } + + crypto = crypto_management_acquire(); + crypto_device_init(crypto, grp); + + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA1, l); + ecp_crypto_ddata_write(&crypto->DDATA2, &pt->X); + ecp_crypto_ddata_write(&crypto->DDATA3, &pt->Y); + ecp_crypto_ddata_write(&crypto->DDATA4, &pt->Z); + CORE_EXIT_CRITICAL(); + + /* Z = l * Z */ + CRYPTO_EXECUTE_2 ( crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL ); + CRYPTO_InstructionSequenceWait(crypto); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Z) ); + + /* X = l^2 * X */ + CRYPTO_EXECUTE_6 ( crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL ); + CRYPTO_InstructionSequenceWait(crypto); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->X) ); + + /* Y = l^3 * Y */ + CRYPTO_EXECUTE_5 ( crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL ); + CRYPTO_InstructionSequenceWait(crypto); + + MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Y) ); + +cleanup: + crypto_management_release( crypto ); + return( ret ); +} +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) +/** + * \brief Addition: R = P + Q, mixed affine-Jacobian coordinates. + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Special cases: (1) P or Q is zero, (2) R is zero, + * (3) P == Q. + * None of these cases can happen as intermediate step in + * ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base + * point, the factor being less than its order, so none of + * them is zero; + * - Q is an odd multiple of the base point, P an even + * multiple, due to the choice of precomputed points in the + * modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as + * meaning 1. + * + * Cost in field operations if done by [5] 3.22: + * 1A := 8M + 3S + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the first summand, given with Jacobian + * coordinates + * + * \param Q Pointer to the second summand, given with affine + * coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_add_mixed( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + int ret; + CORE_DECLARE_IRQ_STATE; + CRYPTO_TypeDef *crypto = crypto_management_acquire(); + + crypto_device_init(crypto, 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: + */ + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_5(crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &Q->X); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_4 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &Q->Y); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL + ); + CRYPTO_InstructionSequenceWait(crypto); + + /* + 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: + + 0. Select R0, R1 + 1. R0 = R0 - R1 = 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 + + Read Operations: + + R->Z = R0 = Pz * C + + Output State: + R0 = FREE + R1 = C + R2 = D + R3 = Px + R4 = FREE + + STEP 2: + */ + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA1, &P->Y); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); /* R2 = D */ + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->X); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_7 (crypto, + CRYPTO_CMD_INSTR_DDATA3TODDATA1, + 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_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z); + + if (ret != 0) goto cleanup; + + /* + 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. R4 = R1 = C + 2. Select R1, R4 + 3. R0 = R1 * R4 = C^2 + 4. R1 = R0 = C^2 + 5. R0 = R1 * R4 = C^3 + 6. R4 = R0 = C^3 + 7. Select R1, R3 + 8. R0 = R1 * R3 = Px * C^2 + 9. R3 = R0 = Px * C^2 + 10. R1 = R2 = D + 11. Select R1, R1 + 12. R0 = R1 * R1 = D^2 + 13. Select R0, R4 + 14. R0 = R0 - R4 = D2 - C3 + + Output state: + + R0 = D2 - C3 + R1 = FREE + R2 = D + R3 = X1C2 = Px * C^2 + R4 = C3 = C^3 + + STEP 3: + */ + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA4, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4); + CRYPTO_InstructionSequenceWait(crypto); + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3); + CRYPTO_InstructionSequenceWait(crypto); + + CRYPTO_EXECUTE_5 (crypto, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA4, + CRYPTO_CMD_INSTR_MSUB + ); + CRYPTO_InstructionSequenceWait(crypto); + + /* + 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 - C3 + R1 = FREE + R2 = D + R3 = X1C2 + R4 = C3 + + Instructions to be executed: + + 1. Select R0, R3 + 2. R0 = R0 - R3 = D2 - C3 - X1C2 + 3. R0 = R0 - R3 = D2 - C3 - X1C2 - X1C2 = R->X + 4. DMA = R0 = R->X + 5. R1 = R0 = R->X + + 6. Select R3, R1 + 7. R0 = R3 - R1 = X1C2 - R->X + 8. R1 = R0 = X1C2 - R->X + 9. Select R1, R2 + 10. R0 = R1 * R2 = D *(X1C2 - R->X) + 11. R2 = R0 + + 12. R0 = DMA = Py + 13. R1 = R0 = Py + 14. Select R1, R4 + 15. R0 = R1 * R4 = Py * C3 = Y1C3 + 16. R4 = R0 = Y1C3 + + 17. Select R2, R4 + 18. R0 = R2 - R4 + + Read Operations: + + R->X = R2 = D2 - (C3 + 2 * X1C2) + R->Y = R0 = D * (X1C2 - R->X) - Y1C3 + + STEP 4: + */ + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA3, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_MSUB); + CRYPTO_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->X); + if ( ret != 0 ) goto cleanup; + + CRYPTO_EXECUTE_7 (crypto, + 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_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_6 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB + ); + CRYPTO_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y); + if ( ret != 0 ) goto cleanup; + + cleanup: + crypto_management_release( crypto ); + return ( ret ); +} +#endif + +/** + * \brief Point doubling R = 2 P, Jacobian coordinates. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + * when the implementation is based on the "dbl-1998-cmo-2" + * doubling formulas in [8] and standard optimizations are + * applied when curve parameter A is one of { 0, -3 }. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the point that has to be doubled, given with + * Jacobian coordinates. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +int mbedtls_internal_ecp_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + CORE_DECLARE_IRQ_STATE; + CRYPTO_TypeDef *crypto = crypto_management_acquire(); + + crypto_device_init(crypto, grp); + + 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: + */ + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_5 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_4 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD); + CRYPTO_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z); + if ( ret != 0 ) goto cleanup; + + CRYPTO_EXECUTE_5 (crypto, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + CRYPTO_CMD_INSTR_MADD + ); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA4, &P->X); + CRYPTO_DDataRead(&crypto->DDATA0, _2YY); + CORE_EXIT_CRITICAL(); + + /* + 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_11(crypto, + CRYPTO_CMD_INSTR_SELDDATA0DDATA0, + 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_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_7 (crypto, + 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 + ); + CRYPTO_InstructionSequenceWait(crypto); + /* + 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 = FREE + R1 = FREE + R2 = FREE + R3 = D + R4 = FREE + + STEP 3: + */ + + CRYPTO_EXECUTE_8 (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_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->X); + if ( ret != 0 ) goto cleanup; + + CRYPTO_EXECUTE_7 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA4, + + CRYPTO_CMD_INSTR_SELDDATA2DDATA4, + CRYPTO_CMD_INSTR_MSUB, + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA3 + ); + CRYPTO_InstructionSequenceWait(crypto); + + + /* + STEP 4: + + Goals: + B = 8 * Y^4 + R->Y = D - B + + Write Operations: + + R1 = YY + + Input State: + R0 = FREE + R1 = YY + R2 = FREE + R3 = D + R4 = FREE + + Instructions to be executed: + + 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: + */ + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA0, _2YY); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_9 (crypto, + 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_InstructionSequenceWait(crypto); + + ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y); + if ( ret != 0 ) goto cleanup; + + cleanup: + crypto_management_release( crypto ); + + return ( ret ); +} +#endif + +/** + * \brief Normalize jacobian coordinates of an array of (pointers to) + * points. + * + * Using Montgomery's trick to perform only one inversion mod P + * the cost is: + * 1N(t) := 1I + (6t - 3)M + 1S + * (See for example Algorithm 10.3.4. in [9]) + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Warning: fails (returning an error) if one of the points is + * zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * \param grp Pointer to the group representing the curve. + * + * \param T Array of pointers to the points to normalise. + * + * \param t_len Number of elements in the array. + * + * \return 0 if successful, + * an error if one of the points is zero. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) +int mbedtls_internal_ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], + size_t t_len ) +{ + int ret = 0; + size_t i; + ecc_bigint_t* cc; + ecc_bigint_t uu; + ecc_bigint_t one; + ecc_bigint_t modulus; + CORE_DECLARE_IRQ_STATE; + + if( t_len < 2 ) + return( mbedtls_internal_ecp_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 ); + + CRYPTO_TypeDef *crypto = crypto_management_acquire(); + crypto_device_init(crypto, grp); + + for( i = 1; i < t_len; i++ ) + { + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write( &crypto->DDATA1, &T[i]->Z ); + CRYPTO_DDataWrite( &crypto->DDATA2, cc[i-1] ); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead( &crypto->DDATA0, cc[i] ); + CORE_EXIT_CRITICAL(); + } + + memset(one, 0, sizeof(one)); + one[0]=1; + MPI_TO_BIGINT( modulus, &grp->P ); + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + crypto_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 */ + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA2, uu); + CORE_EXIT_CRITICAL(); + } + else + { + /* Z_inv (DDATA1) = uu x cc[i-1] modulo p */ + /* uu = uu x T[i]->Z modulo p */ + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA1, uu); + CRYPTO_DDataWrite(&crypto->DDATA2, cc[i-1]); + ecp_crypto_ddata_write( &crypto->DDATA3, &T[i]->Z ); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL, + CRYPTO_CMD_INSTR_DDATA0TODDATA2); /* Z_inv (DDATA2) */ + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(&crypto->DDATA0, uu); + CORE_EXIT_CRITICAL(); + } + + /* + * proceed as in normalize() + */ + CORE_ENTER_CRITICAL(); + ecp_crypto_ddata_write(&crypto->DDATA3, &T[i]->X); + ecp_crypto_ddata_write(&crypto->DDATA4, &T[i]->Y); + CORE_EXIT_CRITICAL(); + + /* Z_inv already in DDATA2 */ + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + + 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. + */ + SLCL_ECP_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + SLCL_ECP_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + + cleanup: + crypto_management_release( crypto ); + mbedtls_free( cc ); + + return( ret ); +} +#endif + +/** + * \brief Normalize jacobian coordinates so that Z == 0 || Z == 1. + * + * Cost in field operations if done by [5] 3.2.1: + * 1N := 1I + 3M + 1S + * + * \param grp Pointer to the group representing the curve. + * + * \param pt pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) +int mbedtls_internal_ecp_normalize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt ) +{ + int ret = 0; + CORE_DECLARE_IRQ_STATE; + CRYPTO_TypeDef *crypto = crypto_management_acquire(); + + crypto_device_init(crypto, grp); + + 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, &pt->Z ); + MPI_TO_BIGINT( modulus, &grp->P ); + + crypto_mpi_div_mod(crypto, one, Z, modulus, Z_inv); + + /* + + 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 + + */ + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA1, Z_inv); + ecp_crypto_ddata_write(&crypto->DDATA3, &pt->X); + ecp_crypto_ddata_write(&crypto->DDATA4, &pt->Y); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA3, + CRYPTO_CMD_INSTR_SELDDATA1DDATA2, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + CRYPTO_EXECUTE_3 (crypto, + CRYPTO_CMD_INSTR_DDATA0TODDATA1, + CRYPTO_CMD_INSTR_SELDDATA1DDATA4, + CRYPTO_CMD_INSTR_MMUL); + CRYPTO_InstructionSequenceWait(crypto); + + ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Y); + ecp_crypto_ddata_read(&crypto->DDATA3, &pt->X); + + crypto_management_release( crypto ); + + /* + * Z = 1 + */ + SLCL_ECP_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + + cleanup: + return( ret ); +} +#endif + +#endif /* #if defined( MBEDTLS_ECP_INTERNAL_ALT ) */ + +#endif /* #if defined( MBEDTLS_ECP_C ) */ + +#endif /* #if defined( CRYPTO_PRESENT ) */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.c b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.c new file mode 100644 index 00000000000..b49fe089313 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.c @@ -0,0 +1,403 @@ +/* + * Silicon Labs CRYPTO device management interface. + * + * 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 "crypto_management.h" +#include "em_core.h" +#include "em_bus.h" + +#if defined( CRYPTO_PRESENT ) + +/* Conversion macro for compatibility with the 5.3.x release of the Gecko SDK */ +#if defined( MBEDTLS_CRYPTO_DEVICE_PREEMPTION ) +#warning "MBEDTLS_CRYPTO_DEVICE_PREEMPTION is deprecated, please define " \ + "CRYPTO_DEVICE_PREEMPTION instead." +#endif + +#if defined( MBEDTLS_THREADING_C ) +#include "mbedtls/threading.h" +static mbedtls_threading_mutex_t crypto_locks[CRYPTO_COUNT]; +static volatile bool crypto_locks_initialized = false; +static unsigned int acquire_count = 0U; +#endif /* MBEDTLS_THREADING_C */ + +#if defined( CRYPTO_DEVICE_PREEMPTION ) +/** Preemptable 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_Data260_TypeDef DDATA[5]; /*!< DDATA registers. Covers all data + registers + of CRYPTO, including DATA(128 bit), + DDATA (256bit/260bit), + QDATA (512bit) registers. */ + uint32_t regmask; /*!< Bitmask for which registers to save */ + uint32_t operands; /*!< Saving the currently selected operands */ + bool carry; /*!< Saving the status of the carry flag */ +} crypto_context_t; + +static crypto_context_t preemption_context; +static bool is_preempted = false; +static CORE_DECLARE_IRQ_STATE; +#endif /* CRYPTO_DEVICE_PREEMPTION */ + +typedef enum +{ +#if defined( CRYPTO0 ) + CRYPTO0_ID = 0, +#elif defined( CRYPTO ) + CRYPTO_ID = 0, +#endif +#if defined( CRYPTO1 ) + CRYPTO1_ID = 1, +#endif +} crypto_instance_number_t; + +typedef struct { + CRYPTO_TypeDef *device; + uint32_t clockMask; +} crypto_device_t; + +static const crypto_device_t crypto_devices[CRYPTO_COUNT] = +{ +#if defined( CRYPTO0 ) + { + CRYPTO0, + _CMU_HFBUSCLKEN0_CRYPTO0_SHIFT + }, +#elif defined( CRYPTO ) + { + CRYPTO, + _CMU_HFBUSCLKEN0_CRYPTO_SHIFT + }, +#endif +#if defined( CRYPTO1 ) + { + CRYPTO1, + _CMU_HFBUSCLKEN0_CRYPTO1_SHIFT + }, +#endif +}; + +static inline int crypto_management_index_by_device( CRYPTO_TypeDef *device ) +{ +#if defined( CRYPTO0 ) + if ( device == CRYPTO0 ) return 0; +#elif defined( CRYPTO ) + if ( device == CRYPTO ) return 0; +#endif +#if defined( CRYPTO1 ) + if ( device == CRYPTO1 ) return 1; +#endif + return -1; +} + +/* Use bitband for clock enable/disable operations, such that they are atomic */ +#define CRYPTO_CLOCK_ENABLE(clk) BUS_RegBitWrite(&(CMU->HFBUSCLKEN0), (clk), 1) +#define CRYPTO_CLOCK_DISABLE(clk) BUS_RegBitWrite(&(CMU->HFBUSCLKEN0), (clk), 0) +#define CRYPTO_CLOCK_ENABLED(clk) BUS_RegBitRead(&(CMU->HFBUSCLKEN0), (clk)) + +/* Get ownership of an available crypto device */ +CRYPTO_TypeDef *crypto_management_acquire( void ) +{ + CRYPTO_TypeDef *device = NULL; + +#if defined( MBEDTLS_THREADING_C ) + /* Initialize mutexes if that hasn't happened yet */ + CORE_DECLARE_IRQ_STATE; + + if ( !crypto_locks_initialized ) { + CORE_ENTER_CRITICAL(); + if ( !crypto_locks_initialized ) { + for ( int i = 0; i < CRYPTO_COUNT; i++ ) { + mbedtls_mutex_init(&crypto_locks[i]); + } + crypto_locks_initialized = true; + } + CORE_EXIT_CRITICAL(); + } + +/* Wrapping this in SL_THREADING_ALT pending non-blocking mutex in official + * threading API. */ +#if defined( SL_THREADING_ALT ) + /* Try to take an available crypto instance */ + unsigned int devno = 0; + for ( ; devno < CRYPTO_COUNT; devno++ ) { + if ( 0 == THREADING_TakeMutexNonBlocking(&crypto_locks[devno]) ) { + device = crypto_devices[devno].device; + break; + } + } +#endif // SL_THREADING_ALT + + /* If no device immediately available, do naieve round-robin */ + if ( device == NULL ) { + devno = acquire_count % CRYPTO_COUNT; + mbedtls_mutex_lock( &crypto_locks[devno] ); + device = crypto_devices[devno].device; + } + + /* Doing this outside of critical section is safe, since we own the lock + * and are using bitband to poke the clock enable bit */ + CRYPTO_CLOCK_ENABLE( crypto_devices[devno].clockMask ); + + acquire_count++; +#else // !MBEDTLS_THREADING_C + device = crypto_devices[0].device; + CRYPTO_CLOCK_ENABLE( crypto_devices[0].clockMask ); +#endif // MBEDTLS_THREADING_C + + return device; +} + +/* Get ownership of the default crypto device (CRYPTO0/CRYPTO) */ +CRYPTO_TypeDef *crypto_management_acquire_default( void ) +{ + CRYPTO_TypeDef *device = NULL; + +#if defined( MBEDTLS_THREADING_C ) + /* Initialize mutexes if that hasn't happened yet */ + CORE_DECLARE_IRQ_STATE; + + if ( !crypto_locks_initialized ) { + CORE_ENTER_CRITICAL(); + if ( !crypto_locks_initialized ) { + for ( int i = 0; i < CRYPTO_COUNT; i++ ) { + mbedtls_mutex_init(&crypto_locks[i]); + } + crypto_locks_initialized = true; + } + CORE_EXIT_CRITICAL(); + } + + mbedtls_mutex_lock( &crypto_locks[0] ); + device = crypto_devices[0].device; + + /* Doing this outside of critical section is safe, since we own the lock + * and are using bitband to poke the clock enable bit */ + CRYPTO_CLOCK_ENABLE( crypto_devices[0].clockMask ); +#else // !MBEDTLS_THREADING_C + device = crypto_devices[0].device; + CRYPTO_CLOCK_ENABLE( crypto_devices[0].clockMask ); +#endif // MBEDTLS_THREADING_C + + return device; +} + +/* Release ownership of an available crypto device */ +void crypto_management_release( CRYPTO_TypeDef *device ) +{ + int devno = crypto_management_index_by_device( device ); + if ( devno < 0 ) { + return; + } + + /* Doing this outside of critical section is safe, since we still own the lock + * and are using bitband to poke the clock enable bit */ + CRYPTO_CLOCK_DISABLE( crypto_devices[devno].clockMask ); + +#if defined ( MBEDTLS_THREADING_C ) + mbedtls_mutex_unlock( &crypto_locks[devno] ); +#endif +} + +/* Acquire a device with preemption. NOT thread-safe! */ +CRYPTO_TypeDef *crypto_management_acquire_preemption( uint32_t regmask ) +{ +#if defined( CRYPTO_DEVICE_PREEMPTION ) + CRYPTO_TypeDef *device = NULL; + /* Turn off interrupts */ + CORE_ENTER_CRITICAL(); + + /* Check if there is an unused CRYPTO instance */ + for ( int i = 0; i < CRYPTO_COUNT; i++ ) { + if ( !CRYPTO_CLOCK_ENABLED( crypto_devices[i].clockMask ) ) { + /* Found an unused device */ + CRYPTO_CLOCK_ENABLE( crypto_devices[i].clockMask ); + device = crypto_devices[i].device; + break; + } + } + + /* If there is no unused instance, preempt the last one */ + if ( device == NULL ) { + is_preempted = true; + device = crypto_devices[CRYPTO_COUNT - 1].device; + + /* In case this instance is still working on anything */ + CRYPTO_InstructionSequenceWait(device); + + /* Store operational context */ + preemption_context.regmask = regmask; + preemption_context.WAC = device->WAC; + preemption_context.CTRL = device->CTRL; + preemption_context.SEQCTRL = device->SEQCTRL; + preemption_context.SEQCTRLB = device->SEQCTRLB; + preemption_context.IEN = device->IEN; + preemption_context.operands = device->CSTATUS; + preemption_context.carry = (device->DSTATUS & CRYPTO_DSTATUS_CARRY) != 0; + + if ( (preemption_context.WAC & _CRYPTO_WAC_RESULTWIDTH_MASK) == CRYPTO_WAC_RESULTWIDTH_260BIT) + { + CRYPTO_DData0Read260(device, preemption_context.DDATA[0]); /* Always save DDATA0 because it'll get clobbered in 260-bit mode*/ + + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA1) != 0 ) { + device->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; /* Move DDATA1 to DDATA0 + in order to read. */ + CRYPTO_DData0Read260(device, preemption_context.DDATA[1]); + } + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA2) != 0 ) { + device->CMD = CRYPTO_CMD_INSTR_DDATA2TODDATA0; /* Move DDATA2 to DDATA0 + in order to read. */ + CRYPTO_DData0Read260(device, preemption_context.DDATA[2]); + } + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA3) != 0 ) { + device->CMD = CRYPTO_CMD_INSTR_DDATA3TODDATA0; /* Move DDATA3 to DDATA0 + in order to read. */ + CRYPTO_DData0Read260(device, preemption_context.DDATA[3]); + } + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA4) != 0 ) { + device->CMD = CRYPTO_CMD_INSTR_DDATA4TODDATA0; /* Move DDATA4 to DDATA0 + in order to read. */ + CRYPTO_DData0Read260(device, preemption_context.DDATA[4]); + } + } + else + { + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA0) != 0 ) + CRYPTO_DDataRead(&device->DDATA0, preemption_context.DDATA[0]); + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA1) != 0 ) + CRYPTO_DDataRead(&device->DDATA1, preemption_context.DDATA[1]); + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA2) != 0 ) + CRYPTO_DDataRead(&device->DDATA2, preemption_context.DDATA[2]); + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA3) != 0 ) + CRYPTO_DDataRead(&device->DDATA3, preemption_context.DDATA[3]); + if ( (regmask & CRYPTO_MANAGEMENT_SAVE_DDATA4) != 0 ) + CRYPTO_DDataRead(&device->DDATA4, preemption_context.DDATA[4]); + } + + /* Search for possible EXEC commands and replace with END. */ + for ( size_t j = 0; j < (regmask & 0x7U)*sizeof(uint32_t); j++ ) { + if ( (j & 0x03) == 0 ) { + preemption_context.SEQ[j / sizeof(uint32_t)] = *((&device->SEQ0) + (j / sizeof(uint32_t))); + } + if ( ((uint8_t*)preemption_context.SEQ)[j] == CRYPTO_CMD_INSTR_EXEC ) { + ((uint8_t*)preemption_context.SEQ)[j] = CRYPTO_CMD_INSTR_END; + } + } + } + + return device; +#else + (void) regmask; + return crypto_management_acquire(); +#endif +} + +/* Release a device from preemption */ +void crypto_management_release_preemption( CRYPTO_TypeDef *device ) +{ + if ( crypto_management_index_by_device( device ) < 0 ) { + return; + } +#if defined( CRYPTO_DEVICE_PREEMPTION ) + + if ( is_preempted ) { + /* If we preempted something, put their context back */ + device->WAC = preemption_context.WAC; + device->CTRL = preemption_context.CTRL; + device->SEQCTRL = preemption_context.SEQCTRL; + device->SEQCTRLB = preemption_context.SEQCTRLB; + device->IEN = preemption_context.IEN; + + if ( (preemption_context.WAC & _CRYPTO_WAC_RESULTWIDTH_MASK) == CRYPTO_WAC_RESULTWIDTH_260BIT) + { + /* Start by writing the DDATA1 value to DDATA0 and move to DDATA1. */ + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA1) != 0 ) { + CRYPTO_DData0Write260(device, preemption_context.DDATA[1]); + device->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA1; + } + + /* Write the DDATA2 value to DDATA0 and move to DDATA2. */ + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA2) != 0 ) { + CRYPTO_DData0Write260(device, preemption_context.DDATA[2]); + device->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA2; + } + + /* Write the DDATA3 value to DDATA0 and move to DDATA3. */ + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA3) != 0 ) { + CRYPTO_DData0Write260(device, preemption_context.DDATA[3]); + device->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA3; + } + + /* Write the DDATA4 value to DDATA0 and move to DDATA4. */ + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA4) != 0 ) { + CRYPTO_DData0Write260(device, preemption_context.DDATA[4]); + device->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA4; + } + + /* Finally write DDATA0 */ + CRYPTO_DData0Write260(device, preemption_context.DDATA[0]); + } + else + { + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA0) != 0 ) + CRYPTO_DDataWrite(&device->DDATA0, preemption_context.DDATA[0]); + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA1) != 0 ) + CRYPTO_DDataWrite(&device->DDATA1, preemption_context.DDATA[1]); + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA2) != 0 ) + CRYPTO_DDataWrite(&device->DDATA2, preemption_context.DDATA[2]); + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA3) != 0 ) + CRYPTO_DDataWrite(&device->DDATA3, preemption_context.DDATA[3]); + if ( (preemption_context.regmask & CRYPTO_MANAGEMENT_SAVE_DDATA4) != 0 ) + CRYPTO_DDataWrite(&device->DDATA4, preemption_context.DDATA[4]); + } + + if (preemption_context.carry) { + device->CMD = CRYPTO_CMD_INSTR_CSET; + } else { + device->CMD = CRYPTO_CMD_INSTR_CCLR; + } + + device->CMD = (preemption_context.operands & 0x7U) | + (((preemption_context.operands >> 8) & 0x7U) << 3) | + 0xC0; + + for (size_t i = 0; i < (preemption_context.regmask & 0x7U); i++ ) { + *((&device->SEQ0) + i) = preemption_context.SEQ[i]; + } + + is_preempted = false; + } else { + /* If we didn't preempt anything, turn crypto clock back off */ + CRYPTO_CLOCK_DISABLE( crypto_devices[crypto_management_index_by_device( device )].clockMask ); + } + + /* Turn interrupts back on */ + CORE_EXIT_CRITICAL(); +#else + crypto_management_release(device); +#endif +} + +#endif /* CRYPTO_PRESENT */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.h b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.h new file mode 100644 index 00000000000..b1a4e9f151f --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_management.h @@ -0,0 +1,128 @@ +/* + * Silicon Labs CRYPTO device management interface. + * + * 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 CRYPTO_MANAGEMENT_H +#define CRYPTO_MANAGEMENT_H + +/***************************************************************************//** + * \addtogroup sl_crypto + * \{ + ******************************************************************************/ + +/***************************************************************************//** + * \addtogroup sl_crypto_management CRYPTO peripheral instance management + * \brief Management functions for CRYPTO peripherals. These functions take care + * of not having two 'owners' simultaneously for the same peripheral, + * potentially messing up the internal state of said peripheral. + * \{ + ******************************************************************************/ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#include "em_device.h" + +#if defined( CRYPTO_PRESENT ) +#include "em_crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Save DDATA0 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_DDATA0 (0x1U << 3) +/** Save DDATA1 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_DDATA1 (0x1U << 4) +/** Save DDATA2 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_DDATA2 (0x1U << 5) +/** Save DDATA3 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_DDATA3 (0x1U << 6) +/** Save DDATA4 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_DDATA4 (0x1U << 7) +/** Save SEQ0 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_UPTO_SEQ0 (0x1U) +/** Save SEQ0 through SEQ1 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_UPTO_SEQ1 (0x2U) +/** Save SEQ0 through SEQ2 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_UPTO_SEQ2 (0x3U) +/** Save SEQ0 through SEQ3 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_UPTO_SEQ3 (0x4U) +/** Save SEQ0 through SEQ4 register when preempting */ +#define CRYPTO_MANAGEMENT_SAVE_UPTO_SEQ4 (0x5U) + +/** + * \brief Get ownership of a CRYPTO peripheral + * + * \return Handle of assigned CRYPTO peripheral + */ +CRYPTO_TypeDef *crypto_management_acquire( void ); + +/** + * \brief Get ownership of the default CRYPTO peripheral + * + * \return Handle of default CRYPTO peripheral + */ +CRYPTO_TypeDef *crypto_management_acquire_default( void ); + +/** + * \brief Release ownership of a CRYPTO peripheral + * + * \param device Handle of CRYPTO peripheral to be released + */ +void crypto_management_release( CRYPTO_TypeDef *device ); + +/** + * \brief Acquire preempting ownership of a CRYPTO peripheral. + * NOTE: this function is not meant for general use, it + * is not thread-safe, and must be called form the + * highest priority thread/interrupt allowed to use mbed TLS. + * + * \param regmask Bitmask of CRYPTO_MANAGEMENT_ defines instructing what + * parts of the device state will be clobbered during + * preemption. + * + * \return Handle of assigned CRYPTO peripheral + */ +CRYPTO_TypeDef *crypto_management_acquire_preemption( uint32_t regmask ); + +/** + * \brief Releasing preempting ownership of a CRYPTO peripheral. + * NOTE: this function is not meant for general use, it + * is not thread-safe, and must be called form the + * highest priority thread/interrupt allowed to use mbed TLS. + * + * \param device Handle of preempted CRYPTO peripheral to be released + */ +void crypto_management_release_preemption( CRYPTO_TypeDef *device ); + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTO_PRESENT */ + +/** \} (end addtogroup sl_crypto_management) */ +/** \} (end addtogroup sl_crypto) */ + +#endif /* CRYPTO_MANAGEMENT_H */ \ No newline at end of file diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_sha.c b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_sha.c new file mode 100644 index 00000000000..64d03989237 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_sha.c @@ -0,0 +1,467 @@ +/* + * FIPS-180-2 compliant SHA-1 & 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/sha[1][256].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 + * + * 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 + +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" + +#if ( defined(MBEDTLS_SHA256_ALT) && defined(MBEDTLS_SHA256_C) ) || ( defined(MBEDTLS_SHA1_ALT) && defined (MBEDTLS_SHA1_C) ) + +#include "em_device.h" + +#if defined(CRYPTO_PRESENT) +#include "em_crypto.h" +#include "em_core.h" +#include "crypto_management.h" +#include "em_assert.h" +#include + +#define CRYPTO_SHA_BLOCK_SIZE (64) + +#if defined(MBEDTLS_SHA1_C) +static const uint32_t init_state_sha1[8] = +{ + 0x67452301UL, + 0xEFCDAB89UL, + 0x98BADCFEUL, + 0x10325476UL, + 0xC3D2E1F0UL, + 0x0UL, + 0x0UL, + 0x0UL +}; +#endif /* defined(MBEDTLS_SHA1_C) */ + +#if defined(MBEDTLS_SHA256_C) +static const uint32_t init_state_sha256[8] = +{ + 0x6A09E667UL, + 0xBB67AE85UL, + 0x3C6EF372UL, + 0xA54FF53AUL, + 0x510E527FUL, + 0x9B05688CUL, + 0x1F83D9ABUL, + 0x5BE0CD19UL +}; + +static const uint32_t init_state_sha224[8] = +{ + 0xC1059ED8UL, + 0x367CD507UL, + 0x3070DD17UL, + 0xF70E5939UL, + 0xFFC00B31UL, + 0x68581511UL, + 0x64F98FA7UL, + 0xBEFA4FA4UL +}; +#endif /* defined(MBEDTLS_SHA256_C) */ + +static const unsigned char sha_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 +}; + +typedef enum { +#if defined(MBEDTLS_SHA1_C) + CRYPTO_SHA1, +#endif /* defined(MBEDTLS_SHA1_C) */ +#if defined(MBEDTLS_SHA256_C) + CRYPTO_SHA2 +#endif /* defined(MBEDTLS_SHA256_C) */ +} crypto_sha_mode_t; + +/* + * 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 + +/** + * @brief unified SHA acceleration function. + * + * @param[inout] state State context for SHA hashing + * @param[in] data Input block(s). Must contain N blocks + * of SHA1/SHA256 block size (64 bytes) + * @param blocks Amount of blocks pointed to by data + * @param mode SHA operation mode + */ +static void crypto_sha_update_state( uint32_t state[8], + const unsigned char *data, + size_t blocks, + crypto_sha_mode_t mode ) +{ + CORE_DECLARE_IRQ_STATE; + CRYPTO_TypeDef *crypto = crypto_management_acquire(); + + switch ( mode ) { +#if defined(MBEDTLS_SHA1_C) + case CRYPTO_SHA1: + crypto->CTRL = CRYPTO_CTRL_SHA_SHA1; + break; +#endif /* defined(MBEDTLS_SHA1_C) */ +#if defined(MBEDTLS_SHA256_C) + case CRYPTO_SHA2: + crypto->CTRL = CRYPTO_CTRL_SHA_SHA2; + break; +#endif /* defined(MBEDTLS_SHA256_C) */ + } + + crypto->WAC = 0; + crypto->IEN = 0; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits); + + /* Clear sequence control registers */ + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Put the state back */ + CORE_ENTER_CRITICAL(); + CRYPTO_DDataWrite(&crypto->DDATA1, state); + CORE_EXIT_CRITICAL(); + + CRYPTO_EXECUTE_3( crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_DDATA1TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1 ); + + /* Load the data block(s) */ + for ( size_t i = 0; i < blocks; i++ ) { + if ((uint32_t)(&data[i*CRYPTO_SHA_BLOCK_SIZE]) & 0x3) + { + uint32_t temp[CRYPTO_SHA_BLOCK_SIZE/sizeof(uint32_t)]; + memcpy(temp, &data[i*CRYPTO_SHA_BLOCK_SIZE], CRYPTO_SHA_BLOCK_SIZE); + CORE_ENTER_CRITICAL(); + CRYPTO_QDataWrite(&crypto->QDATA1BIG, temp); + CORE_EXIT_CRITICAL(); + } + else + { + CORE_ENTER_CRITICAL(); + CRYPTO_QDataWrite(&crypto->QDATA1BIG, + (uint32_t*) &data[i*CRYPTO_SHA_BLOCK_SIZE]); + CORE_EXIT_CRITICAL(); + } + + /* Process the data block */ + CRYPTO_EXECUTE_3( crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1 ); + } + CORE_ENTER_CRITICAL(); + CRYPTO_DDataRead(&crypto->DDATA0, state); + CORE_EXIT_CRITICAL(); + + crypto_management_release( crypto ); +} + +#if defined(MBEDTLS_SHA256_ALT) && defined(MBEDTLS_SHA256_C) +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + if ( dst != NULL && src != NULL ) { + *dst = *src; + } +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if ( is224 != 0 ) { + ctx->is224 = true; + memcpy(ctx->state, init_state_sha224, sizeof(ctx->state)); + } else { + ctx->is224 = false; + memcpy(ctx->state, init_state_sha256, sizeof(ctx->state)); + } +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ) +{ + crypto_sha_update_state( ctx->state, data, 1, CRYPTO_SHA2 ); +} + +/* + * 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 ) { + size_t blocks = ilen / 64; + crypto_sha_update_state( ctx->state, input, blocks, CRYPTO_SHA2 ); + input += blocks * 64; + ilen -= blocks * 64; + } + + if( ilen > 0 ) { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +/* + * 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, sha_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + for ( size_t i = 0; i < (ctx->is224 ? 28 : 32); i+=4) { + *((uint32_t*)(&output[i])) = __REV(ctx->state[i >> 2]); + } +} +#endif /* #if defined(MBEDTLS_SHA256_ALT) && defined(MBEDTLS_SHA256_C) */ + +#if defined(MBEDTLS_SHA1_ALT) && defined(MBEDTLS_SHA1_C) + +/** + * \brief Initialize SHA-1 context + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +/** + * \brief Clear SHA-1 context + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) { + return; + } + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +/** + * \brief Clone (the state of) a SHA-1 context + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + if ( dst != NULL && src != NULL ) { + *dst = *src; + } +} + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + memcpy(ctx->state, init_state_sha1, 32); +} + +/** + * \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 ) +{ + 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 ) { + size_t blocks = ilen / 64; + crypto_sha_update_state( ctx->state, input, blocks, CRYPTO_SHA1 ); + input += blocks * 64; + ilen -= blocks * 64; + } + + if( ilen > 0 ) { + memcpy( (void *) (ctx->buffer + left), input, 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] ) +{ + 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, sha_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + for ( size_t i = 0; i < 20; i+=4) { + *((uint32_t*)(&output[i])) = __REV(ctx->state[i >> 2]); + } +} + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ) +{ + crypto_sha_update_state( ctx->state, data, 1, CRYPTO_SHA1 ); +} + +#endif /* defined(MBEDTLS_SHA1_ALT) && defined(MBEDTLS_SHA1_C) */ + +#endif /* #if defined(CRYPTO_PRESENT) */ + +#endif /* #if ( defined(MBEDTLS_SHA256_ALT) && defined(MBEDTLS_SHA256_C) ) || ( defined(MBEDTLS_SHA1_ALT) && defined (MBEDTLS_SHA1_C) ) */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/mbedtls_device.h b/features/mbedtls/targets/TARGET_Silicon_Labs/mbedtls_device.h new file mode 100644 index 00000000000..d76aba13c6f --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/mbedtls_device.h @@ -0,0 +1,42 @@ +/* + * mbed OS configuration header for mbed TLS 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 MBEDTLS_DEVICE_H +#define MBEDTLS_DEVICE_H + +#include "em_device.h" + +#if defined ( AES_PRESENT ) +#define MBEDTLS_AES_ALT +#endif + +#if defined ( CRYPTO_PRESENT ) +#define MBEDTLS_AES_ALT + +#define MBEDTLS_ECP_INTERNAL_ALT +#define MBEDTLS_ECP_ADD_MIXED_ALT +#define MBEDTLS_ECP_DOUBLE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT + +#define MBEDTLS_SHA1_ALT +#define MBEDTLS_SHA256_ALT +#endif + +#endif /* MBEDTLS_DEVICE_H */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/sha1_alt.h b/features/mbedtls/targets/TARGET_Silicon_Labs/sha1_alt.h new file mode 100644 index 00000000000..891b0655c88 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/sha1_alt.h @@ -0,0 +1,113 @@ +/** + * \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 + +/***************************************************************************//** + * \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) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t state[8]; /*!< intermediate digest state */ + 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 ); + +/** + * \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] ); + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined(MBEDTLS_SHA1_ALT) */ + +/** \} (end addtogroup sl_crypto_sha1) */ +/** \} (end addtogroup sl_crypto) */ + +#endif /* #ifndef MBEDTLS_SHA1_ALT_H */ diff --git a/features/mbedtls/targets/TARGET_Silicon_Labs/sha256_alt.h b/features/mbedtls/targets/TARGET_Silicon_Labs/sha256_alt.h new file mode 100644 index 00000000000..5a7bf9a6766 --- /dev/null +++ b/features/mbedtls/targets/TARGET_Silicon_Labs/sha256_alt.h @@ -0,0 +1,120 @@ +/** + * \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 + +/***************************************************************************//** + * \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 +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t state[8]; /*!< intermediate digest state */ + uint32_t total[2]; /*!< number of bytes processed */ + unsigned char buffer[64]; /*!< data block being processed */ + bool is224; /*!< false => 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 ); + +/** + * \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] ); + +#ifdef __cplusplus +} +#endif + +#endif /* #if defined(MBEDTLS_SHA256_ALT) */ + +/** \} (end addtogroup sl_crypto_sha256) */ +/** \} (end addtogroup sl_crypto) */ + +#endif /* #ifndef MBEDTLS_SHA256_ALT_H */ diff --git a/targets/targets.json b/targets/targets.json index 7da1bd6066e..8ff782c0f37 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -2314,13 +2314,14 @@ "EFM32": { "inherits": ["Target"], "extra_labels": ["Silicon_Labs", "EFM32"], + "macros": ["MBEDTLS_CONFIG_HW_SUPPORT"], "public": false }, "EFM32GG990F1024": { "inherits": ["EFM32"], "extra_labels_add": ["EFM32GG", "1024K", "SL_AES"], "core": "Cortex-M3", - "macros": ["EFM32GG990F1024", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFM32GG990F1024", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "device_name": "EFM32GG990F1024", @@ -2374,7 +2375,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFM32LG", "256K", "SL_AES"], "core": "Cortex-M3", - "macros": ["EFM32LG990F256", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFM32LG990F256", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "device_name": "EFM32LG990F256", @@ -2428,7 +2429,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFM32WG", "256K", "SL_AES"], "core": "Cortex-M4F", - "macros": ["EFM32WG990F256", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFM32WG990F256", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "device_name": "EFM32WG990F256", @@ -2483,7 +2484,7 @@ "extra_labels_add": ["EFM32ZG", "32K", "SL_AES"], "core": "Cortex-M0+", "default_toolchain": "uARM", - "macros": ["EFM32ZG222F32", "TRANSACTION_QUEUE_SIZE_SPI=0"], + "macros_add": ["EFM32ZG222F32", "TRANSACTION_QUEUE_SIZE_SPI=0"], "supported_toolchains": ["GCC_ARM", "uARM", "IAR"], "default_lib": "small", "release_versions": ["2"], @@ -2537,7 +2538,7 @@ "extra_labels_add": ["EFM32HG", "64K", "SL_AES"], "core": "Cortex-M0+", "default_toolchain": "uARM", - "macros": ["EFM32HG322F64", "TRANSACTION_QUEUE_SIZE_SPI=0"], + "macros_add": ["EFM32HG322F64", "TRANSACTION_QUEUE_SIZE_SPI=0"], "supported_toolchains": ["GCC_ARM", "uARM", "IAR"], "default_lib": "small", "release_versions": ["2"], @@ -2590,7 +2591,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFM32PG", "256K", "SL_CRYPTO"], "core": "Cortex-M4F", - "macros": ["EFM32PG1B100F256GM32", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFM32PG1B100F256GM32", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "device_name": "EFM32PG1B100F256GM32", @@ -2643,7 +2644,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFR32MG1", "256K", "SL_RAIL", "SL_CRYPTO"], "core": "Cortex-M4F", - "macros": ["EFR32MG1P132F256GM48", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFR32MG1P132F256GM48", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "device_name": "EFR32MG1P132F256GM48", @@ -2654,7 +2655,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFR32MG1", "256K", "SL_RAIL", "SL_CRYPTO"], "core": "Cortex-M4F", - "macros": ["EFR32MG1P233F256GM48", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFR32MG1P233F256GM48", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "public": false, @@ -2744,7 +2745,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFM32PG12", "1024K", "SL_CRYPTO"], "core": "Cortex-M4F", - "macros": ["EFM32PG12B500F1024GL125", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFM32PG12B500F1024GL125", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "public": false, @@ -2796,7 +2797,7 @@ "inherits": ["EFM32"], "extra_labels_add": ["EFR32MG12", "1024K", "SL_RAIL", "SL_CRYPTO"], "core": "Cortex-M4F", - "macros": ["EFR32MG12P332F1024GL125", "TRANSACTION_QUEUE_SIZE_SPI=4"], + "macros_add": ["EFR32MG12P332F1024GL125", "TRANSACTION_QUEUE_SIZE_SPI=4"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "release_versions": ["2", "5"], "public": false,