onelife.real ea6d73f140 *** EFM32 branch ***
1. Upgrade Cortex driver library (CMSIS -> CMSIS & Device): version 2.3.2 -> 3.0.1 & 3.0.0
 - Remove "bsp/efm32/Libraries/CMSIS/Lib/ARM", "bsp/efm32/Libraries/CMSIS/Lib/G++" and "bsp/efm32/Libraries/CMSIS/SVD" to save space
2. Upgrade EFM32 driver libraries (efm32lib -> emlib): version 2.3.2 -> 3.0.0
 - Remove "bsp/efm32/Libraries/Device/EnergyMicro/EFM32LG" and "bsp/efm32/Libraries/Device/EnergyMicro/EFM32TG" to save space
3. Upgrade EFM32GG_DK3750 development kit driver library: version 1.2.2 -> 2.0.1
4. Upgrade EFM32_Gxxx_DK development kit driver library: version 1.7.3 -> 2.0.1
5. Add energy management unit driver and test code
6. Modify linker script and related code to compatible with new version of libraries
7. Change EFM32 branch version number to 1.0
8. Add photo frame demo application

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2122 bbd45198-f89e-11dd-88c7-29a3b14d5316
2012-05-18 04:40:40 +00:00

1292 lines
40 KiB
C

/***************************************************************************//**
* @file
* @brief Advanced Encryption Standard (AES) accelerator peripheral API
* @author Energy Micro AS
* @version 3.0.0
*******************************************************************************
* @section License
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.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: Energy Micro AS has no
* obligation to support this Software. Energy Micro AS 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.
*
* Energy Micro AS 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"
#include "em_assert.h"
#if defined(AES_COUNT) && (AES_COUNT > 0)
/***************************************************************************//**
* @addtogroup EM_Library
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup AES
* @brief Advanced Encryption Standard Accelerator (AES) Peripheral API for
* EFM32
* @details
* This API is intended for use on EFM32 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 EFM32 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().
* If this argument is null, 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 *_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 (key)
{
const uint32_t *_key = (const uint32_t *)key;
/* Load key into high key for key buffer usage */
for (i = 3; i >= 0; i--)
{
AES->KEYHA = __REV(_key[i]);
}
}
if (encrypt)
{
/* Enable encryption with auto start using XOR */
AES->CTRL = AES_CTRL_KEYBUFEN | 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 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 */
AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | 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 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;
}
}
}
/***************************************************************************//**
* @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;
}
}
}
/***************************************************************************//**
* @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));
/* Select encryption mode */
AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART;
/* Load key into high key for key buffer usage */
for (i = 3; i >= 0; i--)
{
AES->KEYHA = __REV(_key[i]);
}
/* Encrypt/decrypt data */
data = _iv;
len /= AES_BLOCKSIZE;
while (len--)
{
/* 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;
}
}
/***************************************************************************//**
* @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;
}
}
/***************************************************************************//**
* @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.
* If this argument is null, 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;
uint32_t *_ctr = (uint32_t *)ctr;
EFM_ASSERT(!(len % AES_BLOCKSIZE));
EFM_ASSERT(ctrFunc);
/* Select encryption mode, with auto trigger */
AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART;
if (key)
{
const uint32_t *_key = (const uint32_t *)key;
/* Load key into high key for key buffer usage */
for (i = 3; i >= 0; i--)
{
AES->KEYHA = __REV(_key[i]);
}
}
/* Encrypt/decrypt data */
len /= AES_BLOCKSIZE;
while (len--)
{
/* 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;
}
}
/***************************************************************************//**
* @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;
}
}
/***************************************************************************//**
* @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);
}
}
/***************************************************************************//**
* @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);
}
}
/***************************************************************************//**
* @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));
/* Load key into high key for key buffer usage */
for (i = 3; i >= 0; i--)
{
AES->KEYHA = __REV(_key[i]);
}
if (encrypt)
{
/* Select encryption mode */
AES->CTRL = AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART;
}
else
{
/* Select decryption mode */
AES->CTRL = AES_CTRL_DECRYPT | AES_CTRL_KEYBUFEN | AES_CTRL_DATASTART;
}
/* Encrypt/decrypt data */
len /= AES_BLOCKSIZE;
while (len--)
{
/* 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;
}
}
/***************************************************************************//**
* @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;
}
}
/***************************************************************************//**
* @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 */
AES->CTRL = AES_CTRL_KEYBUFEN;
/* Load key into high key for key buffer usage */
/* Load initialization vector */
for (i = 3; i >= 0; i--)
{
AES->KEYHA = __REV(_key[i]);
AES->DATA = __REV(_iv[i]);
}
/* Encrypt/decrypt data */
len /= AES_BLOCKSIZE;
while (len--)
{
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;
}
}
/***************************************************************************//**
* @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;
}
}
/** @} (end addtogroup AES) */
/** @} (end addtogroup EM_Library) */
#endif /* defined(AES_COUNT) && (AES_COUNT > 0) */