mbed library sources. Supersedes mbed-src.
Fork of mbed-dev by
Diff: targets/TARGET_NUVOTON/TARGET_NUC472/crypto/aes/aes_alt.c
- Revision:
- 149:156823d33999
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/crypto/aes/aes_alt.c Fri Oct 28 11:17:30 2016 +0100 @@ -0,0 +1,590 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015-2016 Nuvoton + * + * 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. + */ + +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_AES_ALT) + +#include <string.h> + +#include "mbedtls/aes.h" + +#include "NUC472_442.h" +#include "toolchain.h" +#include "mbed_assert.h" + +//static int aes_init_done = 0; + + +#define mbedtls_trace(...) //printf(__VA_ARGS__) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + + +static uint32_t au32MyAESIV[4] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +extern volatile int g_AES_done; + +// Must be a multiple of 16 bytes block size +#define MAX_DMA_CHAIN_SIZE (16*6) +static uint8_t au8OutputData[MAX_DMA_CHAIN_SIZE] MBED_ALIGN(4); +static uint8_t au8InputData[MAX_DMA_CHAIN_SIZE] MBED_ALIGN(4); + +static void dumpHex(const unsigned char au8Data[], int len) +{ + int j; + for (j = 0; j < len; j++) mbedtls_trace("%02x ", au8Data[j]); + mbedtls_trace("\r\n"); +} + +static void swapInitVector(unsigned char iv[16]) +{ + unsigned int* piv; + int i; + // iv SWAP + piv = (unsigned int*)iv; + for( i=0; i< 4; i++) + { + *piv = (((*piv) & 0x000000FF) << 24) | + (((*piv) & 0x0000FF00) << 8) | + (((*piv) & 0x00FF0000) >> 8) | + (((*piv) & 0xFF000000) >> 24); + piv++; + } +} + +//volatile void CRYPTO_IRQHandler() +//{ +// if (AES_GET_INT_FLAG()) { +// g_AES_done = 1; +// AES_CLR_INT_FLAG(); +// } +//} + +// AES available channel 0~3 +static unsigned char channel_flag[4]={0x00,0x00,0x00,0x00}; // 0: idle, 1: busy +static int channel_alloc() +{ + int i; + for(i=0; i< (int)sizeof(channel_flag); i++) + { + if( channel_flag[i] == 0x00 ) + { + channel_flag[i] = 0x01; + return i; + } + } + return(-1); +} + +static void channel_free(int i) +{ + if( i >=0 && i < (int)sizeof(channel_flag) ) + channel_flag[i] = 0x00; +} + + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + int i =-1; + +// sw_mbedtls_aes_init(ctx); +// return; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); + + ctx->swapType = AES_IN_OUT_SWAP; + while( (i = channel_alloc()) < 0 ) + { + mbed_assert_internal("No available AES channel", __FILE__, __LINE__); + //osDelay(300); + } + ctx->channel = i; + ctx->iv = au32MyAESIV; + + /* Unlock protected registers */ + SYS_UnlockReg(); + CLK_EnableModuleClock(CRPT_MODULE); + /* Lock protected registers */ + SYS_LockReg(); + + NVIC_EnableIRQ(CRPT_IRQn); + AES_ENABLE_INT(); + mbedtls_trace("=== %s channel[%d]\r\n", __FUNCTION__, (int)ctx->channel); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + + mbedtls_trace("=== %s channel[%d]\r\n", __FUNCTION__,(int)ctx->channel); + + if( ctx == NULL ) + return; + + /* Unlock protected registers */ +// SYS_UnlockReg(); +// CLK_DisableModuleClock(CRPT_MODULE); + /* Lock protected registers */ +// SYS_LockReg(); + +// NVIC_DisableIRQ(CRPT_IRQn); +// AES_DISABLE_INT(); + channel_free(ctx->channel); + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * AES key schedule (encryption) + */ +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + + mbedtls_trace("=== %s keybits[%d]\r\n", __FUNCTION__, keybits); + dumpHex(key,keybits/8); + + switch( keybits ) + { + case 128: + ctx->keySize = AES_KEY_SIZE_128; + break; + case 192: + ctx->keySize = AES_KEY_SIZE_192; + break; + case 256: + ctx->keySize = AES_KEY_SIZE_256; + break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + + + // key swap + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + ctx->buf[i] = (*(key+i*4) << 24) | + (*(key+1+i*4) << 16) | + (*(key+2+i*4) << 8) | + (*(key+3+i*4) ); + } + AES_SetKey(ctx->channel, ctx->buf, ctx->keySize); + + + return( 0 ); +} +#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int ret; + + mbedtls_trace("=== %s keybits[%d]\r\n", __FUNCTION__, keybits); + dumpHex((uint8_t *)key,keybits/8); + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( ctx, key, keybits ) ) != 0 ) + goto exit; + +exit: + + return( ret ); +} +#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */ + + +static void __nvt_aes_crypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16], int dataSize) +{ + unsigned char* pIn; + unsigned char* pOut; + +// mbedtls_trace("=== %s \r\n", __FUNCTION__); + dumpHex(input,16); + + AES_Open(ctx->channel, ctx->encDec, ctx->opMode, ctx->keySize, ctx->swapType); + AES_SetInitVect(ctx->channel, ctx->iv); + if( ((uint32_t)input) & 0x03 ) + { + memcpy(au8InputData, input, dataSize); + pIn = au8InputData; + }else{ + pIn = (unsigned char*)input; + } + if( (((uint32_t)output) & 0x03) || (dataSize%4)) // HW CFB output byte count must be multiple of word + { + pOut = au8OutputData; + } else { + pOut = output; + } + + AES_SetDMATransfer(ctx->channel, (uint32_t)pIn, (uint32_t)pOut, dataSize); + + g_AES_done = 0; + AES_Start(ctx->channel, CRYPTO_DMA_ONE_SHOT); + while (!g_AES_done); + + if( pOut != output ) memcpy(output, au8OutputData, dataSize); + dumpHex(output,16); + +} + +/* + * AES-ECB block encryption + */ +#if defined(MBEDTLS_AES_ENCRYPT_ALT) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, 16); + +} +#endif /* MBEDTLS_AES_ENCRYPT_ALT */ + +/* + * AES-ECB block decryption + */ +#if defined(MBEDTLS_AES_DECRYPT_ALT) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, 16); + + +} +#endif /* MBEDTLS_AES_DECRYPT_ALT */ + +/* + * 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] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->opMode = AES_MODE_ECB; + if( mode == MBEDTLS_AES_ENCRYPT ) + mbedtls_aes_encrypt( ctx, input, output ); + else + mbedtls_aes_decrypt( ctx, input, output ); + + + 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 len, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char temp[16]; + int length = len; + int blockChainLen; + mbedtls_trace("=== %s [0x%x]\r\n", __FUNCTION__,length); + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + + if( (((uint32_t)input) & 0x03) || (((uint32_t)output) & 0x03) ) + { + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? MAX_DMA_CHAIN_SIZE : length ); + } else { + blockChainLen = length; + } + + while( length > 0 ) + { + ctx->opMode = AES_MODE_CBC; + swapInitVector(iv); // iv SWAP + ctx->iv = (uint32_t *)iv; + + if( mode == MBEDTLS_AES_ENCRYPT ) + { + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, blockChainLen); +// if( blockChainLen == length ) break; // finish last block chain but still need to prepare next iv for mbedtls_aes_self_test() + memcpy( iv, output+blockChainLen-16, 16 ); + }else{ + memcpy( temp, input+blockChainLen-16, 16 ); + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, blockChainLen); +// if( blockChainLen == length ) break; // finish last block chain but still need to prepare next iv for mbedtls_aes_self_test() + memcpy( iv, temp, 16 ); + } + length -= blockChainLen; + input += blockChainLen; + output += blockChainLen; + if(length < MAX_DMA_CHAIN_SIZE ) blockChainLen = length; // For last remainder block chain + + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +/* Support partial block encryption/decryption */ +static int __nvt_aes_crypt_partial_block_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 ) +{ + int c; + size_t n = *iv_off; + unsigned char iv_tmp[16]; + mbedtls_trace("=== %s \r\n", __FUNCTION__); + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + else if( ctx->opMode == AES_MODE_CFB) // For previous cryption is CFB mode + { + memcpy(iv_tmp, iv, n); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, ctx->prv_iv, iv ); + memcpy(iv, iv_tmp, n); + } + + 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 ); + else if( ctx->opMode == AES_MODE_CFB) // For previous cryption is CFB mode + { + memcpy(iv_tmp, iv, n); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, ctx->prv_iv, iv ); + memcpy(iv, iv_tmp, n); + } + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t len, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n = *iv_off; + unsigned char temp[16]; + int length=len; + int blockChainLen; + int remLen=0; + int ivLen; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + // proceed: start with partial block by ECB mode first + if( n !=0 ) { + __nvt_aes_crypt_partial_block_cfb128(ctx, mode, 16 - n , iv_off, iv, input, output); + input += (16 - n); + output += (16 - n); + length -= (16 - n); + } + + // For address or byte count non-word alignment, go through reserved DMA buffer. + if( (((uint32_t)input) & 0x03) || (((uint32_t)output) & 0x03) ) // Must reserved DMA buffer for each block + { + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? MAX_DMA_CHAIN_SIZE : length ); + } else if(length%4) { // Need reserved DMA buffer once for last chain + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? (length - length%16) : length ); + } else { // Not need reserved DMA buffer + blockChainLen = length; + } + + // proceed: start with block alignment + while( length > 0 ) + { + + ctx->opMode = AES_MODE_CFB; + + swapInitVector(iv); // iv SWAP + + ctx->iv = (uint32_t *)iv; + remLen = blockChainLen%16; + ivLen = (( remLen > 0) ? remLen: 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy(temp, input+blockChainLen - ivLen, ivLen); + if(blockChainLen >= 16) memcpy(ctx->prv_iv, input+blockChainLen-remLen-16 , 16); + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, blockChainLen); + memcpy(iv,temp, ivLen); + } + else + { + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, blockChainLen); + if(blockChainLen >= 16) memcpy(ctx->prv_iv, output+blockChainLen-remLen-16 , 16); + memcpy(iv,output+blockChainLen-ivLen,ivLen); + } + length -= blockChainLen; + input += blockChainLen; + output += blockChainLen; + if(length < MAX_DMA_CHAIN_SIZE ) blockChainLen = length; // For last remainder block chain + } + + *iv_off = remLen; + + 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]; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + 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 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 ) +{ + int c, i; + size_t n = *nc_off; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* MBEDTLS_AES_ALT */ + + +#endif /* MBEDTLS_AES_C */