zephyr/subsys/bluetooth/controller/hal/nrf5/ecb.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;
}