added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_aes.c
- Revision:
- 144:ef7eb2e8f9f7
- Parent:
- 50:a417edff4437
diff -r 423e1876dc07 -r ef7eb2e8f9f7 targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_aes.c --- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_aes.c Tue Aug 02 14:07:36 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_aes.c Fri Sep 02 15:07:44 2016 +0100 @@ -1,1387 +1,1387 @@ -/***************************************************************************//** - * @file em_aes.c - * @brief Advanced Encryption Standard (AES) accelerator peripheral API. - * @version 4.2.1 - ******************************************************************************* - * @section License - * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> - ******************************************************************************* - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no - * obligation to support this Software. Silicon Labs is providing the - * Software "AS IS", with no express or implied warranties of any kind, - * including, but not limited to, any implied warranties of merchantability - * or fitness for any particular purpose or warranties against infringement - * of any proprietary rights of a third party. - * - * Silicon Labs will not be liable for any consequential, incidental, or - * special damages, or any other relief, or for any claim by any third party, - * arising from your use of this Software. - * - ******************************************************************************/ - -#include "em_aes.h" -#if defined(AES_COUNT) && (AES_COUNT > 0) - -#include "em_assert.h" -/***************************************************************************//** - * @addtogroup EM_Library - * @{ - ******************************************************************************/ - -/***************************************************************************//** - * @addtogroup AES - * @brief Advanced Encryption Standard Accelerator (AES) Peripheral API. - * @details - * This API is intended for use on Silicon Labs target devices, and the - * following input/output notations should be noted: - * - * @li Input/output data (plaintext, ciphertext, key etc) are treated as - * byte arrays, starting with most significant byte. Ie, 32 bytes of - * plaintext (B0...B31) is located in memory in the same order, with B0 at - * the lower address and B31 at the higher address. - * - * @li Byte arrays must always be a multiple of AES block size, ie a multiple - * of 16. Padding, if required, is done at the end of the byte array. - * - * @li Byte arrays should be word (32 bit) aligned for performance - * considerations, since the array is accessed with 32 bit access type. - * The Cortex-M supports unaligned accesses, but with a performance penalty. - * - * @li It is possible to specify the same output buffer as input buffer - * as long as they point to the same address. In that case the provided input - * buffer is replaced with the encrypted/decrypted output. Notice that the - * buffers must be exactly overlapping. If partly overlapping, the - * behaviour is undefined. - * - * It is up to the user to use a cipher mode according to its requirements - * in order to not break security. Please refer to specific cipher mode - * theory for details. - * - * References: - * @li Wikipedia - Cipher modes, http://en.wikipedia.org/wiki/Cipher_modes - * - * @li Recommendation for Block Cipher Modes of Operation, - * NIST Special Publication 800-38A, 2001 Edition, - * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - * @{ - ******************************************************************************/ - -/******************************************************************************* - ******************************* DEFINES *********************************** - ******************************************************************************/ - -/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ - -#define AES_BLOCKSIZE 16 - -/** @endcond */ - -/******************************************************************************* - ************************** GLOBAL FUNCTIONS ******************************* - ******************************************************************************/ - -/***************************************************************************//** - * @brief - * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key. - * - * @details - * Encryption: - * @verbatim - * Plaintext Plaintext - * | | - * V V - * InitVector ->XOR +-------------->XOR - * | | | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | encryption | | | encryption | - * +--------------+ | +--------------+ - * |---------+ | - * V V - * Ciphertext Ciphertext - * @endverbatim - * Decryption: - * @verbatim - * Ciphertext Ciphertext - * |----------+ | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | decryption | | | decryption | - * +--------------+ | +--------------+ - * | | | - * V | V - * InitVector ->XOR +-------------->XOR - * | | - * V V - * Plaintext Plaintext - * @endverbatim - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * When doing encryption, this is the 128 bit encryption key. When doing - * decryption, this is the 128 bit decryption key. The decryption key may - * be generated from the encryption key with AES_DecryptKey128(). - * On devices supporting key buffering this argument can be null, if so, the - * key will not be loaded, as it is assumed the key has been loaded - * into KEYHA previously. - * - * @param[in] iv - * 128 bit initalization vector to use. - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_CBC128(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv, - bool encrypt) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - /* Need to buffer one block when decrypting in case 'out' replaces 'in' */ - uint32_t prev[4]; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - /* Number of blocks to process */ - len /= AES_BLOCKSIZE; - - #if defined( AES_CTRL_KEYBUFEN ) - if (key) - { - /* Load key into high key for key buffer usage */ - for (i = 3; i >= 0; i--) - { - AES->KEYHA = __REV(_key[i]); - } - } - #endif - - if (encrypt) - { - /* Enable encryption with auto start using XOR */ - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_XORSTART; - #else - AES->CTRL = AES_CTRL_XORSTART; - #endif - - /* Load initialization vector, since writing to DATA, it will */ - /* not trigger encryption. */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_iv[i]); - } - - /* Encrypt data */ - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - /* Load data and trigger encryption */ - for (i = 3; i >= 0; i--) - { - AES->XORDATA = __REV(_in[i]); - } - _in += 4; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } - } - else - { - /* Select decryption mode */ - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; - #else - AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_DATASTART; - #endif - - /* Copy init vector to previous buffer to avoid special handling */ - for (i = 0; i < 4; i++) - { - prev[i] = _iv[i]; - } - - /* Decrypt data */ - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - /* Load data and trigger decryption */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_in[i]); - } - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* In order to avoid additional buffer, we use HW directly for XOR and buffer */ - /* (Writing to XORDATA will not trigger encoding, triggering enabled on DATA.) */ - for (i = 3; i >= 0; i--) - { - AES->XORDATA = __REV(prev[i]); - prev[i] = _in[i]; - } - _in += 4; - - /* Then fetch decrypted data, we have to do it in a separate loop */ - /* due to internal auto-shifting of words */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit key. - * - * @details - * Please see AES_CBC128() for CBC figure. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * When doing encryption, this is the 256 bit encryption key. When doing - * decryption, this is the 256 bit decryption key. The decryption key may - * be generated from the encryption key with AES_DecryptKey256(). - * - * @param[in] iv - * 128 bit initalization vector to use. - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_CBC256(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv, - bool encrypt) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - /* Need to buffer one block when decrypting in case output replaces input */ - uint32_t prev[4]; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - /* Number of blocks to process */ - len /= AES_BLOCKSIZE; - - if (encrypt) - { - /* Enable encryption with auto start using XOR */ - AES->CTRL = AES_CTRL_AES256 | AES_CTRL_XORSTART; - - /* Load initialization vector, since writing to DATA, it will */ - /* not trigger encryption. */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_iv[i]); - } - - /* Encrypt data */ - while (len--) - { - /* Load key and data and trigger encryption */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - /* Write data last, since will trigger encryption on last iteration */ - AES->XORDATA = __REV(_in[i]); - } - _in += 4; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } - } - else - { - /* Select decryption mode */ - AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DECRYPT | AES_CTRL_DATASTART; - - /* Copy init vector to previous buffer to avoid special handling */ - for (i = 0; i < 4; i++) - { - prev[i] = _iv[i]; - } - - /* Decrypt data */ - while (len--) - { - /* Load key and data and trigger decryption */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - /* Write data last, since will trigger encryption on last iteration */ - AES->DATA = __REV(_in[i]); - } - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* In order to avoid additional buffer, we use HW directly for XOR and buffer */ - for (i = 3; i >= 0; i--) - { - AES->XORDATA = __REV(prev[i]); - prev[i] = _in[i]; - } - _in += 4; - - /* Then fetch decrypted data, we have to do it in a separate loop */ - /* due to internal auto-shifting of words */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } - } -} -#endif - - -/***************************************************************************//** - * @brief - * Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. - * - * @details - * Encryption: - * @verbatim - * InitVector +----------------+ - * | | | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | encryption | | | encryption | - * +--------------+ | +--------------+ - * | | | - * V | V - * Plaintext ->XOR | Plaintext ->XOR - * |---------+ | - * V V - * Ciphertext Ciphertext - * @endverbatim - * Decryption: - * @verbatim - * InitVector +----------------+ - * | | | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | encryption | | | encryption | - * +--------------+ | +--------------+ - * | | | - * V | V - * XOR<- Ciphertext XOR<- Ciphertext - * | | - * V V - * Plaintext Plaintext - * @endverbatim - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 128 bit encryption key is used for both encryption and decryption modes. - * - * @param[in] iv - * 128 bit initalization vector to use. - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_CFB128(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv, - bool encrypt) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - const uint32_t *data; - uint32_t tmp[4]; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; - #else - AES->CTRL = AES_CTRL_DATASTART; - #endif - - #if defined( AES_CTRL_KEYBUFEN ) - /* Load key into high key for key buffer usage */ - for (i = 3; i >= 0; i--) - { - AES->KEYHA = __REV(_key[i]); - } - #endif - - /* Encrypt/decrypt data */ - data = _iv; - len /= AES_BLOCKSIZE; - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - /* Load data and trigger encryption */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(data[i]); - } - - /* Do some required processing before waiting for completion */ - if (encrypt) - { - data = _out; - } - else - { - /* Must copy current ciphertext block since it may be overwritten */ - for (i = 0; i < 4; i++) - { - tmp[i] = _in[i]; - } - data = tmp; - } - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. - * - * @details - * Please see AES_CFB128() for CFB figure. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 256 bit encryption key is used for both encryption and decryption modes. - * - * @param[in] iv - * 128 bit initalization vector to use. - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_CFB256(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv, - bool encrypt) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - const uint32_t *data; - uint32_t tmp[4]; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - /* Select encryption mode */ - AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; - - /* Encrypt/decrypt data */ - data = _iv; - len /= AES_BLOCKSIZE; - while (len--) - { - /* Load key and block to be encrypted/decrypted */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - /* Write data last, since will trigger encryption on last iteration */ - AES->DATA = __REV(data[i]); - } - - /* Do some required processing before waiting for completion */ - if (encrypt) - { - data = _out; - } - else - { - /* Must copy current ciphertext block since it may be overwritten */ - for (i = 0; i < 4; i++) - { - tmp[i] = _in[i]; - } - data = tmp; - } - - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} -#endif - - -/***************************************************************************//** - * @brief - * Counter (CTR) cipher mode encryption/decryption, 128 bit key. - * - * @details - * Encryption: - * @verbatim - * Counter Counter - * | | - * V V - * +--------------+ +--------------+ - * Key ->| Block cipher | Key ->| Block cipher | - * | encryption | | encryption | - * +--------------+ +--------------+ - * | | - * Plaintext ->XOR Plaintext ->XOR - * | | - * V V - * Ciphertext Ciphertext - * @endverbatim - * Decryption: - * @verbatim - * Counter Counter - * | | - * V V - * +--------------+ +--------------+ - * Key ->| Block cipher | Key ->| Block cipher | - * | encryption | | encryption | - * +--------------+ +--------------+ - * | | - * Ciphertext ->XOR Ciphertext ->XOR - * | | - * V V - * Plaintext Plaintext - * @endverbatim - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 128 bit encryption key. - * On devices supporting key buffering this argument can be null, if so, the - * key will not be loaded, as it is assumed the key has been loaded - * into KEYHA previously. - * - * @param[in,out] ctr - * 128 bit initial counter value. The counter is updated after each AES - * block encoding through use of @p ctrFunc. - * - * @param[in] ctrFunc - * Function used to update counter value. - ******************************************************************************/ -void AES_CTR128(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - uint8_t *ctr, - AES_CtrFuncPtr_TypeDef ctrFunc) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - uint32_t *_ctr = (uint32_t *)ctr; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - EFM_ASSERT(ctrFunc); - - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; - #else - AES->CTRL = AES_CTRL_DATASTART; - #endif - - #if defined( AES_CTRL_KEYBUFEN ) - if (key) - { - /* Load key into high key for key buffer usage */ - for (i = 3; i >= 0; i--) - { - AES->KEYHA = __REV(_key[i]); - } - } - #endif - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - /* Load ctr to be encrypted/decrypted */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_ctr[i]); - } - /* Increment ctr for next use */ - ctrFunc(ctr); - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Counter (CTR) cipher mode encryption/decryption, 256 bit key. - * - * @details - * Please see AES_CTR128() for CTR figure. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 256 bit encryption key. - * - * @param[in,out] ctr - * 128 bit initial counter value. The counter is updated after each AES - * block encoding through use of @p ctrFunc. - * - * @param[in] ctrFunc - * Function used to update counter value. - ******************************************************************************/ -void AES_CTR256(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - uint8_t *ctr, - AES_CtrFuncPtr_TypeDef ctrFunc) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - uint32_t *_ctr = (uint32_t *)ctr; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - EFM_ASSERT(ctrFunc); - - /* Select encryption mode, with auto trigger */ - AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - /* Load key and block to be encrypted/decrypted */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - /* Write data last, since will trigger encryption on last iteration */ - AES->DATA = __REV(_ctr[i]); - } - /* Increment ctr for next use */ - ctrFunc(ctr); - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} -#endif - - -/***************************************************************************//** - * @brief - * Update last 32 bits of 128 bit counter, by incrementing with 1. - * - * @details - * Notice that no special consideration is given to possible wrap around. If - * 32 least significant bits are 0xFFFFFFFF, they will be updated to 0x00000000, - * ignoring overflow. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[in,out] ctr - * Buffer holding 128 bit counter to be updated. - ******************************************************************************/ -void AES_CTRUpdate32Bit(uint8_t *ctr) -{ - uint32_t *_ctr = (uint32_t *)ctr; - - _ctr[3] = __REV(__REV(_ctr[3]) + 1); -} - - -/***************************************************************************//** - * @brief - * Generate 128 bit decryption key from 128 bit encryption key. The decryption - * key is used for some cipher modes when decrypting. - * - * @details - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place 128 bit decryption key. Must be at least 16 bytes long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding 128 bit encryption key. Must be at least 16 bytes long. - ******************************************************************************/ -void AES_DecryptKey128(uint8_t *out, const uint8_t *in) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_in[i]); - } - - /* Do dummy encryption to generate decrypt key */ - AES->CTRL = 0; - AES_IntClear(AES_IF_DONE); - AES->CMD = AES_CMD_START; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save decryption key */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->KEYLA); - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Generate 256 bit decryption key from 256 bit encryption key. The decryption - * key is used for some cipher modes when decrypting. - * - * @details - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place 256 bit decryption key. Must be at least 32 bytes long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding 256 bit encryption key. Must be at least 32 bytes long. - ******************************************************************************/ -void AES_DecryptKey256(uint8_t *out, const uint8_t *in) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - - /* Load key */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_in[j]); - AES->KEYHA = __REV(_in[i]); - } - - /* Do dummy encryption to generate decrypt key */ - AES->CTRL = AES_CTRL_AES256; - AES->CMD = AES_CMD_START; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save decryption key */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - _out[j] = __REV(AES->KEYLA); - _out[i] = __REV(AES->KEYHA); - } -} -#endif - - -/***************************************************************************//** - * @brief - * Electronic Codebook (ECB) cipher mode encryption/decryption, 128 bit key. - * - * @details - * Encryption: - * @verbatim - * Plaintext Plaintext - * | | - * V V - * +--------------+ +--------------+ - * Key ->| Block cipher | Key ->| Block cipher | - * | encryption | | encryption | - * +--------------+ +--------------+ - * | | - * V V - * Ciphertext Ciphertext - * @endverbatim - * Decryption: - * @verbatim - * Ciphertext Ciphertext - * | | - * V V - * +--------------+ +--------------+ - * Key ->| Block cipher | Key ->| Block cipher | - * | decryption | | decryption | - * +--------------+ +--------------+ - * | | - * V V - * Plaintext Plaintext - * @endverbatim - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * When doing encryption, this is the 128 bit encryption key. When doing - * decryption, this is the 128 bit decryption key. The decryption key may - * be generated from the encryption key with AES_DecryptKey128(). - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_ECB128(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - bool encrypt) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - #if defined( AES_CTRL_KEYBUFEN ) - /* Load key into high key for key buffer usage */ - for (i = 3; i >= 0; i--) - { - AES->KEYHA = __REV(_key[i]); - } - #endif - - if (encrypt) - { - /* Select encryption mode */ - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; - #else - AES->CTRL = AES_CTRL_DATASTART; - #endif - } - else - { - /* Select decryption mode */ - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; - #else - AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_DATASTART; - #endif - } - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - /* Load block to be encrypted/decrypted */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_in[i]); - } - _in += 4; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Electronic Codebook (ECB) cipher mode encryption/decryption, 256 bit key. - * - * @details - * Please see AES_ECB128() for ECB figure. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * When doing encryption, this is the 256 bit encryption key. When doing - * decryption, this is the 256 bit decryption key. The decryption key may - * be generated from the encryption key with AES_DecryptKey256(). - * - * @param[in] encrypt - * Set to true to encrypt, false to decrypt. - ******************************************************************************/ -void AES_ECB256(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - bool encrypt) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - if (encrypt) - { - /* Select encryption mode */ - AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; - } - else - { - /* Select decryption mode */ - AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_AES256 | AES_CTRL_DATASTART; - } - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - /* Load key and block to be encrypted/decrypted */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - /* Write data last, since will trigger encryption on last iteration */ - AES->DATA = __REV(_in[i]); - } - _in += 4; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA); - } - _out += 4; - } -} -#endif - - -/***************************************************************************//** - * @brief - * Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. - * - * @details - * Encryption: - * @verbatim - * InitVector +----------------+ - * | | | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | encryption | | | encryption | - * +--------------+ | +--------------+ - * | | | - * |---------+ | - * V V - * Plaintext ->XOR Plaintext ->XOR - * | | - * V V - * Ciphertext Ciphertext - * @endverbatim - * Decryption: - * @verbatim - * InitVector +----------------+ - * | | | - * V | V - * +--------------+ | +--------------+ - * Key ->| Block cipher | | Key ->| Block cipher | - * | encryption | | | encryption | - * +--------------+ | +--------------+ - * | | | - * |---------+ | - * V V - * Ciphertext ->XOR Ciphertext ->XOR - * | | - * V V - * Plaintext Plaintext - * @endverbatim - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 128 bit encryption key. - * - * @param[in] iv - * 128 bit initalization vector to use. - ******************************************************************************/ -void AES_OFB128(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv) -{ - int i; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - /* Select encryption mode, trigger explicitly by command */ - #if defined( AES_CTRL_KEYBUFEN ) - AES->CTRL = AES_CTRL_KEYBUFEN; - #else - AES->CTRL = 0; - #endif - - /* Load key into high key for key buffer usage */ - /* Load initialization vector */ - for (i = 3; i >= 0; i--) - { - #if defined( AES_CTRL_KEYBUFEN ) - AES->KEYHA = __REV(_key[i]); - #endif - AES->DATA = __REV(_iv[i]); - } - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - #if !defined( AES_CTRL_KEYBUFEN ) - /* Load key */ - for (i = 3; i >= 0; i--) - { - AES->KEYLA = __REV(_key[i]); - } - #endif - - AES->CMD = AES_CMD_START; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} - - -#if defined( AES_CTRL_AES256 ) -/***************************************************************************//** - * @brief - * Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. - * - * @details - * Please see AES_OFB128() for OFB figure. - * - * Please refer to general comments on layout and byte ordering of parameters. - * - * @param[out] out - * Buffer to place encrypted/decrypted data. Must be at least @p len long. It - * may be set equal to @p in, in which case the input buffer is overwritten. - * - * @param[in] in - * Buffer holding data to encrypt/decrypt. Must be at least @p len long. - * - * @param[in] len - * Number of bytes to encrypt/decrypt. Must be a multiple of 16. - * - * @param[in] key - * 256 bit encryption key. - * - * @param[in] iv - * 128 bit initalization vector to use. - ******************************************************************************/ -void AES_OFB256(uint8_t *out, - const uint8_t *in, - unsigned int len, - const uint8_t *key, - const uint8_t *iv) -{ - int i; - int j; - uint32_t *_out = (uint32_t *)out; - const uint32_t *_in = (const uint32_t *)in; - const uint32_t *_key = (const uint32_t *)key; - const uint32_t *_iv = (const uint32_t *)iv; - - EFM_ASSERT(!(len % AES_BLOCKSIZE)); - - /* Select encryption mode, trigger explicitly by command */ - AES->CTRL = AES_CTRL_AES256; - - /* Load initialization vector */ - for (i = 3; i >= 0; i--) - { - AES->DATA = __REV(_iv[i]); - } - - /* Encrypt/decrypt data */ - len /= AES_BLOCKSIZE; - while (len--) - { - /* Load key */ - for (i = 3, j = 7; i >= 0; i--, j--) - { - AES->KEYLA = __REV(_key[j]); - AES->KEYHA = __REV(_key[i]); - } - - AES->CMD = AES_CMD_START; - - /* Wait for completion */ - while (AES->STATUS & AES_STATUS_RUNNING) - ; - - /* Save encrypted/decrypted data */ - for (i = 3; i >= 0; i--) - { - _out[i] = __REV(AES->DATA) ^ _in[i]; - } - _out += 4; - _in += 4; - } -} -#endif - - -/** @} (end addtogroup AES) */ -/** @} (end addtogroup EM_Library) */ -#endif /* defined(AES_COUNT) && (AES_COUNT > 0) */ +/***************************************************************************//** + * @file em_aes.c + * @brief Advanced Encryption Standard (AES) accelerator peripheral API. + * @version 4.2.1 + ******************************************************************************* + * @section License + * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ + +#include "em_aes.h" +#if defined(AES_COUNT) && (AES_COUNT > 0) + +#include "em_assert.h" +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup AES + * @brief Advanced Encryption Standard Accelerator (AES) Peripheral API. + * @details + * This API is intended for use on Silicon Labs target devices, and the + * following input/output notations should be noted: + * + * @li Input/output data (plaintext, ciphertext, key etc) are treated as + * byte arrays, starting with most significant byte. Ie, 32 bytes of + * plaintext (B0...B31) is located in memory in the same order, with B0 at + * the lower address and B31 at the higher address. + * + * @li Byte arrays must always be a multiple of AES block size, ie a multiple + * of 16. Padding, if required, is done at the end of the byte array. + * + * @li Byte arrays should be word (32 bit) aligned for performance + * considerations, since the array is accessed with 32 bit access type. + * The Cortex-M supports unaligned accesses, but with a performance penalty. + * + * @li It is possible to specify the same output buffer as input buffer + * as long as they point to the same address. In that case the provided input + * buffer is replaced with the encrypted/decrypted output. Notice that the + * buffers must be exactly overlapping. If partly overlapping, the + * behaviour is undefined. + * + * It is up to the user to use a cipher mode according to its requirements + * in order to not break security. Please refer to specific cipher mode + * theory for details. + * + * References: + * @li Wikipedia - Cipher modes, http://en.wikipedia.org/wiki/Cipher_modes + * + * @li Recommendation for Block Cipher Modes of Operation, + * NIST Special Publication 800-38A, 2001 Edition, + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#define AES_BLOCKSIZE 16 + +/** @endcond */ + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Plaintext Plaintext + * | | + * V V + * InitVector ->XOR +-------------->XOR + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * |----------+ | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | decryption | | | decryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * InitVector ->XOR +-------------->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with AES_DecryptKey128(). + * On devices supporting key buffering this argument can be null, if so, the + * key will not be loaded, as it is assumed the key has been loaded + * into KEYHA previously. + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_CBC128(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv, + bool encrypt) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + /* Need to buffer one block when decrypting in case 'out' replaces 'in' */ + uint32_t prev[4]; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + /* Number of blocks to process */ + len /= AES_BLOCKSIZE; + + #if defined( AES_CTRL_KEYBUFEN ) + if (key) + { + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_key[i]); + } + } + #endif + + if (encrypt) + { + /* Enable encryption with auto start using XOR */ + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_XORSTART; + #else + AES->CTRL = AES_CTRL_XORSTART; + #endif + + /* Load initialization vector, since writing to DATA, it will */ + /* not trigger encryption. */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_iv[i]); + } + + /* Encrypt data */ + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + /* Load data and trigger encryption */ + for (i = 3; i >= 0; i--) + { + AES->XORDATA = __REV(_in[i]); + } + _in += 4; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } + } + else + { + /* Select decryption mode */ + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; + #else + AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_DATASTART; + #endif + + /* Copy init vector to previous buffer to avoid special handling */ + for (i = 0; i < 4; i++) + { + prev[i] = _iv[i]; + } + + /* Decrypt data */ + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + /* Load data and trigger decryption */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_in[i]); + } + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* In order to avoid additional buffer, we use HW directly for XOR and buffer */ + /* (Writing to XORDATA will not trigger encoding, triggering enabled on DATA.) */ + for (i = 3; i >= 0; i--) + { + AES->XORDATA = __REV(prev[i]); + prev[i] = _in[i]; + } + _in += 4; + + /* Then fetch decrypted data, we have to do it in a separate loop */ + /* due to internal auto-shifting of words */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_CBC128() for CBC figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with AES_DecryptKey256(). + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_CBC256(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv, + bool encrypt) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + /* Need to buffer one block when decrypting in case output replaces input */ + uint32_t prev[4]; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + /* Number of blocks to process */ + len /= AES_BLOCKSIZE; + + if (encrypt) + { + /* Enable encryption with auto start using XOR */ + AES->CTRL = AES_CTRL_AES256 | AES_CTRL_XORSTART; + + /* Load initialization vector, since writing to DATA, it will */ + /* not trigger encryption. */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_iv[i]); + } + + /* Encrypt data */ + while (len--) + { + /* Load key and data and trigger encryption */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + /* Write data last, since will trigger encryption on last iteration */ + AES->XORDATA = __REV(_in[i]); + } + _in += 4; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } + } + else + { + /* Select decryption mode */ + AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DECRYPT | AES_CTRL_DATASTART; + + /* Copy init vector to previous buffer to avoid special handling */ + for (i = 0; i < 4; i++) + { + prev[i] = _iv[i]; + } + + /* Decrypt data */ + while (len--) + { + /* Load key and data and trigger decryption */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + /* Write data last, since will trigger encryption on last iteration */ + AES->DATA = __REV(_in[i]); + } + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* In order to avoid additional buffer, we use HW directly for XOR and buffer */ + for (i = 3; i >= 0; i--) + { + AES->XORDATA = __REV(prev[i]); + prev[i] = _in[i]; + } + _in += 4; + + /* Then fetch decrypted data, we have to do it in a separate loop */ + /* due to internal auto-shifting of words */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } + } +} +#endif + + +/***************************************************************************//** + * @brief + * Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * Plaintext ->XOR | Plaintext ->XOR + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * XOR<- Ciphertext XOR<- Ciphertext + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key is used for both encryption and decryption modes. + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_CFB128(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv, + bool encrypt) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + const uint32_t *data; + uint32_t tmp[4]; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; + #else + AES->CTRL = AES_CTRL_DATASTART; + #endif + + #if defined( AES_CTRL_KEYBUFEN ) + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_key[i]); + } + #endif + + /* Encrypt/decrypt data */ + data = _iv; + len /= AES_BLOCKSIZE; + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + /* Load data and trigger encryption */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(data[i]); + } + + /* Do some required processing before waiting for completion */ + if (encrypt) + { + data = _out; + } + else + { + /* Must copy current ciphertext block since it may be overwritten */ + for (i = 0; i < 4; i++) + { + tmp[i] = _in[i]; + } + data = tmp; + } + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_CFB128() for CFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key is used for both encryption and decryption modes. + * + * @param[in] iv + * 128 bit initalization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_CFB256(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv, + bool encrypt) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + const uint32_t *data; + uint32_t tmp[4]; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + /* Select encryption mode */ + AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; + + /* Encrypt/decrypt data */ + data = _iv; + len /= AES_BLOCKSIZE; + while (len--) + { + /* Load key and block to be encrypted/decrypted */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + /* Write data last, since will trigger encryption on last iteration */ + AES->DATA = __REV(data[i]); + } + + /* Do some required processing before waiting for completion */ + if (encrypt) + { + data = _out; + } + else + { + /* Must copy current ciphertext block since it may be overwritten */ + for (i = 0; i < 4; i++) + { + tmp[i] = _in[i]; + } + data = tmp; + } + + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} +#endif + + +/***************************************************************************//** + * @brief + * Counter (CTR) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * On devices supporting key buffering this argument can be null, if so, the + * key will not be loaded, as it is assumed the key has been loaded + * into KEYHA previously. + * + * @param[in,out] ctr + * 128 bit initial counter value. The counter is updated after each AES + * block encoding through use of @p ctrFunc. + * + * @param[in] ctrFunc + * Function used to update counter value. + ******************************************************************************/ +void AES_CTR128(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + uint8_t *ctr, + AES_CtrFuncPtr_TypeDef ctrFunc) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + uint32_t *_ctr = (uint32_t *)ctr; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + EFM_ASSERT(ctrFunc); + + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; + #else + AES->CTRL = AES_CTRL_DATASTART; + #endif + + #if defined( AES_CTRL_KEYBUFEN ) + if (key) + { + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_key[i]); + } + } + #endif + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + /* Load ctr to be encrypted/decrypted */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_ctr[i]); + } + /* Increment ctr for next use */ + ctrFunc(ctr); + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Counter (CTR) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_CTR128() for CTR figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in,out] ctr + * 128 bit initial counter value. The counter is updated after each AES + * block encoding through use of @p ctrFunc. + * + * @param[in] ctrFunc + * Function used to update counter value. + ******************************************************************************/ +void AES_CTR256(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + uint8_t *ctr, + AES_CtrFuncPtr_TypeDef ctrFunc) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + uint32_t *_ctr = (uint32_t *)ctr; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + EFM_ASSERT(ctrFunc); + + /* Select encryption mode, with auto trigger */ + AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + /* Load key and block to be encrypted/decrypted */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + /* Write data last, since will trigger encryption on last iteration */ + AES->DATA = __REV(_ctr[i]); + } + /* Increment ctr for next use */ + ctrFunc(ctr); + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} +#endif + + +/***************************************************************************//** + * @brief + * Update last 32 bits of 128 bit counter, by incrementing with 1. + * + * @details + * Notice that no special consideration is given to possible wrap around. If + * 32 least significant bits are 0xFFFFFFFF, they will be updated to 0x00000000, + * ignoring overflow. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in,out] ctr + * Buffer holding 128 bit counter to be updated. + ******************************************************************************/ +void AES_CTRUpdate32Bit(uint8_t *ctr) +{ + uint32_t *_ctr = (uint32_t *)ctr; + + _ctr[3] = __REV(__REV(_ctr[3]) + 1); +} + + +/***************************************************************************//** + * @brief + * Generate 128 bit decryption key from 128 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place 128 bit decryption key. Must be at least 16 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding 128 bit encryption key. Must be at least 16 bytes long. + ******************************************************************************/ +void AES_DecryptKey128(uint8_t *out, const uint8_t *in) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_in[i]); + } + + /* Do dummy encryption to generate decrypt key */ + AES->CTRL = 0; + AES_IntClear(AES_IF_DONE); + AES->CMD = AES_CMD_START; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save decryption key */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->KEYLA); + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Generate 256 bit decryption key from 256 bit encryption key. The decryption + * key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place 256 bit decryption key. Must be at least 32 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding 256 bit encryption key. Must be at least 32 bytes long. + ******************************************************************************/ +void AES_DecryptKey256(uint8_t *out, const uint8_t *in) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + + /* Load key */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_in[j]); + AES->KEYHA = __REV(_in[i]); + } + + /* Do dummy encryption to generate decrypt key */ + AES->CTRL = AES_CTRL_AES256; + AES->CMD = AES_CMD_START; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save decryption key */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + _out[j] = __REV(AES->KEYLA); + _out[i] = __REV(AES->KEYHA); + } +} +#endif + + +/***************************************************************************//** + * @brief + * Electronic Codebook (ECB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Plaintext Plaintext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | decryption | | decryption | + * +--------------+ +--------------+ + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with AES_DecryptKey128(). + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_ECB128(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + bool encrypt) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + #if defined( AES_CTRL_KEYBUFEN ) + /* Load key into high key for key buffer usage */ + for (i = 3; i >= 0; i--) + { + AES->KEYHA = __REV(_key[i]); + } + #endif + + if (encrypt) + { + /* Select encryption mode */ + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; + #else + AES->CTRL = AES_CTRL_DATASTART; + #endif + } + else + { + /* Select decryption mode */ + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART; + #else + AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_DATASTART; + #endif + } + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + /* Load block to be encrypted/decrypted */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_in[i]); + } + _in += 4; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Electronic Codebook (ECB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_ECB128() for ECB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with AES_DecryptKey256(). + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void AES_ECB256(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + bool encrypt) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + if (encrypt) + { + /* Select encryption mode */ + AES->CTRL = AES_CTRL_AES256 | AES_CTRL_DATASTART; + } + else + { + /* Select decryption mode */ + AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_AES256 | AES_CTRL_DATASTART; + } + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + /* Load key and block to be encrypted/decrypted */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + /* Write data last, since will trigger encryption on last iteration */ + AES->DATA = __REV(_in[i]); + } + _in += 4; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA); + } + _out += 4; + } +} +#endif + + +/***************************************************************************//** + * @brief + * Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * + * @param[in] iv + * 128 bit initalization vector to use. + ******************************************************************************/ +void AES_OFB128(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv) +{ + int i; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + /* Select encryption mode, trigger explicitly by command */ + #if defined( AES_CTRL_KEYBUFEN ) + AES->CTRL = AES_CTRL_KEYBUFEN; + #else + AES->CTRL = 0; + #endif + + /* Load key into high key for key buffer usage */ + /* Load initialization vector */ + for (i = 3; i >= 0; i--) + { + #if defined( AES_CTRL_KEYBUFEN ) + AES->KEYHA = __REV(_key[i]); + #endif + AES->DATA = __REV(_iv[i]); + } + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + #if !defined( AES_CTRL_KEYBUFEN ) + /* Load key */ + for (i = 3; i >= 0; i--) + { + AES->KEYLA = __REV(_key[i]); + } + #endif + + AES->CMD = AES_CMD_START; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} + + +#if defined( AES_CTRL_AES256 ) +/***************************************************************************//** + * @brief + * Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see AES_OFB128() for OFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in] iv + * 128 bit initalization vector to use. + ******************************************************************************/ +void AES_OFB256(uint8_t *out, + const uint8_t *in, + unsigned int len, + const uint8_t *key, + const uint8_t *iv) +{ + int i; + int j; + uint32_t *_out = (uint32_t *)out; + const uint32_t *_in = (const uint32_t *)in; + const uint32_t *_key = (const uint32_t *)key; + const uint32_t *_iv = (const uint32_t *)iv; + + EFM_ASSERT(!(len % AES_BLOCKSIZE)); + + /* Select encryption mode, trigger explicitly by command */ + AES->CTRL = AES_CTRL_AES256; + + /* Load initialization vector */ + for (i = 3; i >= 0; i--) + { + AES->DATA = __REV(_iv[i]); + } + + /* Encrypt/decrypt data */ + len /= AES_BLOCKSIZE; + while (len--) + { + /* Load key */ + for (i = 3, j = 7; i >= 0; i--, j--) + { + AES->KEYLA = __REV(_key[j]); + AES->KEYHA = __REV(_key[i]); + } + + AES->CMD = AES_CMD_START; + + /* Wait for completion */ + while (AES->STATUS & AES_STATUS_RUNNING) + ; + + /* Save encrypted/decrypted data */ + for (i = 3; i >= 0; i--) + { + _out[i] = __REV(AES->DATA) ^ _in[i]; + } + _out += 4; + _in += 4; + } +} +#endif + + +/** @} (end addtogroup AES) */ +/** @} (end addtogroup EM_Library) */ +#endif /* defined(AES_COUNT) && (AES_COUNT > 0) */