217 lines
4.7 KiB
C
217 lines
4.7 KiB
C
/*
|
|
* Copyright (c) 2016 Nordic Semiconductor ASA
|
|
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <soc.h>
|
|
#if !defined(CONFIG_ARCH_POSIX)
|
|
#include <arch/arm/cortex_m/cmsis.h>
|
|
#endif
|
|
|
|
#include "util/mem.h"
|
|
#include "hal/ecb.h"
|
|
|
|
#include "common/log.h"
|
|
#include "hal/debug.h"
|
|
|
|
struct ecb_param {
|
|
u8_t key[16];
|
|
u8_t clear_text[16];
|
|
u8_t cipher_text[16];
|
|
} __packed;
|
|
|
|
static void do_ecb(struct ecb_param *ecb)
|
|
{
|
|
do {
|
|
NRF_ECB->TASKS_STOPECB = 1;
|
|
NRF_ECB->ECBDATAPTR = (u32_t)ecb;
|
|
NRF_ECB->EVENTS_ENDECB = 0;
|
|
NRF_ECB->EVENTS_ERRORECB = 0;
|
|
NRF_ECB->TASKS_STARTECB = 1;
|
|
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
|
|
NRF_ECB_regw_sideeffects_TASKS_STOPECB();
|
|
NRF_ECB_regw_sideeffects_TASKS_STARTECB();
|
|
#endif
|
|
while ((NRF_ECB->EVENTS_ENDECB == 0) &&
|
|
(NRF_ECB->EVENTS_ERRORECB == 0) &&
|
|
(NRF_ECB->ECBDATAPTR != 0)) {
|
|
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
|
|
__WFE();
|
|
#else
|
|
/*__WFE();*/
|
|
#endif
|
|
}
|
|
NRF_ECB->TASKS_STOPECB = 1;
|
|
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
|
|
NRF_ECB_regw_sideeffects_TASKS_STOPECB();
|
|
#endif
|
|
} while ((NRF_ECB->EVENTS_ERRORECB != 0) || (NRF_ECB->ECBDATAPTR == 0));
|
|
|
|
NRF_ECB->ECBDATAPTR = 0;
|
|
}
|
|
|
|
void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be,
|
|
u8_t * const cipher_text_be)
|
|
{
|
|
struct ecb_param ecb;
|
|
|
|
memcpy(&ecb.key[0], key_be, sizeof(ecb.key));
|
|
memcpy(&ecb.clear_text[0], clear_text_be, sizeof(ecb.clear_text));
|
|
|
|
do_ecb(&ecb);
|
|
|
|
memcpy(cipher_text_be, &ecb.cipher_text[0], sizeof(ecb.cipher_text));
|
|
}
|
|
|
|
void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le,
|
|
u8_t * const cipher_text_le, u8_t * const cipher_text_be)
|
|
{
|
|
struct ecb_param ecb;
|
|
|
|
mem_rcopy(&ecb.key[0], key_le, sizeof(ecb.key));
|
|
mem_rcopy(&ecb.clear_text[0], clear_text_le, sizeof(ecb.clear_text));
|
|
|
|
do_ecb(&ecb);
|
|
|
|
if (cipher_text_le) {
|
|
mem_rcopy(cipher_text_le, &ecb.cipher_text[0],
|
|
sizeof(ecb.cipher_text));
|
|
}
|
|
|
|
if (cipher_text_be) {
|
|
memcpy(cipher_text_be, &ecb.cipher_text[0],
|
|
sizeof(ecb.cipher_text));
|
|
}
|
|
}
|
|
|
|
u32_t ecb_encrypt_nonblocking(struct ecb *ecb)
|
|
{
|
|
/* prepare to be used in a BE AES h/w */
|
|
if (ecb->in_key_le) {
|
|
mem_rcopy(&ecb->in_key_be[0], ecb->in_key_le,
|
|
sizeof(ecb->in_key_be));
|
|
}
|
|
if (ecb->in_clear_text_le) {
|
|
mem_rcopy(&ecb->in_clear_text_be[0],
|
|
ecb->in_clear_text_le,
|
|
sizeof(ecb->in_clear_text_be));
|
|
}
|
|
|
|
/* setup the encryption h/w */
|
|
NRF_ECB->ECBDATAPTR = (u32_t)ecb;
|
|
NRF_ECB->EVENTS_ENDECB = 0;
|
|
NRF_ECB->EVENTS_ERRORECB = 0;
|
|
NRF_ECB->INTENSET = ECB_INTENSET_ERRORECB_Msk | ECB_INTENSET_ENDECB_Msk;
|
|
|
|
/* enable interrupt */
|
|
NVIC_ClearPendingIRQ(ECB_IRQn);
|
|
irq_enable(ECB_IRQn);
|
|
|
|
/* start the encryption h/w */
|
|
NRF_ECB->TASKS_STARTECB = 1;
|
|
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
|
|
NRF_ECB_regw_sideeffects_INTENSET();
|
|
NRF_ECB_regw_sideeffects_TASKS_STARTECB();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ecb_cleanup(void)
|
|
{
|
|
/* stop h/w */
|
|
NRF_ECB->TASKS_STOPECB = 1;
|
|
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
|
|
NRF_ECB_regw_sideeffects_TASKS_STOPECB();
|
|
#endif
|
|
|
|
/* cleanup interrupt */
|
|
irq_disable(ECB_IRQn);
|
|
}
|
|
|
|
void isr_ecb(void *param)
|
|
{
|
|
ARG_UNUSED(param);
|
|
|
|
if (NRF_ECB->EVENTS_ERRORECB) {
|
|
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;
|
|
|
|
ecb_cleanup();
|
|
|
|
ecb->fp_ecb(1, NULL, ecb->context);
|
|
}
|
|
|
|
else if (NRF_ECB->EVENTS_ENDECB) {
|
|
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;
|
|
|
|
ecb_cleanup();
|
|
|
|
ecb->fp_ecb(0, &ecb->out_cipher_text_be[0],
|
|
ecb->context);
|
|
}
|
|
|
|
else {
|
|
LL_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
struct ecb_ut_context {
|
|
u32_t volatile done;
|
|
u32_t status;
|
|
u8_t cipher_text[16];
|
|
};
|
|
|
|
static void ecb_cb(u32_t status, u8_t *cipher_be, void *context)
|
|
{
|
|
struct ecb_ut_context *ecb_ut_context =
|
|
(struct ecb_ut_context *)context;
|
|
|
|
ecb_ut_context->done = 1;
|
|
ecb_ut_context->status = status;
|
|
if (!status) {
|
|
mem_rcopy(ecb_ut_context->cipher_text, cipher_be,
|
|
sizeof(ecb_ut_context->cipher_text));
|
|
}
|
|
}
|
|
|
|
u32_t ecb_ut(void)
|
|
{
|
|
u8_t key[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
|
0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
|
u8_t clear_text[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44,
|
|
0x55 };
|
|
u8_t cipher_text[16];
|
|
u32_t status = 0;
|
|
struct ecb ecb;
|
|
struct ecb_ut_context context;
|
|
|
|
ecb_encrypt(key, clear_text, cipher_text, NULL);
|
|
|
|
context.done = 0;
|
|
ecb.in_key_le = key;
|
|
ecb.in_clear_text_le = clear_text;
|
|
ecb.fp_ecb = ecb_cb;
|
|
ecb.context = &context;
|
|
status = ecb_encrypt_nonblocking(&ecb);
|
|
do {
|
|
__WFE();
|
|
__SEV();
|
|
__WFE();
|
|
} while (!context.done);
|
|
|
|
if (context.status != 0) {
|
|
return context.status;
|
|
}
|
|
|
|
status = memcmp(cipher_text, context.cipher_text, sizeof(cipher_text));
|
|
if (status) {
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|