1 /*
2 * Copyright (c) 2016-2024 Nordic Semiconductor ASA
3 * Copyright (c) 2016 Vinayak Kariappa Chettimada
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdint.h>
9 #include <string.h>
10
11 #include <zephyr/sys/byteorder.h>
12
13 #include <hal/nrf_ecb.h>
14
15 #include "util/mem.h"
16
17 #include "hal/cpu.h"
18 #include "hal/ecb.h"
19
20 #include "hal/debug.h"
21
22 #if defined(NRF54L_SERIES)
23 #define NRF_ECB NRF_ECB00
24 #define ECB_IRQn ECB00_IRQn
25 #define ECB_INTENSET_ERRORECB_Msk ECB_INTENSET_ERROR_Msk
26 #define ECB_INTENSET_ENDECB_Msk ECB_INTENSET_END_Msk
27 #define TASKS_STARTECB TASKS_START
28 #define TASKS_STOPECB TASKS_STOP
29 #define EVENTS_ENDECB EVENTS_END
30 #define EVENTS_ERRORECB EVENTS_ERROR
31 #define NRF_ECB_TASK_STARTECB NRF_ECB_TASK_START
32 #define NRF_ECB_TASK_STOPECB NRF_ECB_TASK_STOP
33 #define ECBDATAPTR IN.PTR
34
35 struct ecb_job_ptr {
36 void *ptr;
37 struct {
38 uint32_t length:24;
39 uint32_t attribute:8;
40 } __packed;
41 } __packed;
42
43 /* Product Specification recommends a value of 11, but prior work had used 7 */
44 #define ECB_JOB_PTR_ATTRIBUTE 7U
45 #endif /* NRF54L_SERIES */
46
47 struct ecb_param {
48 uint8_t key[16];
49 uint8_t clear_text[16];
50 uint8_t cipher_text[16];
51
52 #if defined(NRF54L_SERIES)
53 struct ecb_job_ptr in[2];
54 struct ecb_job_ptr out[2];
55 #endif /* NRF54L_SERIES */
56 } __packed;
57
do_ecb(struct ecb_param * ep)58 static void do_ecb(struct ecb_param *ep)
59 {
60 do {
61 nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
62
63 #if defined(NRF54L_SERIES)
64 NRF_ECB->KEY.VALUE[3] = sys_get_be32(&ep->key[0]);
65 NRF_ECB->KEY.VALUE[2] = sys_get_be32(&ep->key[4]);
66 NRF_ECB->KEY.VALUE[1] = sys_get_be32(&ep->key[8]);
67 NRF_ECB->KEY.VALUE[0] = sys_get_be32(&ep->key[12]);
68
69 ep->in[0].ptr = ep->clear_text;
70 ep->in[0].length = sizeof(ep->clear_text);
71 ep->in[0].attribute = ECB_JOB_PTR_ATTRIBUTE;
72 ep->in[1].ptr = NULL;
73 ep->in[1].length = 0U;
74 ep->in[1].attribute = 0U;
75
76 ep->out[0].ptr = ep->cipher_text;
77 ep->out[0].length = sizeof(ep->cipher_text);
78 ep->out[0].attribute = ECB_JOB_PTR_ATTRIBUTE;
79 ep->out[1].ptr = NULL;
80 ep->out[1].length = 0U;
81 ep->out[1].attribute = 0U;
82
83 NRF_ECB->IN.PTR = (uint32_t)ep->in;
84 NRF_ECB->OUT.PTR = (uint32_t)ep->out;
85 #else /* !NRF54L_SERIES */
86 NRF_ECB->ECBDATAPTR = (uint32_t)ep;
87 #endif /* !NRF54L_SERIES */
88
89 NRF_ECB->EVENTS_ENDECB = 0;
90 NRF_ECB->EVENTS_ERRORECB = 0;
91 nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
92 while ((NRF_ECB->EVENTS_ENDECB == 0) &&
93 (NRF_ECB->EVENTS_ERRORECB == 0) &&
94 (NRF_ECB->ECBDATAPTR != 0)) {
95 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
96 k_busy_wait(10);
97 #else
98 /* FIXME: use cpu_sleep(), but that will need interrupt
99 * wake up source and hence necessary appropriate
100 * code.
101 */
102 #endif
103 }
104 nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
105 } while ((NRF_ECB->EVENTS_ERRORECB != 0) || (NRF_ECB->ECBDATAPTR == 0));
106
107 NRF_ECB->ECBDATAPTR = 0;
108 }
109
ecb_encrypt_be(uint8_t const * const key_be,uint8_t const * const clear_text_be,uint8_t * const cipher_text_be)110 void ecb_encrypt_be(uint8_t const *const key_be, uint8_t const *const clear_text_be,
111 uint8_t * const cipher_text_be)
112 {
113 struct ecb_param ecb;
114
115 memcpy(&ecb.key[0], key_be, sizeof(ecb.key));
116 memcpy(&ecb.clear_text[0], clear_text_be, sizeof(ecb.clear_text));
117
118 do_ecb(&ecb);
119
120 memcpy(cipher_text_be, &ecb.cipher_text[0], sizeof(ecb.cipher_text));
121 }
122
ecb_encrypt(uint8_t const * const key_le,uint8_t const * const clear_text_le,uint8_t * const cipher_text_le,uint8_t * const cipher_text_be)123 void ecb_encrypt(uint8_t const *const key_le, uint8_t const *const clear_text_le,
124 uint8_t * const cipher_text_le, uint8_t * const cipher_text_be)
125 {
126 struct ecb_param ecb;
127
128 mem_rcopy(&ecb.key[0], key_le, sizeof(ecb.key));
129 mem_rcopy(&ecb.clear_text[0], clear_text_le, sizeof(ecb.clear_text));
130
131 do_ecb(&ecb);
132
133 if (cipher_text_le) {
134 mem_rcopy(cipher_text_le, &ecb.cipher_text[0],
135 sizeof(ecb.cipher_text));
136 }
137
138 if (cipher_text_be) {
139 memcpy(cipher_text_be, &ecb.cipher_text[0],
140 sizeof(ecb.cipher_text));
141 }
142 }
143
ecb_encrypt_nonblocking(struct ecb * e)144 void ecb_encrypt_nonblocking(struct ecb *e)
145 {
146 /* prepare to be used in a BE AES h/w */
147 if (e->in_key_le) {
148 mem_rcopy(&e->in_key_be[0], e->in_key_le, sizeof(e->in_key_be));
149 }
150 if (e->in_clear_text_le) {
151 mem_rcopy(&e->in_clear_text_be[0], e->in_clear_text_le,
152 sizeof(e->in_clear_text_be));
153 }
154
155 /* setup the encryption h/w */
156 #if defined(NRF54L_SERIES)
157 NRF_ECB->KEY.VALUE[3] = sys_get_be32(&e->in_key_be[0]);
158 NRF_ECB->KEY.VALUE[2] = sys_get_be32(&e->in_key_be[4]);
159 NRF_ECB->KEY.VALUE[1] = sys_get_be32(&e->in_key_be[8]);
160 NRF_ECB->KEY.VALUE[0] = sys_get_be32(&e->in_key_be[12]);
161
162 struct ecb_job_ptr *in = (void *)((uint8_t *)e + sizeof(*e));
163 struct ecb_job_ptr *out = (void *)((uint8_t *)in + 16U);
164
165 in[0].ptr = e->in_clear_text_be;
166 in[0].length = sizeof(e->in_clear_text_be);
167 in[0].attribute = ECB_JOB_PTR_ATTRIBUTE;
168 in[1].ptr = NULL;
169 in[1].length = 0U;
170 in[1].attribute = 0U;
171
172 out[0].ptr = e->out_cipher_text_be;
173 out[0].length = sizeof(e->out_cipher_text_be);
174 out[0].attribute = ECB_JOB_PTR_ATTRIBUTE;
175 out[1].ptr = NULL;
176 out[1].length = 0U;
177 out[1].attribute = 0U;
178
179 NRF_ECB->IN.PTR = (uint32_t)in;
180 NRF_ECB->OUT.PTR = (uint32_t)out;
181 #else /* !NRF54L_SERIES */
182 NRF_ECB->ECBDATAPTR = (uint32_t)e;
183 #endif /* !NRF54L_SERIES */
184 NRF_ECB->EVENTS_ENDECB = 0;
185 NRF_ECB->EVENTS_ERRORECB = 0;
186 nrf_ecb_int_enable(NRF_ECB, ECB_INTENSET_ERRORECB_Msk
187 | ECB_INTENSET_ENDECB_Msk);
188
189 /* enable interrupt */
190 NVIC_ClearPendingIRQ(ECB_IRQn);
191 irq_enable(ECB_IRQn);
192
193 /* start the encryption h/w */
194 nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
195 }
196
isr_ecb(const void * arg)197 static void isr_ecb(const void *arg)
198 {
199 #if defined(NRF54L_SERIES)
200 struct ecb *e = (void *)((uint8_t *)NRF_ECB->ECBDATAPTR -
201 sizeof(struct ecb));
202 #else /* !NRF54L_SERIES */
203 struct ecb *e = (void *)NRF_ECB->ECBDATAPTR;
204 #endif /* !NRF54L_SERIES */
205
206 ARG_UNUSED(arg);
207
208 /* Stop ECB h/w */
209 nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
210
211 /* We are done or encountered error, disable interrupt */
212 irq_disable(ECB_IRQn);
213
214 if (NRF_ECB->EVENTS_ERRORECB) {
215 NRF_ECB->EVENTS_ERRORECB = 0U;
216
217 e->fp_ecb(1U, NULL, e->context);
218 }
219
220 else if (NRF_ECB->EVENTS_ENDECB) {
221 NRF_ECB->EVENTS_ENDECB = 0U;
222
223 e->fp_ecb(0U, &e->out_cipher_text_be[0],
224 e->context);
225 }
226
227 else {
228 LL_ASSERT(false);
229 }
230 }
231
232 struct ecb_ut_context {
233 uint32_t volatile done;
234 uint32_t status;
235 uint8_t cipher_text[16];
236 };
237
ecb_cb(uint32_t status,uint8_t * cipher_be,void * context)238 static void ecb_cb(uint32_t status, uint8_t *cipher_be, void *context)
239 {
240 struct ecb_ut_context *ecb_ut_context =
241 (struct ecb_ut_context *)context;
242
243 ecb_ut_context->done = 1U;
244 ecb_ut_context->status = status;
245 if (!status) {
246 mem_rcopy(ecb_ut_context->cipher_text, cipher_be,
247 sizeof(ecb_ut_context->cipher_text));
248 }
249 }
250
ecb_ut(void)251 int ecb_ut(void)
252 {
253 uint8_t key[] = {
254 0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
255 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c
256 };
257 uint8_t clear_text[] = {
258 0x13, 0x02, 0xf1, 0xe0, 0xdf, 0xce, 0xbd, 0xac,
259 0x79, 0x68, 0x57, 0x46, 0x35, 0x24, 0x13, 0x02
260 };
261 uint8_t cipher_text_expected[] = {
262 0x66, 0xc6, 0xc2, 0x27, 0x8e, 0x3b, 0x8e, 0x05,
263 0x3e, 0x7e, 0xa3, 0x26, 0x52, 0x1b, 0xad, 0x99
264 };
265 uint8_t cipher_text_actual[16];
266 int status;
267
268 (void)memset(cipher_text_actual, 0, sizeof(cipher_text_actual));
269 ecb_encrypt(key, clear_text, cipher_text_actual, NULL);
270
271 status = memcmp(cipher_text_actual, cipher_text_expected,
272 sizeof(cipher_text_actual));
273 if (status) {
274 return status;
275 }
276
277 #if defined(CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS)
278 irq_connect_dynamic(ECB_IRQn, CONFIG_BT_CTLR_ULL_LOW_PRIO, isr_ecb, NULL, 0);
279 #else /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */
280 IRQ_CONNECT(ECB_IRQn, CONFIG_BT_CTLR_ULL_LOW_PRIO, isr_ecb, NULL, 0);
281 #endif /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */
282
283 uint8_t ecb_mem[sizeof(struct ecb) + 32U];
284 struct ecb *e = (void *)ecb_mem;
285 struct ecb_ut_context context;
286
287 (void)memset(&context, 0, sizeof(context));
288 e->in_key_le = key;
289 e->in_clear_text_le = clear_text;
290 e->fp_ecb = ecb_cb;
291 e->context = &context;
292 ecb_encrypt_nonblocking(e);
293 do {
294 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
295 k_busy_wait(10);
296 #else
297 cpu_sleep();
298 #endif
299 } while (!context.done);
300
301 if (context.status != 0U) {
302 return context.status;
303 }
304
305 status = memcmp(cipher_text_expected, context.cipher_text,
306 sizeof(cipher_text_expected));
307 if (status) {
308 return status;
309 }
310
311 return status;
312 }
313