1823 lines
66 KiB
C
1823 lines
66 KiB
C
/***************************************************************************//**
|
|
* @file em_crypto.c
|
|
* @brief Cryptography accelerator peripheral API
|
|
* @version 5.2.2
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2016 Silicon Laboratories, Inc. 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.@n
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.@n
|
|
* 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_device.h"
|
|
|
|
#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0)
|
|
|
|
#include "em_crypto.h"
|
|
#include "em_assert.h"
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup emlib
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup CRYPTO
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
******************************* DEFINES ***********************************
|
|
******************************************************************************/
|
|
|
|
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
|
|
|
#define CRYPTO_INSTRUCTIONS_PER_REG (4)
|
|
#define CRYPTO_INSTRUCTIONS_MAX (12)
|
|
#define CRYPTO_INSTRUCTION_REGS (CRYPTO_INSTRUCTIONS_MAX / CRYPTO_INSTRUCTIONS_PER_REG)
|
|
|
|
#define CRYPTO_SHA1_BLOCK_SIZE_IN_BITS (512)
|
|
#define CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES (CRYPTO_SHA1_BLOCK_SIZE_IN_BITS / 8)
|
|
#define CRYPTO_SHA1_BLOCK_SIZE_IN_32BIT_WORDS (CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES / sizeof(uint32_t))
|
|
#define CRYPTO_SHA1_DIGEST_SIZE_IN_32BIT_WORDS (CRYPTO_SHA1_DIGEST_SIZE_IN_BYTES / sizeof(uint32_t))
|
|
|
|
#define CRYPTO_SHA256_BLOCK_SIZE_IN_BITS (512)
|
|
#define CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES (CRYPTO_SHA256_BLOCK_SIZE_IN_BITS / 8)
|
|
#define CRYPTO_SHA256_BLOCK_SIZE_IN_32BIT_WORDS (CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES / sizeof(uint32_t))
|
|
|
|
#define CRYPTO_SHA256_DIGEST_SIZE_IN_32BIT_WORDS (CRYPTO_SHA256_DIGEST_SIZE_IN_BYTES / sizeof(uint32_t))
|
|
|
|
#define PARTIAL_OPERAND_WIDTH_LOG2 (7) /* 2^7 = 128 */
|
|
#define PARTIAL_OPERAND_WIDTH (1 << PARTIAL_OPERAND_WIDTH_LOG2)
|
|
#define PARTIAL_OPERAND_WIDTH_MASK (PARTIAL_OPERAND_WIDTH - 1)
|
|
#define PARTIAL_OPERAND_WIDTH_IN_BYTES (PARTIAL_OPERAND_WIDTH / 8)
|
|
#define PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS (PARTIAL_OPERAND_WIDTH_IN_BYTES / sizeof(uint32_t))
|
|
|
|
#define SWAP32(x) (__REV(x))
|
|
|
|
#define CRYPTO_AES_BLOCKSIZE (16)
|
|
|
|
/*******************************************************************************
|
|
*********************** STATIC FUNCTIONS **********************************
|
|
******************************************************************************/
|
|
|
|
static inline void CRYPTO_AES_ProcessLoop(CRYPTO_TypeDef *crypto,
|
|
uint32_t len,
|
|
CRYPTO_DataReg_TypeDef inReg,
|
|
uint32_t * in,
|
|
CRYPTO_DataReg_TypeDef outReg,
|
|
uint32_t * out);
|
|
|
|
static void CRYPTO_AES_CBCx(CRYPTO_TypeDef *crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth);
|
|
|
|
static void CRYPTO_AES_CFBx(CRYPTO_TypeDef *crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth);
|
|
|
|
static void CRYPTO_AES_CTRx(CRYPTO_TypeDef *crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
uint8_t * ctr,
|
|
CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth);
|
|
|
|
static void CRYPTO_AES_ECBx(CRYPTO_TypeDef *crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth);
|
|
|
|
static void CRYPTO_AES_OFBx(CRYPTO_TypeDef *crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth);
|
|
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Write variable sized 32 bit data array (max 128 bits) to a DATAX register
|
|
*
|
|
* @details
|
|
* Write variable sized 32 bit array (max 128 bits / 4 words) to a DATAX
|
|
* register in the CRYPTO module.
|
|
*
|
|
* @param[in] dataReg The 128 bits DATA register.
|
|
* @param[in] val Value of the data to write to the DATA register.
|
|
* @param[in] valSize Size of @ref val in number of 32bit words.
|
|
******************************************************************************/
|
|
__STATIC_INLINE
|
|
void CRYPTO_DataWriteVariableSize(CRYPTO_DataReg_TypeDef dataReg,
|
|
const CRYPTO_Data_TypeDef val,
|
|
int valSize)
|
|
{
|
|
int i;
|
|
volatile uint32_t * reg = (volatile uint32_t *) dataReg;
|
|
|
|
if (valSize < 4) {
|
|
/* Non optimal write of data. */
|
|
for (i = 0; i < valSize; i++) {
|
|
*reg = *val++;
|
|
}
|
|
for (; i < 4; i++) {
|
|
*reg = 0;
|
|
}
|
|
} else {
|
|
CRYPTO_BurstToCrypto(reg, &val[0]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/** @endcond */
|
|
|
|
/*******************************************************************************
|
|
************************** GLOBAL FUNCTIONS *******************************
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Set the modulus used for wide modular operations.
|
|
*
|
|
* @details
|
|
* This function sets the modulus to be used by the modular instructions
|
|
* of the CRYPTO module.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @param[in] modulusId
|
|
* Modulus identifier.
|
|
******************************************************************************/
|
|
void CRYPTO_ModulusSet(CRYPTO_TypeDef * crypto,
|
|
CRYPTO_ModulusId_TypeDef modulusId)
|
|
{
|
|
uint32_t temp = crypto->WAC & (~(_CRYPTO_WAC_MODULUS_MASK | _CRYPTO_WAC_MODOP_MASK));
|
|
|
|
switch (modulusId) {
|
|
case cryptoModulusBin256:
|
|
case cryptoModulusBin128:
|
|
case cryptoModulusGcmBin128:
|
|
case cryptoModulusEccB233:
|
|
case cryptoModulusEccB163:
|
|
#ifdef _CRYPTO_WAC_MODULUS_ECCBIN233N
|
|
case cryptoModulusEccB233Order:
|
|
case cryptoModulusEccB233KOrder:
|
|
case cryptoModulusEccB163Order:
|
|
case cryptoModulusEccB163KOrder:
|
|
#endif
|
|
crypto->WAC = temp | modulusId | CRYPTO_WAC_MODOP_BINARY;
|
|
break;
|
|
|
|
case cryptoModulusEccP256:
|
|
case cryptoModulusEccP224:
|
|
case cryptoModulusEccP192:
|
|
#ifdef _CRYPTO_WAC_MODULUS_ECCPRIME256P
|
|
case cryptoModulusEccP256Order:
|
|
case cryptoModulusEccP224Order:
|
|
case cryptoModulusEccP192Order:
|
|
#endif
|
|
crypto->WAC = temp | modulusId | CRYPTO_WAC_MODOP_REGULAR;
|
|
break;
|
|
|
|
default:
|
|
/* Unknown modulus identifier. */
|
|
EFM_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Read the key value currently used by the CRYPTO module.
|
|
*
|
|
* @details
|
|
* Read 128 bits or 256 bits from KEY register in the CRYPTO module.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @param[in] val
|
|
* Value of the data to write to the KEYBUF register.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Key width - 128 or 256 bits
|
|
******************************************************************************/
|
|
void CRYPTO_KeyRead(CRYPTO_TypeDef * crypto,
|
|
CRYPTO_KeyBuf_TypeDef val,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
EFM_ASSERT(val);
|
|
|
|
CRYPTO_BurstFromCrypto(&crypto->KEY, &val[0]);
|
|
if (keyWidth == cryptoKey256Bits) {
|
|
CRYPTO_BurstFromCrypto(&crypto->KEY, &val[4]);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Perform a SHA-1 hash operation on a message.
|
|
*
|
|
* @details
|
|
* This function performs a SHA-1 hash operation on the message specified by
|
|
* msg with length msgLen, and returns the message digest in msgDigest.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @param[in] msg
|
|
* Message to hash.
|
|
*
|
|
* @param[in] msgLen
|
|
* Length of message in bytes.
|
|
*
|
|
* @param[out] msgDigest
|
|
* Message digest.
|
|
******************************************************************************/
|
|
void CRYPTO_SHA_1(CRYPTO_TypeDef * crypto,
|
|
const uint8_t * msg,
|
|
uint64_t msgLen,
|
|
CRYPTO_SHA1_Digest_TypeDef msgDigest)
|
|
{
|
|
uint32_t temp;
|
|
uint32_t len;
|
|
int blockLen;
|
|
uint32_t shaBlock[CRYPTO_SHA1_BLOCK_SIZE_IN_32BIT_WORDS] =
|
|
{
|
|
/* Initial value */
|
|
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
|
|
};
|
|
uint8_t * p8ShaBlock = (uint8_t *) shaBlock;
|
|
|
|
/* Initialize crypto module to do SHA-1. */
|
|
crypto->CTRL = CRYPTO_CTRL_SHA_SHA1;
|
|
crypto->SEQCTRL = 0;
|
|
crypto->SEQCTRLB = 0;
|
|
|
|
/* Set result width of MADD32 operation. */
|
|
CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits);
|
|
|
|
/* Write init value to DDATA1. */
|
|
CRYPTO_DDataWrite(&crypto->DDATA1, shaBlock);
|
|
|
|
/* Copy data to DDATA0 and select DDATA0 and DDATA1 for SHA operation. */
|
|
CRYPTO_EXECUTE_2(crypto,
|
|
CRYPTO_CMD_INSTR_DDATA1TODDATA0,
|
|
CRYPTO_CMD_INSTR_SELDDATA0DDATA1);
|
|
|
|
len = msgLen;
|
|
|
|
while (len >= CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES) {
|
|
/* Write block to QDATA1. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t *) msg);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
|
|
len -= CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES;
|
|
msg += CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES;
|
|
}
|
|
|
|
blockLen = 0;
|
|
|
|
/* Build the last (or second to last) block */
|
|
for (; len; len--) {
|
|
p8ShaBlock[blockLen++] = *msg++;
|
|
}
|
|
|
|
/* append the '1' bit */
|
|
p8ShaBlock[blockLen++] = 0x80;
|
|
|
|
/* if the length is currently above 56 bytes we append zeros
|
|
* then compress. Then we can fall back to padding zeros and length
|
|
* encoding like normal.
|
|
*/
|
|
if (blockLen > 56) {
|
|
while (blockLen < 64)
|
|
p8ShaBlock[blockLen++] = 0;
|
|
|
|
/* Write block to QDATA1BIG. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
blockLen = 0;
|
|
}
|
|
|
|
/* pad upto 56 bytes of zeroes */
|
|
while (blockLen < 56)
|
|
p8ShaBlock[blockLen++] = 0;
|
|
|
|
/* And finally, encode the message length. */
|
|
{
|
|
uint64_t msgLenInBits = msgLen << 3;
|
|
temp = msgLenInBits >> 32;
|
|
*(uint32_t*)&p8ShaBlock[56] = SWAP32(temp);
|
|
temp = msgLenInBits & 0xFFFFFFFF;
|
|
*(uint32_t*)&p8ShaBlock[60] = SWAP32(temp);
|
|
}
|
|
|
|
/* Write block to QDATA1BIG. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
|
|
/* Read resulting message digest from DDATA0BIG. */
|
|
((uint32_t*)msgDigest)[0] = crypto->DDATA0BIG;
|
|
((uint32_t*)msgDigest)[1] = crypto->DDATA0BIG;
|
|
((uint32_t*)msgDigest)[2] = crypto->DDATA0BIG;
|
|
((uint32_t*)msgDigest)[3] = crypto->DDATA0BIG;
|
|
((uint32_t*)msgDigest)[4] = crypto->DDATA0BIG;
|
|
temp = crypto->DDATA0BIG;
|
|
temp = crypto->DDATA0BIG;
|
|
temp = crypto->DDATA0BIG;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Perform a SHA-256 hash operation on a message.
|
|
*
|
|
* @details
|
|
* This function performs a SHA-256 hash operation on the message specified
|
|
* by msg with length msgLen, and returns the message digest in msgDigest.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @param[in] msg
|
|
* Message to hash.
|
|
*
|
|
* @param[in] msgLen
|
|
* Length of message in bytes.
|
|
*
|
|
* @param[out] msgDigest
|
|
* Message digest.
|
|
******************************************************************************/
|
|
void CRYPTO_SHA_256(CRYPTO_TypeDef * crypto,
|
|
const uint8_t * msg,
|
|
uint64_t msgLen,
|
|
CRYPTO_SHA256_Digest_TypeDef msgDigest)
|
|
{
|
|
uint32_t temp;
|
|
uint32_t len;
|
|
int blockLen;
|
|
uint32_t shaBlock[CRYPTO_SHA256_BLOCK_SIZE_IN_32BIT_WORDS] =
|
|
{
|
|
/* Initial value */
|
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
|
};
|
|
uint8_t * p8ShaBlock = (uint8_t *) shaBlock;
|
|
|
|
/* Initialize crypyo module to do SHA-256 (SHA-2). */
|
|
crypto->CTRL = CRYPTO_CTRL_SHA_SHA2;
|
|
crypto->SEQCTRL = 0;
|
|
crypto->SEQCTRLB = 0;
|
|
|
|
/* Set result width of MADD32 operation. */
|
|
CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits);
|
|
|
|
/* Write init value to DDATA1. */
|
|
CRYPTO_DDataWrite(&crypto->DDATA1, shaBlock);
|
|
|
|
/* Copy data ot DDATA0 and select DDATA0 and DDATA1 for SHA operation. */
|
|
CRYPTO_EXECUTE_2(crypto,
|
|
CRYPTO_CMD_INSTR_DDATA1TODDATA0,
|
|
CRYPTO_CMD_INSTR_SELDDATA0DDATA1);
|
|
len = msgLen;
|
|
|
|
while (len >= CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES) {
|
|
/* Write block to QDATA1BIG. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t *) msg);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
|
|
len -= CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES;
|
|
msg += CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES;
|
|
}
|
|
|
|
blockLen = 0;
|
|
|
|
/* Build the last (or second to last) block */
|
|
for (; len; len--) {
|
|
p8ShaBlock[blockLen++] = *msg++;
|
|
}
|
|
|
|
/* append the '1' bit */
|
|
p8ShaBlock[blockLen++] = 0x80;
|
|
|
|
/* if the length is currently above 56 bytes we append zeros
|
|
* then compress. Then we can fall back to padding zeros and length
|
|
* encoding like normal.
|
|
*/
|
|
if (blockLen > 56) {
|
|
while (blockLen < 64)
|
|
p8ShaBlock[blockLen++] = 0;
|
|
|
|
/* Write block to QDATA1BIG. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
blockLen = 0;
|
|
}
|
|
|
|
/* Pad upto 56 bytes of zeroes */
|
|
while (blockLen < 56)
|
|
p8ShaBlock[blockLen++] = 0;
|
|
|
|
/* And finally, encode the message length. */
|
|
{
|
|
uint64_t msgLenInBits = msgLen << 3;
|
|
temp = msgLenInBits >> 32;
|
|
*(uint32_t *)&p8ShaBlock[56] = SWAP32(temp);
|
|
temp = msgLenInBits & 0xFFFFFFFF;
|
|
*(uint32_t *)&p8ShaBlock[60] = SWAP32(temp);
|
|
}
|
|
|
|
/* Write the final block to QDATA1BIG. */
|
|
CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock);
|
|
|
|
/* Execute SHA */
|
|
CRYPTO_EXECUTE_3(crypto,
|
|
CRYPTO_CMD_INSTR_SHA,
|
|
CRYPTO_CMD_INSTR_MADD32,
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA1);
|
|
|
|
/* Read resulting message digest from DDATA0BIG. */
|
|
CRYPTO_DDataRead(&crypto->DDATA0BIG, (uint32_t *)msgDigest);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Set 32bit word array to zero.
|
|
*
|
|
* @param[in] words32bits Pointer to 32bit word array
|
|
* @param[in] num32bitWords Number of 32bit words in array
|
|
******************************************************************************/
|
|
__STATIC_INLINE void cryptoBigintZeroize(uint32_t * words32bits,
|
|
int num32bitWords)
|
|
{
|
|
while (num32bitWords--)
|
|
*words32bits++ = 0;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Increment value of 32bit word array by one.
|
|
*
|
|
* @param[in] words32bits Pointer to 32bit word array
|
|
* @param[in] num32bitWords Number of 32bit words in array
|
|
******************************************************************************/
|
|
__STATIC_INLINE void cryptoBigintIncrement(uint32_t * words32bits,
|
|
int num32bitWords)
|
|
{
|
|
int i;
|
|
for (i = 0; i < num32bitWords; i++) {
|
|
if (++words32bits[i] != 0) {
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Multiply two big integers.
|
|
*
|
|
* @details
|
|
* This function uses the CRYPTO unit to multiply two big integer operands.
|
|
* If USE_VARIABLE_SIZED_DATA_LOADS is defined, the sizes of the operands
|
|
* may be any multiple of 32 bits. If USE_VARIABLE_SIZED_DATA_LOADS is _not_
|
|
* defined, the sizes of the operands must be a multiple of 128 bits.
|
|
*
|
|
* @param[in] A operand A
|
|
* @param[in] aSize size of operand A in bits
|
|
* @param[in] B operand B
|
|
* @param[in] bSize size of operand B in bits
|
|
* @param[out] R result of multiplication
|
|
* @param[in] rSize size of result buffer R in bits
|
|
******************************************************************************/
|
|
void CRYPTO_Mul(CRYPTO_TypeDef * crypto,
|
|
uint32_t * A, int aSize,
|
|
uint32_t * B, int bSize,
|
|
uint32_t * R, int rSize)
|
|
{
|
|
int i, j;
|
|
|
|
/**************** Initializations ******************/
|
|
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
int numWordsLastOperandA = (aSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5;
|
|
int numPartialOperandsA = numWordsLastOperandA
|
|
? (aSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1
|
|
: aSize >> PARTIAL_OPERAND_WIDTH_LOG2;
|
|
int numWordsLastOperandB = (bSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5;
|
|
int numPartialOperandsB = numWordsLastOperandB
|
|
? (bSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1
|
|
: bSize >> PARTIAL_OPERAND_WIDTH_LOG2;
|
|
int numWordsLastOperandR = (rSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5;
|
|
int numPartialOperandsR = numWordsLastOperandR
|
|
? (rSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1
|
|
: rSize >> PARTIAL_OPERAND_WIDTH_LOG2;
|
|
EFM_ASSERT(numPartialOperandsA + numPartialOperandsB <= numPartialOperandsR);
|
|
#else
|
|
int numPartialOperandsA = aSize >> PARTIAL_OPERAND_WIDTH_LOG2;
|
|
int numPartialOperandsB = bSize >> PARTIAL_OPERAND_WIDTH_LOG2;
|
|
EFM_ASSERT((aSize & PARTIAL_OPERAND_WIDTH_MASK) == 0);
|
|
EFM_ASSERT((bSize & PARTIAL_OPERAND_WIDTH_MASK) == 0);
|
|
#endif
|
|
EFM_ASSERT(aSize + bSize <= rSize);
|
|
|
|
/* Set R to zero. */
|
|
cryptoBigintZeroize(R, rSize >> 5);
|
|
|
|
/* Set multiplication width. */
|
|
crypto->WAC = CRYPTO_WAC_MULWIDTH_MUL128 | CRYPTO_WAC_RESULTWIDTH_256BIT;
|
|
|
|
/* Setup DMA request signalling in order for MCU to run in parallel with
|
|
CRYPTO instruction sequence execution, and prepare data loading which
|
|
can take place immediately when CRYPTO is ready inside the instruction
|
|
sequence. */
|
|
crypto->CTRL =
|
|
CRYPTO_CTRL_DMA0RSEL_DATA0 | CRYPTO_CTRL_DMA0MODE_FULL
|
|
| CRYPTO_CTRL_DMA1RSEL_DATA1 | CRYPTO_CTRL_DMA1MODE_FULL;
|
|
|
|
CRYPTO_EXECUTE_4(crypto,
|
|
CRYPTO_CMD_INSTR_CCLR, /* Carry = 0 */
|
|
CRYPTO_CMD_INSTR_CLR, /* DDATA0 = 0 */
|
|
/* clear result accumulation register */
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA2,
|
|
CRYPTO_CMD_INSTR_SELDDATA1DDATA3);
|
|
/*
|
|
register map:
|
|
DDATA0: working register
|
|
DDATA1: B(j)
|
|
DDATA2: R(i+j+1) and R(i+j), combined with DMA entry for B(j)
|
|
DDATA3: A(i)
|
|
*/
|
|
|
|
CRYPTO_SEQ_LOAD_10(crypto,
|
|
/* Temporarily load partial operand B(j) to DATA0. */
|
|
/* R(i+j+1) is still in DATA1 */
|
|
CRYPTO_CMD_INSTR_DMA0TODATA,
|
|
/* Move B(j) to DDATA1 */
|
|
CRYPTO_CMD_INSTR_DDATA2TODDATA1,
|
|
|
|
/* Restore previous partial result (now R(i+j)) */
|
|
CRYPTO_CMD_INSTR_DATA1TODATA0,
|
|
|
|
/* Load next partial result R(i+j+1) */
|
|
CRYPTO_CMD_INSTR_DMA1TODATA,
|
|
|
|
/* Execute partial multiplication A(i)inDDATA1 * B(j)inDDATA3*/
|
|
CRYPTO_CMD_INSTR_MULO,
|
|
|
|
/* Add the result to the previous partial result */
|
|
/* AND take the previous carry value into account */
|
|
/* at the right place (bit 128, ADDIC instruction */
|
|
CRYPTO_CMD_INSTR_SELDDATA0DDATA2,
|
|
CRYPTO_CMD_INSTR_ADDIC,
|
|
|
|
/* Save the new partial result (lower half) */
|
|
CRYPTO_CMD_INSTR_DDATA0TODDATA2,
|
|
CRYPTO_CMD_INSTR_DATATODMA0,
|
|
/* Reset the operand selector for next*/
|
|
CRYPTO_CMD_INSTR_SELDDATA2DDATA3
|
|
);
|
|
|
|
/**************** End Initializations ******************/
|
|
|
|
for (i = 0; i < numPartialOperandsA; i++) {
|
|
/* Load partial operand #1 A>>(i*PARTIAL_OPERAND_WIDTH) to DDATA1. */
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
if ( (numWordsLastOperandA != 0) && (i == numPartialOperandsA - 1) ) {
|
|
CRYPTO_DataWriteVariableSize(&crypto->DATA2,
|
|
&A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
|
|
numWordsLastOperandA);
|
|
} else {
|
|
CRYPTO_DataWrite(&crypto->DATA2, &A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
}
|
|
#else
|
|
CRYPTO_DataWrite(&crypto->DATA2, &A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
#endif
|
|
|
|
/* Load partial result in R>>(i*PARTIAL_OPERAND_WIDTH) to DATA1. */
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
if ( (numWordsLastOperandR != 0) && (i == numPartialOperandsR - 1) ) {
|
|
CRYPTO_DataWriteVariableSize(&crypto->DATA1,
|
|
&R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
|
|
numWordsLastOperandR);
|
|
} else {
|
|
CRYPTO_DataWrite(&crypto->DATA1, &R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
}
|
|
#else
|
|
CRYPTO_DataWrite(&crypto->DATA1, &R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
#endif
|
|
|
|
/* Clear carry */
|
|
crypto->CMD = CRYPTO_CMD_INSTR_CCLR;
|
|
|
|
/* Setup number of sequence iterations and block size. */
|
|
crypto->SEQCTRL = CRYPTO_SEQCTRL_BLOCKSIZE_16BYTES
|
|
| (PARTIAL_OPERAND_WIDTH_IN_BYTES * numPartialOperandsB);
|
|
|
|
/* Execute the MULtiply instruction sequence. */
|
|
CRYPTO_InstructionSequenceExecute(crypto);
|
|
|
|
for (j = 0; j < numPartialOperandsB; j++) {
|
|
/* Load partial operand 2 B>>(j*`PARTIAL_OPERAND_WIDTH) to DDATA2
|
|
(via DATA0). */
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
if ( (numWordsLastOperandB != 0) && (j == numPartialOperandsB - 1) ) {
|
|
CRYPTO_DataWriteVariableSize(&crypto->DATA0,
|
|
&B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
|
|
numWordsLastOperandB);
|
|
} else {
|
|
CRYPTO_DataWrite(&crypto->DATA0,
|
|
&B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
}
|
|
#else
|
|
CRYPTO_DataWrite(&crypto->DATA0,
|
|
&B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
#endif
|
|
|
|
/* Load most significant partial result
|
|
R>>((i+j+1)*`PARTIAL_OPERAND_WIDTH) into DATA1. */
|
|
#ifdef USE_VARIABLE_SIZED_DATA_LOADS
|
|
if ( (numWordsLastOperandR != 0) && ( (i + j + 1) == numPartialOperandsR - 1) ) {
|
|
CRYPTO_DataWriteVariableSize(&crypto->DATA1,
|
|
&R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
|
|
numWordsLastOperandR);
|
|
} else {
|
|
CRYPTO_DataWrite(&crypto->DATA1,
|
|
&R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
}
|
|
#else
|
|
CRYPTO_DataWrite(&crypto->DATA1,
|
|
&R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
#endif
|
|
/* Store least significant partial result */
|
|
CRYPTO_DataRead(&crypto->DATA0,
|
|
&R[(i + j) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
} /* for (j=0; j<numPartialOperandsB; j++) */
|
|
|
|
/* Handle carry at the end of the inner loop. */
|
|
if (CRYPTO_CarryIsSet(crypto)) {
|
|
cryptoBigintIncrement(&R[(i + numPartialOperandsB + 1)
|
|
* PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
|
|
(numPartialOperandsA - i - 1)
|
|
* PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS);
|
|
}
|
|
|
|
CRYPTO_DataRead(&crypto->DATA1,
|
|
&R[(i + numPartialOperandsB)
|
|
* PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
|
|
} /* for (i=0; i<numPartialOperandsA; i++) */
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES 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[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_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 initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CBC128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
CRYPTO_AES_CBCx(crypto, out, in, len, key, iv, encrypt, cryptoKey128Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit
|
|
* key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CBC128() for CBC figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey256().
|
|
*
|
|
* @param[in] iv
|
|
* 128 bit initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CBC256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
CRYPTO_AES_CBCx(crypto, out, in, len, key, iv, encrypt, cryptoKey256Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key.
|
|
*
|
|
* @details
|
|
* Encryption:
|
|
* @verbatim
|
|
* InitVector +----------------+
|
|
* | | |
|
|
* V | V
|
|
* +--------------+ | +--------------+
|
|
* Key ->| Block cipher | | Key ->| Block cipher |
|
|
* | encryption | | | encryption |
|
|
* +--------------+ | +--------------+
|
|
* | | |
|
|
* V | V
|
|
* Plaintext ->XOR | Plaintext ->XOR
|
|
* |---------+ |
|
|
* V V
|
|
* Ciphertext Ciphertext
|
|
* @endverbatim
|
|
* Decryption:
|
|
* @verbatim
|
|
* InitVector +----------------+
|
|
* | | |
|
|
* V | V
|
|
* +--------------+ | +--------------+
|
|
* Key ->| Block cipher | | Key ->| Block cipher |
|
|
* | encryption | | | encryption |
|
|
* +--------------+ | +--------------+
|
|
* | | |
|
|
* V | V
|
|
* XOR<- Ciphertext XOR<- Ciphertext
|
|
* | |
|
|
* V V
|
|
* Plaintext Plaintext
|
|
* @endverbatim
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CFB128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
CRYPTO_AES_CFBx(crypto, out, in, len, key, iv, encrypt, cryptoKey128Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CFB128() for CFB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CFB256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
CRYPTO_AES_CFBx(crypto, out, in, len, key, iv, encrypt, cryptoKey256Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Counter (CTR) cipher mode encryption/decryption, 128 bit key.
|
|
*
|
|
* @details
|
|
* Encryption:
|
|
* @verbatim
|
|
* Counter Counter
|
|
* | |
|
|
* V V
|
|
* +--------------+ +--------------+
|
|
* Key ->| Block cipher | Key ->| Block cipher |
|
|
* | encryption | | encryption |
|
|
* +--------------+ +--------------+
|
|
* | |
|
|
* Plaintext ->XOR Plaintext ->XOR
|
|
* | |
|
|
* V V
|
|
* Ciphertext Ciphertext
|
|
* @endverbatim
|
|
* Decryption:
|
|
* @verbatim
|
|
* Counter Counter
|
|
* | |
|
|
* V V
|
|
* +--------------+ +--------------+
|
|
* Key ->| Block cipher | Key ->| Block cipher |
|
|
* | encryption | | encryption |
|
|
* +--------------+ +--------------+
|
|
* | |
|
|
* Ciphertext ->XOR Ciphertext ->XOR
|
|
* | |
|
|
* V V
|
|
* Plaintext Plaintext
|
|
* @endverbatim
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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. Not supported by CRYPTO.
|
|
* This parameter is included in order for backwards compatibility with
|
|
* the EFM32 em_aes.h API.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CTR128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
uint8_t * ctr,
|
|
CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
CRYPTO_AES_CTRx(crypto, out, in, len, key, ctr, ctrFunc, cryptoKey128Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Counter (CTR) cipher mode encryption/decryption, 256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CTR128() for CTR figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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. Not supported by CRYPTO.
|
|
* This parameter is included in order for backwards compatibility with
|
|
* the EFM32 em_aes.h API.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_CTR256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
uint8_t * ctr,
|
|
CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
CRYPTO_AES_CTRx(crypto, out, in, len, key, ctr, ctrFunc, cryptoKey256Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @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 CRYPTO_AES_CTRUpdate32Bit(uint8_t * ctr)
|
|
{
|
|
uint32_t * _ctr = (uint32_t *) ctr;
|
|
|
|
_ctr[3] = __REV(__REV(_ctr[3]) + 1);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Generate 128 bit AES decryption key from 128 bit encryption key. The
|
|
* decryption key is used for some cipher modes when decrypting.
|
|
*
|
|
* @details
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in)
|
|
{
|
|
uint32_t * _out = (uint32_t *) out;
|
|
const uint32_t * _in = (const uint32_t *) in;
|
|
|
|
/* Setup CRYPTO in AES-128 mode. */
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
|
|
/* Load key */
|
|
CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[0]);
|
|
|
|
/* Do dummy encryption to generate decrypt key */
|
|
crypto->CMD = CRYPTO_CMD_INSTR_AESENC;
|
|
|
|
/* Save decryption key */
|
|
CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[0]);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Generate 256 bit AES decryption key from 256 bit encryption key. The
|
|
* decryption key is used for some cipher modes when decrypting.
|
|
*
|
|
* @details
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in)
|
|
{
|
|
uint32_t * _out = (uint32_t *) out;
|
|
const uint32_t * _in = (const uint32_t *) in;
|
|
|
|
/* Setup CRYPTO in AES-256 mode. */
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
|
|
/* Load key */
|
|
CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[0]);
|
|
CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[4]);
|
|
|
|
/* Do dummy encryption to generate decrypt key */
|
|
crypto->CMD = CRYPTO_CMD_INSTR_AESENC;
|
|
|
|
/* Save decryption key */
|
|
CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[0]);
|
|
CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[4]);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Electronic Codebook (ECB) cipher mode encryption/decryption,
|
|
* 128 bit key.
|
|
*
|
|
* @details
|
|
* Encryption:
|
|
* @verbatim
|
|
* Plaintext Plaintext
|
|
* | |
|
|
* V V
|
|
* +--------------+ +--------------+
|
|
* Key ->| Block cipher | Key ->| Block cipher |
|
|
* | encryption | | encryption |
|
|
* +--------------+ +--------------+
|
|
* | |
|
|
* V V
|
|
* Ciphertext Ciphertext
|
|
* @endverbatim
|
|
* Decryption:
|
|
* @verbatim
|
|
* Ciphertext Ciphertext
|
|
* | |
|
|
* V V
|
|
* +--------------+ +--------------+
|
|
* Key ->| Block cipher | Key ->| Block cipher |
|
|
* | decryption | | decryption |
|
|
* +--------------+ +--------------+
|
|
* | |
|
|
* V V
|
|
* Plaintext Plaintext
|
|
* @endverbatim
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey128().
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_ECB128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
CRYPTO_AES_ECBx(crypto, out, in, len, key, encrypt, cryptoKey128Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Electronic Codebook (ECB) cipher mode encryption/decryption,
|
|
* 256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_ECB128() for ECB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey256().
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_ECB256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
bool encrypt)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
CRYPTO_AES_ECBx(crypto, out, in, len, key, encrypt, cryptoKey256Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Output feedback (OFB) cipher mode encryption/decryption, 128 bit key.
|
|
*
|
|
* @details
|
|
* Encryption:
|
|
* @verbatim
|
|
* InitVector +----------------+
|
|
* | | |
|
|
* V | V
|
|
* +--------------+ | +--------------+
|
|
* Key ->| Block cipher | | Key ->| Block cipher |
|
|
* | encryption | | | encryption |
|
|
* +--------------+ | +--------------+
|
|
* | | |
|
|
* |---------+ |
|
|
* V V
|
|
* Plaintext ->XOR Plaintext ->XOR
|
|
* | |
|
|
* V V
|
|
* Ciphertext Ciphertext
|
|
* @endverbatim
|
|
* Decryption:
|
|
* @verbatim
|
|
* InitVector +----------------+
|
|
* | | |
|
|
* V | V
|
|
* +--------------+ | +--------------+
|
|
* Key ->| Block cipher | | Key ->| Block cipher |
|
|
* | encryption | | | encryption |
|
|
* +--------------+ | +--------------+
|
|
* | | |
|
|
* |---------+ |
|
|
* V V
|
|
* Ciphertext ->XOR Ciphertext ->XOR
|
|
* | |
|
|
* V V
|
|
* Plaintext Plaintext
|
|
* @endverbatim
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_OFB128(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES128;
|
|
CRYPTO_AES_OFBx(crypto, out, in, len, key, iv, cryptoKey128Bits);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* AES Output feedback (OFB) cipher mode encryption/decryption, 256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_OFB128() for OFB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
******************************************************************************/
|
|
void CRYPTO_AES_OFB256(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv)
|
|
{
|
|
crypto->CTRL = CRYPTO_CTRL_AES_AES256;
|
|
CRYPTO_AES_OFBx(crypto, out, in, len, key, iv, cryptoKey256Bits);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
************************** LOCAL FUNCTIONS *******************************
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Cipher-block chaining (CBC) cipher mode encryption/decryption, 128/256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CBC128() for CBC figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey256().
|
|
*
|
|
* @param[in] iv
|
|
* 128 bit initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Set to cryptoKey128Bits or cryptoKey256Bits.
|
|
******************************************************************************/
|
|
static void CRYPTO_AES_CBCx(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE));
|
|
|
|
/* Initialize control registers. */
|
|
crypto->WAC = 0;
|
|
|
|
CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth);
|
|
|
|
if (encrypt) {
|
|
CRYPTO_DataWrite(&crypto->DATA0, (uint32_t *)iv);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT;
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA1, (uint32_t *) in,
|
|
&crypto->DATA0, (uint32_t *) out);
|
|
} else {
|
|
CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *) iv);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_AESDEC << _CRYPTO_SEQ0_INSTR1_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT;
|
|
|
|
crypto->SEQ1 = 0;
|
|
|
|
/* The following call is equivalent to the last call in the
|
|
'if( encrypt )' branch. However moving this
|
|
call outside the conditional scope results in slightly poorer
|
|
performance for some compiler optimizations. */
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA1, (uint32_t *) in,
|
|
&crypto->DATA0, (uint32_t *) out);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Cipher feedback (CFB) cipher mode encryption/decryption, 128/256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CFB128() for CFB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Set to cryptoKey128Bits or cryptoKey256Bits.
|
|
******************************************************************************/
|
|
static void CRYPTO_AES_CFBx(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE));
|
|
|
|
/* Initialize control registers. */
|
|
crypto->WAC = 0;
|
|
|
|
/* Load Key */
|
|
CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth);
|
|
|
|
/* Load instructions to CRYPTO sequencer. */
|
|
if (encrypt) {
|
|
/* Load IV */
|
|
CRYPTO_DataWrite(&crypto->DATA0, (uint32_t *)iv);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR1_SHIFT;
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA1, (uint32_t *)in,
|
|
&crypto->DATA0, (uint32_t *)out
|
|
);
|
|
} else {
|
|
/* Load IV */
|
|
CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *)iv);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA2TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT;
|
|
crypto->SEQ1 = 0;
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA1, (uint32_t *)in,
|
|
&crypto->DATA0, (uint32_t *)out
|
|
);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Counter (CTR) cipher mode encryption/decryption, 128/256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_CTR128() for CTR figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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. Not supported by CRYPTO.
|
|
* This parameter is included in order for backwards compatibility with
|
|
* the EFM32 em_aes.h API.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Set to cryptoKey128Bits or cryptoKey256Bits.
|
|
******************************************************************************/
|
|
static void CRYPTO_AES_CTRx(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
uint8_t * ctr,
|
|
CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
(void) ctrFunc;
|
|
|
|
EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE));
|
|
|
|
/* Initialize control registers. */
|
|
crypto->CTRL |= CRYPTO_CTRL_INCWIDTH_INCWIDTH4;
|
|
crypto->WAC = 0;
|
|
|
|
CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth);
|
|
|
|
CRYPTO_DataWrite(&crypto->DATA1, (uint32_t *) ctr);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA0TODATA3 << _CRYPTO_SEQ0_INSTR2_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA1INC << _CRYPTO_SEQ0_INSTR3_SHIFT;
|
|
|
|
crypto->SEQ1 = CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ1_INSTR4_SHIFT;
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA2, (uint32_t *) in,
|
|
&crypto->DATA0, (uint32_t *) out);
|
|
|
|
CRYPTO_DataRead(&crypto->DATA1, (uint32_t *) ctr);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Electronic Codebook (ECB) cipher mode encryption/decryption, 128/256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_ECB128() for ECB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 CRYPTO_AES_DecryptKey256().
|
|
*
|
|
* @param[in] encrypt
|
|
* Set to true to encrypt, false to decrypt.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Set to cryptoKey128Bits or cryptoKey256Bits.
|
|
******************************************************************************/
|
|
static void CRYPTO_AES_ECBx(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
bool encrypt,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE));
|
|
|
|
crypto->WAC = 0;
|
|
|
|
CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth);
|
|
|
|
if (encrypt) {
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR1_SHIFT;
|
|
} else {
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_AESDEC << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR1_SHIFT;
|
|
}
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA0, (uint32_t *) in,
|
|
&crypto->DATA1, (uint32_t *) out);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Output feedback (OFB) cipher mode encryption/decryption, 128/256 bit key.
|
|
*
|
|
* @details
|
|
* Please see CRYPTO_AES_OFB128() for OFB figure.
|
|
*
|
|
* Please refer to general comments on layout and byte ordering of parameters.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @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 initialization vector to use.
|
|
*
|
|
* @param[in] keyWidth
|
|
* Set to cryptoKey128Bits or cryptoKey256Bits.
|
|
******************************************************************************/
|
|
static void CRYPTO_AES_OFBx(CRYPTO_TypeDef * crypto,
|
|
uint8_t * out,
|
|
const uint8_t * in,
|
|
unsigned int len,
|
|
const uint8_t * key,
|
|
const uint8_t * iv,
|
|
CRYPTO_KeyWidth_TypeDef keyWidth)
|
|
{
|
|
EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE));
|
|
|
|
crypto->WAC = 0;
|
|
|
|
CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth);
|
|
|
|
CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *)iv);
|
|
|
|
crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR0_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA2TODATA0 << _CRYPTO_SEQ0_INSTR1_SHIFT
|
|
| CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR2_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA0TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT;
|
|
crypto->SEQ1 = CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ1_INSTR4_SHIFT
|
|
| CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ1_INSTR5_SHIFT;
|
|
|
|
CRYPTO_AES_ProcessLoop(crypto, len,
|
|
&crypto->DATA0, (uint32_t *) in,
|
|
&crypto->DATA1, (uint32_t *) out);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Function performs generic AES loop.
|
|
*
|
|
* @details
|
|
* Function loads given register with provided input data. Triggers CRYPTO to
|
|
* perform sequence of instructions and read specified output register to
|
|
* output buffer.
|
|
*
|
|
* @param[in] crypto
|
|
* Pointer to CRYPTO peripheral register block.
|
|
*
|
|
* @param[in] len
|
|
* Number of bytes to encrypt/decrypt. Must be a multiple of 16.
|
|
*
|
|
* @param[in] inReg
|
|
* Input register - one of DATA0,DATA1,DATA2,DATA3
|
|
*
|
|
* @param[in] in
|
|
* Buffer holding data to encrypt/decrypt. Must be at least @p len long.
|
|
*
|
|
* @param[in] outReg
|
|
* Output register - one of DATA0,DATA1,DATA2,DATA3
|
|
*
|
|
* @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.
|
|
******************************************************************************/
|
|
static inline void CRYPTO_AES_ProcessLoop(CRYPTO_TypeDef * crypto,
|
|
uint32_t len,
|
|
CRYPTO_DataReg_TypeDef inReg,
|
|
uint32_t * in,
|
|
CRYPTO_DataReg_TypeDef outReg,
|
|
uint32_t * out)
|
|
{
|
|
len /= CRYPTO_AES_BLOCKSIZE;
|
|
crypto->SEQCTRL = 16 << _CRYPTO_SEQCTRL_LENGTHA_SHIFT;
|
|
|
|
while (len--) {
|
|
/* Load data and trigger encryption */
|
|
CRYPTO_DataWrite(inReg, (uint32_t *)in);
|
|
|
|
crypto->CMD = CRYPTO_CMD_SEQSTART;
|
|
|
|
/* Save encrypted/decrypted data */
|
|
CRYPTO_DataRead(outReg, (uint32_t *)out);
|
|
|
|
out += 4;
|
|
in += 4;
|
|
}
|
|
}
|
|
|
|
/** @} (end addtogroup CRYPTO) */
|
|
/** @} (end addtogroup emlib) */
|
|
|
|
#endif /* defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */
|