1 /***************************************************************************//**
2  * @file
3  * @brief Accelerated cryptographic primitives using the RADIOAES peripheral.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #include "em_device.h"
31 
32 #if defined(RADIOAES_PRESENT)
33 /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
34 
35 #include "sli_radioaes_management.h"
36 #include "sli_protocol_crypto.h"
37 #include "em_core.h"
38 
39 #define AES_BLOCK_BYTES       16U
40 #define AES_128_KEY_BYTES     16U
41 #define AES_256_KEY_BYTES     32U
42 
43 #define RADIOAES_CONFIG_BYTES  4U
44 
45 #ifndef RADIOAES_BLE_RPA_MAX_KEYS
46 #define RADIOAES_BLE_RPA_MAX_KEYS 32
47 #endif
48 
49 /// value for sli_radioaes_dma_sg_descr.tag to direct data to parameters
50 #define DMA_SG_TAG_ISCONFIG 0x00000010
51 /// value for sli_radioaes_dma_sg_descr.tag to direct data to processing
52 #define DMA_SG_TAG_ISDATA   0x00000000
53 /// value for sli_radioaes_dma_sg_descr.tag specifying data as last
54 #define DMA_SG_TAG_ISLAST   0x00000020
55 
56 /// macro to set the offset in the configuration for sli_radioaes_dma_sg_descr.tag
57 #define DMA_SG_TAG_SETCFGOFFSET(a) ((((a) & 0xFF) << 8))
58 
59 /// value for sli_radioaes_dma_sg_descr.tag specifying data type payload (will be encrypted/decrypted and authenticated)
60 #define DMA_SG_TAG_DATATYPE_AESPAYLOAD    0x00000000
61 /// value for sli_radioaes_dma_sg_descr.tag specifying data type header (will only be authenticated, not encrypted/decrypted)
62 #define DMA_SG_TAG_DATATYPE_AESHEADER     0x00000040
63 
64 /// macro to set the amount of invalid bytes in for sli_radioaes_dma_sg_descr.tag
65 #define DMA_SG_TAG_SETINVALIDBYTES(a) ((((a) & 0x1F) << 8))
66 
67 #define DMA_AXI_DESCR_CONST_ADDR       0x10000000
68 #define DMA_AXI_DESCR_REALIGN          0x20000000
69 #define DMA_AXI_DESCR_DISCARD          0x40000000
70 #define DMA_AXI_DESCR_INT_ENABLE       0x80000000
71 #define DMA_AXI_DESCR_INT_DISABLE      0x00000000
72 
73 #define DMA_AXI_DESCR_NEXT_STOP        0x00000001
74 #define DMA_AXI_DESCR_NEXT_CONTINUE    0x00000000
75 #define DMA_AXI_DESCR_MASK_NEXT_ADD    0xFFFFFFFC
76 
77 /// value of flags to discard the data
78 #define BLOCK_S_DISCARD_DATA           0x40000000
79 /// value of flags to realign the data
80 #define BLOCK_S_REALIGN_DATA           0x20000000
81 /// value of flags to set addressing in constant mode (pointing to a FIFO)
82 #define BLOCK_S_CONST_ADDR             0x10000000
83 /// value of flags to set addressing in increment mode (pointing to a buffer)
84 #define BLOCK_S_INCR_ADDR              0x00000000
85 /// mask for flags to only get DMA-related options
86 #define BLOCK_S_FLAG_MASK_DMA_PROPS    0x70000000
87 /// value of flags mask for fetcher location destination
88 #define BLOCK_S_MASK_LOC_DEST          0x00FFFFFF
89 
90 /// Config ///
91 
92 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
93 #define AES_OFFSET_CFG        0
94 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
95 #define AES_OFFSET_KEY        8
96 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
97 #define AES_OFFSET_IV        40
98 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
99 #define AES_OFFSET_IV2       56
100 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
101 #define AES_OFFSET_KEY2      72
102 /// BA411E offset for Configuration word in DMA Scatter-Gather Tag
103 #define AES_OFFSET_MASK      104
104 
105 /// BA411E Mode Register value for ECB mode of operation
106 #define AES_MODEID_ECB        0x00000100
107 /// BA411E Mode Register value for CBC mode of operation
108 #define AES_MODEID_CBC        0x00000200
109 /// BA411E Mode Register value for CTR mode of operation
110 #define AES_MODEID_CTR        0x00000400
111 /// BA411E Mode Register value for CCM mode of operation
112 #define AES_MODEID_CCM        0x00002000
113 /// BA411E Mode Register value for CMAC mode of operation
114 #define AES_MODEID_CMA        0x00010000
115 
116 /// BA411E Mode Register value for AES context saving
117 #define AES_MODEID_CX_SAVE    0x00000020
118 /// BA411E Mode Register value for AES context loading
119 #define AES_MODEID_CX_LOAD    0x00000010
120 /// BA411E Mode Register value for AES no context
121 #define AES_MODEID_NO_CX      0x00000000
122 
123 /// BA411E Mode Register value for AES keysize of 128 bits
124 #define AES_MODEID_AES128     0x00000000
125 /// BA411E Mode Register value for AES keysize of 256 bits
126 #define AES_MODEID_AES256     0x00000004
127 /// BA411E Mode Register value for AES keysize of 192 bits
128 #define AES_MODEID_AES192     0x00000008
129 
130 /// BA411E Mode Register value for encryption mode
131 #define AES_MODEID_ENCRYPT    0x00000000
132 /// BA411E Mode Register value for decryption mode
133 #define AES_MODEID_DECRYPT    0x00000001
134 
135 /// BA411E Size for IV in GCM mode
136 #define AES_IV_GCM_SIZE       12
137 /// BA411E Size for IV in all modes except GCM
138 #define AES_IV_SIZE           16
139 /// BA411E Size for Context in GCM and CCM modes
140 #define AES_CTX_xCM_SIZE      32
141 /// BA411E Size for Context in all modes except GCM and CCM
142 #define AES_CTX_SIZE          16
143 
144 ///
145 /// @brief Select which IP core the DMA will use. To set in descriptor sli_radioaes_dma_sg_descr.tag.
146 ///
147 typedef enum {
148   DMA_SG_ENGINESELECT_BYPASS = 0x00,  ///< direct bypass from input to output
149   DMA_SG_ENGINESELECT_BA411E = 0x01,  ///< data flow through BA411E AES
150   DMA_SG_ENGINESELECT_BA412  = 0x02,  ///< data flow through BA412 DES
151   DMA_SG_ENGINESELECT_BA413  = 0x03,  ///< data flow through BA413 Hash
152   DMA_SG_ENGINESELECT_BA417  = 0x04   ///< data flow through BA417 ChaChaPoly
153 } dma_engine_select_t;
154 
155 ///
156 /// @brief Structure that represent a descriptor for the DMA module
157 /// (in scatter-gather mode).
158 ///
159 typedef struct {
160   volatile uint32_t address;
161   volatile uint32_t nextDescr;
162   volatile uint32_t lengthAndIrq;
163   volatile uint32_t tag;
164 } sli_radioaes_dma_descr_t;
165 
166 #if defined(SLI_RADIOAES_REQUIRES_MASKING)
167 #define SLI_RADIOAES_MASK_DESCRIPTOR(next_descr_addr) \
168   {                                                   \
169     .address       = (uint32_t) &sli_radioaes_mask,   \
170     .nextDescr     = next_descr_addr,                 \
171     .lengthAndIrq  = 0x20000004UL,                    \
172     .tag           = 0x00006811UL                     \
173   };
174 #endif
175 
176 #define DMA_AXI_DESCR_END_POINTER ((sli_radioaes_dma_descr_t*) DMA_AXI_DESCR_NEXT_STOP)
177 
178 // Local CCM variables
179 static const uint32_t aes_ccm_config_encrypt = AES_MODEID_CCM
180                                                | AES_MODEID_NO_CX
181                                                | AES_MODEID_AES128
182                                                | AES_MODEID_ENCRYPT;
183 
184 static const uint32_t aes_ccm_config_decrypt = AES_MODEID_CCM
185                                                | AES_MODEID_NO_CX
186                                                | AES_MODEID_AES128
187                                                | AES_MODEID_DECRYPT;
188 static const uint32_t zeros = 0;
189 
sli_radioaes_run_operation(sli_radioaes_dma_descr_t * first_fetch_descriptor,sli_radioaes_dma_descr_t * first_push_descriptor)190 static sl_status_t sli_radioaes_run_operation(sli_radioaes_dma_descr_t *first_fetch_descriptor,
191                                               sli_radioaes_dma_descr_t *first_push_descriptor)
192 {
193   sli_radioaes_state_t aes_ctx;
194   #if defined(SLI_RADIOAES_REQUIRES_MASKING)
195   sli_radioaes_dma_descr_t mask_descr = SLI_RADIOAES_MASK_DESCRIPTOR((uint32_t)first_fetch_descriptor);
196   #endif
197 
198   sl_status_t status = sli_radioaes_acquire();
199   if (status == SL_STATUS_ISR) {
200     sli_radioaes_save_state(&aes_ctx);
201   } else if (status != SL_STATUS_OK) {
202     return status;
203   }
204 
205   RADIOAES->CTRL = AES_CTRL_FETCHERSCATTERGATHER | AES_CTRL_PUSHERSCATTERGATHER;
206 
207   #if defined(SLI_RADIOAES_REQUIRES_MASKING)
208   RADIOAES->FETCHADDR = (uint32_t) &mask_descr;
209   #else
210   RADIOAES->FETCHADDR = (uint32_t) first_fetch_descriptor;
211   #endif
212   RADIOAES->PUSHADDR  = (uint32_t) first_push_descriptor;
213 
214   RADIOAES->CMD = AES_CMD_STARTPUSHER | AES_CMD_STARTFETCHER;
215   while (RADIOAES->STATUS & (AES_STATUS_FETCHERBSY | AES_STATUS_PUSHERBSY)) {
216     // Wait for completion
217   }
218 
219   if (status == SL_STATUS_ISR) {
220     sli_radioaes_restore_state(&aes_ctx);
221   }
222 
223   return sli_radioaes_release();
224 }
225 
226 // CCM (and CCM-star) implementation
aes_ccm_radio(bool encrypt,const unsigned char * add_data,size_t add_length,const unsigned char * data_in,unsigned char * data_out,size_t length,const unsigned char * key,const unsigned char * header,size_t header_length,unsigned char * tag,size_t tag_length)227 static sl_status_t aes_ccm_radio(bool                encrypt,
228                                  const unsigned char *add_data,
229                                  size_t              add_length,
230                                  const unsigned char *data_in,
231                                  unsigned char       *data_out,
232                                  size_t              length,
233                                  const unsigned char *key,
234                                  const unsigned char *header,
235                                  size_t              header_length,
236                                  unsigned char       *tag,
237                                  size_t              tag_length)
238 
239 {
240   // Assumptions:
241   // * There is always header input, but the header input may be block-aligned (BLE-CCM)
242   // * There may not always be ADD input (e.g. BLE-CCM)
243   // * There may not always be data input (e.g. CCM in authenticated-only mode)
244   // * The header input is pre-calculated by the caller of this function
245   // * Data output may be NULL (in which case it is discarded)
246   // * Tag length may be 0 (CCM-star), in which case the tag pointer is also allowed to be NULL
247 
248   // Setup ver_failed output buffer and initialize it in case of decryption to an invalid value
249   volatile uint8_t ver_failed[AES_BLOCK_BYTES] = {[0 ... AES_BLOCK_BYTES - 1] = 0xFF };
250 
251   // Calculate padding bytes. Since the accelerator expects to see the AESPAYLOAD data type
252   // at least once during the operation, ensure that we're emitting a padding block in case
253   // no input data is present.
254   size_t header_pad_bytes = (AES_BLOCK_BYTES - ((header_length + add_length) % AES_BLOCK_BYTES)) % AES_BLOCK_BYTES;
255   size_t data_pad_bytes = (length > 0 ? (AES_BLOCK_BYTES - (length % AES_BLOCK_BYTES)) % AES_BLOCK_BYTES : 16);
256 
257   // Fetchers
258 
259   // Tag output. If used, always the last descriptor. Not used for CCM-* without tag, the
260   // accelerator actually looks at the header and figures out whether or not to take in
261   // tag input.
262   sli_radioaes_dma_descr_t ccm_desc_fetcher_tag = {
263     .address       = (uint32_t) tag,
264     .nextDescr     = (uint32_t) DMA_AXI_DESCR_END_POINTER,
265     .lengthAndIrq  = (uint32_t) tag_length
266                      | BLOCK_S_INCR_ADDR
267                      | BLOCK_S_REALIGN_DATA,
268     .tag           = DMA_SG_ENGINESELECT_BA411E
269                      | DMA_SG_TAG_ISDATA
270                      | DMA_SG_TAG_ISLAST
271                      | DMA_SG_TAG_DATATYPE_AESPAYLOAD
272                      | DMA_SG_TAG_SETINVALIDBYTES(AES_BLOCK_BYTES - tag_length)
273   };
274 
275   // Data input. Can be zero-length, in which case we'll issue a bogus descriptor instead.
276   sli_radioaes_dma_descr_t ccm_desc_fetcher_data = {
277     .address       = (uint32_t) (length > 0 ? data_in : ver_failed),
278     .nextDescr     = (uint32_t) ((encrypt || tag_length == 0) ? DMA_AXI_DESCR_END_POINTER : &ccm_desc_fetcher_tag),
279     .lengthAndIrq  = (uint32_t) (length > 0 ? length : data_pad_bytes)
280                      | BLOCK_S_INCR_ADDR
281                      | BLOCK_S_REALIGN_DATA,
282     .tag           = DMA_SG_ENGINESELECT_BA411E
283                      | DMA_SG_TAG_ISDATA
284                      | DMA_SG_TAG_DATATYPE_AESPAYLOAD
285                      | ((encrypt || tag_length == 0) ? DMA_SG_TAG_ISLAST : 0)
286                      | DMA_SG_TAG_SETINVALIDBYTES(data_pad_bytes),
287   };
288 
289   // Possible CCM AAD block (concatenated with the header). Can be zero-length, in which case
290   // this descriptor should not be referenced but rather bypassed to data.
291   sli_radioaes_dma_descr_t ccm_desc_fetcher_add = {
292     .address       = (uint32_t) add_data,
293     .nextDescr     = (uint32_t) &ccm_desc_fetcher_data,
294     .lengthAndIrq  = (uint32_t) add_length
295                      | BLOCK_S_INCR_ADDR
296                      | BLOCK_S_REALIGN_DATA,
297     .tag           = DMA_SG_ENGINESELECT_BA411E
298                      | DMA_SG_TAG_ISDATA
299                      | DMA_SG_TAG_DATATYPE_AESHEADER
300                      | DMA_SG_TAG_SETINVALIDBYTES(header_pad_bytes)
301   };
302 
303   // Header input block. Always present.
304   sli_radioaes_dma_descr_t ccm_desc_fetcher_header = {
305     .address       = (uint32_t) header,
306     .nextDescr     = (uint32_t) (add_length > 0 ? &ccm_desc_fetcher_add : &ccm_desc_fetcher_data),
307     .lengthAndIrq  = (uint32_t) header_length
308                      | BLOCK_S_INCR_ADDR
309                      | (add_length > 0 ? 0 : BLOCK_S_REALIGN_DATA),
310     .tag           = DMA_SG_ENGINESELECT_BA411E
311                      | DMA_SG_TAG_ISDATA
312                      | DMA_SG_TAG_DATATYPE_AESHEADER
313                      | (add_length > 0 ? 0 : DMA_SG_TAG_SETINVALIDBYTES(header_pad_bytes))
314   };
315 
316   // Key input block. Always present.
317   sli_radioaes_dma_descr_t ccm_desc_fetcher_key = {
318     .address       = (uint32_t) key,
319     .nextDescr     = (uint32_t) &ccm_desc_fetcher_header,
320     .lengthAndIrq  = (uint32_t) AES_128_KEY_BYTES
321                      | BLOCK_S_INCR_ADDR
322                      | BLOCK_S_REALIGN_DATA,
323     .tag           = DMA_SG_ENGINESELECT_BA411E
324                      | DMA_SG_TAG_ISCONFIG
325                      | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_KEY)
326   };
327 
328   // Operation configuration word block. Always present.
329   sli_radioaes_dma_descr_t ccm_desc_fetcher_config = {
330     .address       = (uint32_t) (encrypt ? &aes_ccm_config_encrypt : &aes_ccm_config_decrypt),
331     .nextDescr     = (uint32_t) &ccm_desc_fetcher_key,
332     .lengthAndIrq  = (uint32_t) RADIOAES_CONFIG_BYTES
333                      | BLOCK_S_INCR_ADDR
334                      | BLOCK_S_REALIGN_DATA,
335     .tag           = DMA_SG_ENGINESELECT_BA411E
336                      | DMA_SG_TAG_ISCONFIG
337                      | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_CFG)
338   };
339 
340   // Pushers
341 
342   // Tag / verification output padding, only if 0 < tag length < 16 bytes.
343   sli_radioaes_dma_descr_t ccm_desc_pusher_final_padding = {
344     .address       = (uint32_t) NULL,
345     .nextDescr     = (uint32_t) DMA_AXI_DESCR_END_POINTER,
346     .lengthAndIrq  = (uint32_t) (AES_BLOCK_BYTES - tag_length)
347                      | DMA_AXI_DESCR_DISCARD
348   };
349 
350   // Tag output. Direct into tag buffer for encrypt, into local buffer for
351   // decrypt-and-verify. This descriptor is not referenced with tag_length == 0 (CCM-*)
352   sli_radioaes_dma_descr_t ccm_desc_pusher_tag = {
353     .address       = (uint32_t) (encrypt ? tag : (unsigned char *)ver_failed),
354     .nextDescr     = (uint32_t) ((AES_BLOCK_BYTES - tag_length) > 0 ? &ccm_desc_pusher_final_padding : DMA_AXI_DESCR_END_POINTER),
355     .lengthAndIrq  = (uint32_t) tag_length
356   };
357 
358   // Data padding output. There's guaranteed always at least one of data or data padding.
359   sli_radioaes_dma_descr_t ccm_desc_pusher_data_padding = {
360     .address       = (uint32_t) NULL,
361     .nextDescr     = (uint32_t) (tag_length > 0 ? &ccm_desc_pusher_tag : DMA_AXI_DESCR_END_POINTER),
362     .lengthAndIrq  = (uint32_t) data_pad_bytes
363                      | DMA_AXI_DESCR_DISCARD,
364   };
365 
366   // Data (ciphertext/plaintext) output. Pointer can be NULL, in which case we tell the
367   // DMA to discard the data.
368   sli_radioaes_dma_descr_t ccm_desc_pusher_data = {
369     .address       = (uint32_t) data_out,
370     .nextDescr     = (uint32_t) (data_pad_bytes > 0 ? &ccm_desc_pusher_data_padding : (tag_length > 0 ? &ccm_desc_pusher_tag : DMA_AXI_DESCR_END_POINTER)),
371     .lengthAndIrq  = (uint32_t) length
372                      | (data_out == NULL ? DMA_AXI_DESCR_DISCARD : 0),
373   };
374 
375   // Discard all AAD input (which is reflected back to the output). There's guaranteed always a header.
376   sli_radioaes_dma_descr_t ccm_desc_pusher_header_add = {
377     .address       = (uint32_t) NULL,
378     .nextDescr     = (uint32_t) (length > 0 ? &ccm_desc_pusher_data : &ccm_desc_pusher_data_padding),
379     .lengthAndIrq  = (uint32_t) (header_length + add_length + header_pad_bytes)
380                      | DMA_AXI_DESCR_DISCARD
381   };
382 
383   sl_status_t status = sli_radioaes_run_operation(&ccm_desc_fetcher_config, &ccm_desc_pusher_header_add);
384 
385   if (status != SL_STATUS_OK) {
386     return status;
387   }
388 
389   // Check MIC
390   if (!encrypt) {
391     uint32_t accumulator = 0;
392     for (size_t i = 0; i < tag_length; i++) {
393       accumulator |= ver_failed[i];
394     }
395     if (accumulator != 0) {
396       return SL_STATUS_INVALID_SIGNATURE;
397     }
398   }
399   return SL_STATUS_OK;
400 }
401 
402 // Perform a CCM encrypt/decrypt operation with BLE parameters and input.
403 // This means:
404 // * 13 bytes IV
405 // * 1 byte AAD (parameter 'header')
406 // * AES-128 key (16 byte key)
407 // * in-place encrypt/decrypt with variable length plain/ciphertext
408 //   (up to 64 kB, uint16 overflow)
409 // * 4 byte tag
aes_ccm_ble(bool encrypt,unsigned char * data,size_t length,const unsigned char * key,const unsigned char * iv,unsigned char header,unsigned char * tag)410 static sl_status_t aes_ccm_ble(bool                encrypt,
411                                unsigned char       *data,
412                                size_t              length,
413                                const unsigned char *key,
414                                const unsigned char *iv,
415                                unsigned char       header,
416                                unsigned char       *tag)
417 
418 {
419   uint8_t b0b1[19];
420 
421   // Fill in B0 block according to BLE spec
422   b0b1[0] = 0x49U;
423 
424   // Copy in the 13 bytes of nonce
425   for (size_t i = 0; i < 13; i++) {
426     b0b1[i + 1] = iv[i];
427   }
428 
429   b0b1[14] = (uint8_t) length >> 8;
430   b0b1[15] = (uint8_t) length;
431   b0b1[16] = 0; // upper octet of AAD length
432   b0b1[17] = 1; // lower octet of AAD length (BLE CCM always has only one byte of AAD)
433   b0b1[18] = header; // AAD
434 
435   return aes_ccm_radio(encrypt,
436                        NULL, 0,
437                        data, data, length,
438                        key,
439                        b0b1, sizeof(b0b1),
440                        tag, 4);
441 }
442 
sli_aes_crypt_ctr_radio(const unsigned char * key,unsigned int keybits,const unsigned char input[AES_BLOCK_BYTES],const unsigned char iv_in[AES_BLOCK_BYTES],volatile unsigned char iv_out[AES_BLOCK_BYTES],volatile unsigned char output[AES_BLOCK_BYTES])443 sl_status_t sli_aes_crypt_ctr_radio(const unsigned char    *key,
444                                     unsigned int           keybits,
445                                     const unsigned char    input[AES_BLOCK_BYTES],
446                                     const unsigned char    iv_in[AES_BLOCK_BYTES],
447                                     volatile unsigned char iv_out[AES_BLOCK_BYTES],
448                                     volatile unsigned char output[AES_BLOCK_BYTES])
449 {
450   uint32_t aes_config;
451   static const uint32_t zero = 0;
452 
453   switch (keybits) {
454     case 256:
455       aes_config = AES_MODEID_CTR | AES_MODEID_CX_LOAD | (((uint32_t)iv_out != 0) ? AES_MODEID_CX_SAVE : 0) | AES_MODEID_AES256;
456       break;
457     case 192:
458       return SL_STATUS_NOT_SUPPORTED;
459     case 128:
460       aes_config = AES_MODEID_CTR | AES_MODEID_CX_LOAD | (((uint32_t)iv_out != 0) ? AES_MODEID_CX_SAVE : 0) | AES_MODEID_AES128;
461       break;
462     default:
463       return SL_STATUS_INVALID_KEY;
464   }
465 
466   sli_radioaes_dma_descr_t aes_desc_pusher_ctx = {
467     .address       = (uint32_t) iv_out,
468     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
469     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
470     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST
471   };
472 
473   sli_radioaes_dma_descr_t aes_desc_pusher_data = {
474     .address       = (uint32_t) output,
475     .nextDescr     = (((uint32_t)iv_out != 0) ? (uint32_t) &aes_desc_pusher_ctx : DMA_AXI_DESCR_NEXT_STOP),
476     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
477     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISDATA
478   };
479 
480   sli_radioaes_dma_descr_t aes_desc_fetcher_data = {
481     .address       = (uint32_t) input,
482     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
483     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
484     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST | DMA_SG_TAG_ISDATA | DMA_SG_TAG_DATATYPE_AESPAYLOAD
485   };
486 
487   sli_radioaes_dma_descr_t aes_desc_fetcher_no_ctx = {
488     .address       = (uint32_t) &zero,
489     .nextDescr     = (uint32_t) &aes_desc_fetcher_data,
490     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_CONST_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
491     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_IV)
492   };
493 
494   sli_radioaes_dma_descr_t aes_desc_fetcher_ctx = {
495     .address       = (uint32_t) iv_in,
496     .nextDescr     = (uint32_t) &aes_desc_fetcher_data,
497     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
498     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_IV)
499   };
500 
501   sli_radioaes_dma_descr_t aes_desc_fetcher_config = {
502     .address       = (uint32_t) &aes_config,
503     .nextDescr     = (((uint32_t)iv_in != 0) ? (uint32_t) &aes_desc_fetcher_ctx : (uint32_t) &aes_desc_fetcher_no_ctx),
504     .lengthAndIrq  = sizeof(aes_config),
505     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_CFG)
506   };
507 
508   sli_radioaes_dma_descr_t aes_desc_fetcher_key = {
509     .address       = (uint32_t) key,
510     .nextDescr     = (uint32_t) &aes_desc_fetcher_config,
511     .lengthAndIrq  = (uint32_t) (keybits / 8) | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
512     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_KEY)
513   };
514 
515   // Start operation
516   return sli_radioaes_run_operation(&aes_desc_fetcher_key, &aes_desc_pusher_data);
517 }
518 
sli_aes_crypt_ecb_radio(bool encrypt,const unsigned char * key,unsigned int keybits,const unsigned char input[AES_BLOCK_BYTES],volatile unsigned char output[AES_BLOCK_BYTES])519 sl_status_t sli_aes_crypt_ecb_radio(bool                   encrypt,
520                                     const unsigned char    *key,
521                                     unsigned int           keybits,
522                                     const unsigned char    input[AES_BLOCK_BYTES],
523                                     volatile unsigned char output[AES_BLOCK_BYTES])
524 {
525   uint32_t aes_config;
526 
527   switch (keybits) {
528     case 256:
529       aes_config = AES_MODEID_ECB | AES_MODEID_NO_CX | AES_MODEID_AES256;
530       break;
531     case 192:
532       return SL_STATUS_NOT_SUPPORTED;
533     case 128:
534       aes_config = AES_MODEID_ECB | AES_MODEID_NO_CX | AES_MODEID_AES128;
535       break;
536     default:
537       return SL_STATUS_INVALID_KEY;
538   }
539 
540   aes_config |= encrypt ? AES_MODEID_ENCRYPT : AES_MODEID_DECRYPT;
541 
542   sli_radioaes_dma_descr_t aes_desc_pusher_data = {
543     .address       = (uint32_t) output,
544     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
545     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
546     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST
547   };
548 
549   sli_radioaes_dma_descr_t aes_desc_fetcher_data = {
550     .address       = (uint32_t) input,
551     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
552     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
553     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST | DMA_SG_TAG_ISDATA | DMA_SG_TAG_DATATYPE_AESPAYLOAD
554   };
555 
556   sli_radioaes_dma_descr_t aes_desc_fetcher_config = {
557     .address       = (uint32_t) &aes_config,
558     .nextDescr     = (uint32_t) &aes_desc_fetcher_data,
559     .lengthAndIrq  = sizeof(aes_config),
560     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_CFG)
561   };
562 
563   sli_radioaes_dma_descr_t aes_desc_fetcher_key = {
564     .address       = (uint32_t) key,
565     .nextDescr     = (uint32_t) &aes_desc_fetcher_config,
566     .lengthAndIrq  = (uint32_t) (keybits / 8) | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
567     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_KEY)
568   };
569 
570   // Start operation
571   return sli_radioaes_run_operation(&aes_desc_fetcher_key, &aes_desc_pusher_data);
572 }
573 
sli_aes_cmac_radio(const unsigned char * key,unsigned int keybits,const unsigned char * input,unsigned int length,volatile unsigned char output[16])574 sl_status_t sli_aes_cmac_radio(const unsigned char    *key,
575                                unsigned int           keybits,
576                                const unsigned char    *input,
577                                unsigned int           length,
578                                volatile unsigned char output[16])
579 {
580   uint32_t aes_config;
581 
582   switch (keybits) {
583     case 256:
584       aes_config = AES_MODEID_CMA | AES_MODEID_NO_CX | AES_MODEID_AES256 | AES_MODEID_ENCRYPT;
585       break;
586     case 192:
587       return SL_STATUS_NOT_SUPPORTED;
588     case 128:
589       aes_config = AES_MODEID_CMA | AES_MODEID_NO_CX | AES_MODEID_AES128 | AES_MODEID_ENCRYPT;
590       break;
591     default:
592       return SL_STATUS_INVALID_KEY;
593   }
594 
595   size_t pad_len = 16 - (length % 16);
596   if (pad_len == 16 && length > 0) {
597     pad_len = 0;
598   }
599 
600   if (length == 0) {
601     length = 16UL;
602     input = (const unsigned char *)&zeros;
603   } else {
604     length = (length + 15) & ~0xFUL;
605   }
606 
607   sli_radioaes_dma_descr_t aes_desc_pusher_data = {
608     .address       = (uint32_t) output,
609     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
610     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
611     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST
612   };
613 
614   sli_radioaes_dma_descr_t aes_desc_fetcher_data = {
615     .address       = (uint32_t) input,
616     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
617     .lengthAndIrq  = length | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
618     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST | DMA_SG_TAG_ISDATA | DMA_SG_TAG_DATATYPE_AESPAYLOAD | DMA_SG_TAG_SETINVALIDBYTES(pad_len)
619   };
620 
621   sli_radioaes_dma_descr_t aes_desc_fetcher_config = {
622     .address       = (uint32_t) &aes_config,
623     .nextDescr     = (uint32_t) &aes_desc_fetcher_data,
624     .lengthAndIrq  = sizeof(aes_config),
625     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_CFG)
626   };
627 
628   sli_radioaes_dma_descr_t aes_desc_fetcher_key = {
629     .address       = (uint32_t) key,
630     .nextDescr     = (uint32_t) &aes_desc_fetcher_config,
631     .lengthAndIrq  = (uint32_t) (keybits / 8) | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
632     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_KEY)
633   };
634 
635   // Start operation
636   return sli_radioaes_run_operation(&aes_desc_fetcher_key, &aes_desc_pusher_data);
637 }
638 
639 //
640 // CCM buffer authenticated decryption optimized for BLE
641 //
sli_ccm_auth_decrypt_ble(unsigned char * data,size_t length,const unsigned char * key,const unsigned char * iv,unsigned char header,unsigned char * tag)642 sl_status_t sli_ccm_auth_decrypt_ble(unsigned char       *data,
643                                      size_t              length,
644                                      const unsigned char *key,
645                                      const unsigned char *iv,
646                                      unsigned char       header,
647                                      unsigned char       *tag)
648 {
649   return aes_ccm_ble(false,
650                      data,
651                      length,
652                      key,
653                      iv,
654                      header,
655                      (uint8_t *) tag);
656 }
657 
658 //
659 // CCM buffer encryption optimized for BLE
660 //
sli_ccm_encrypt_and_tag_ble(unsigned char * data,size_t length,const unsigned char * key,const unsigned char * iv,unsigned char header,unsigned char * tag)661 sl_status_t sli_ccm_encrypt_and_tag_ble(unsigned char       *data,
662                                         size_t              length,
663                                         const unsigned char *key,
664                                         const unsigned char *iv,
665                                         unsigned char       header,
666                                         unsigned char       *tag)
667 {
668   return aes_ccm_ble(true,
669                      data,
670                      length,
671                      key,
672                      iv,
673                      header,
674                      tag);
675 }
676 
sli_ccm_zigbee(bool encrypt,const unsigned char * data_in,unsigned char * data_out,size_t length,const unsigned char * key,const unsigned char * iv,const unsigned char * aad,size_t aad_len,unsigned char * tag,size_t tag_len)677 sl_status_t sli_ccm_zigbee(bool encrypt,
678                            const unsigned char *data_in,
679                            unsigned char       *data_out,
680                            size_t              length,
681                            const unsigned char *key,
682                            const unsigned char *iv,
683                            const unsigned char *aad,
684                            size_t              aad_len,
685                            unsigned char       *tag,
686                            size_t              tag_len)
687 {
688   // Validated assumption: for ZigBee, the authenticated data
689   // length will always fit into a 16-bit length field, meaning
690   // the header will always be either 16 or 18 bytes long.
691   uint8_t header[18];
692 
693   // Start with the 'flags' byte. It encodes whether there is AAD,
694   // and the length of the tag fields
695   header[0] = 0x01 // always 2 bytes of message length
696               | ((aad_len > 0) ? 0x40 : 0x00) // Set 'aflag' bit if there is AAD
697               | ((tag_len >= 4) ? (((tag_len - 2) / 2) << 3) : 0); // Encode tag length
698 
699   for (size_t i = 0; i < 13; i++) {
700     header[i + 1] = iv[i];
701   }
702 
703   header[14] = (uint8_t) length >> 8;
704   header[15] = (uint8_t) length;
705   if (aad_len > 0) {
706     header[16] = (uint8_t) aad_len >> 8; // upper octet of AAD length
707     header[17] = (uint8_t) aad_len; // lower octet of AAD length
708   }
709 
710   return aes_ccm_radio(encrypt,
711                        aad,
712                        aad_len,
713                        data_in,
714                        data_out,
715                        length,
716                        key,
717                        header,
718                        (aad_len > 0 ? 18 : 16),
719                        tag,
720                        tag_len);
721 }
722 
723 //
724 // Process a table of BLE RPA device keys and look for a
725 // match against the supplied hash. Algorithm is AES-128.
726 //
sli_process_ble_rpa(const unsigned char keytable[],uint32_t keymask,uint32_t prand,uint32_t hash)727 int sli_process_ble_rpa(const unsigned char keytable[],
728                         uint32_t            keymask,
729                         uint32_t            prand,
730                         uint32_t            hash)
731 {
732   int block;
733   int previous_block = -1, result = -1;
734   static const uint32_t  aes_rpa_config = AES_MODEID_ECB
735                                           | AES_MODEID_NO_CX
736                                           | AES_MODEID_AES128
737                                           | AES_MODEID_ENCRYPT;
738 
739   uint32_t rpa_data_in[AES_BLOCK_BYTES / sizeof(uint32_t)] = { 0 };
740   volatile uint32_t rpa_data_out[AES_BLOCK_BYTES / sizeof(uint32_t)];
741   sli_radioaes_state_t aes_ctx;
742   CORE_DECLARE_IRQ_STATE;
743 
744   rpa_data_in[3] = __REV(prand);
745 
746   sli_radioaes_dma_descr_t aes_desc_pusher_data = {
747     .address       = (uint32_t) rpa_data_out,
748     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
749     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
750     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST
751   };
752 
753   sli_radioaes_dma_descr_t aes_desc_fetcher_data = {
754     .address       = (uint32_t) rpa_data_in,
755     .nextDescr     = DMA_AXI_DESCR_NEXT_STOP,
756     .lengthAndIrq  = AES_BLOCK_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
757     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISLAST | DMA_SG_TAG_ISDATA | DMA_SG_TAG_DATATYPE_AESPAYLOAD
758   };
759 
760   sli_radioaes_dma_descr_t aes_desc_fetcher_config = {
761     .address       = (uint32_t) &aes_rpa_config,
762     .nextDescr     = (uint32_t) &aes_desc_fetcher_data,
763     .lengthAndIrq  = sizeof(aes_rpa_config),
764     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_CFG)
765   };
766 
767   volatile sli_radioaes_dma_descr_t aes_desc_fetcher_key = {
768     .address       = (uint32_t) NULL, // Filled out in each round of RPA check
769     .nextDescr     = (uint32_t) &aes_desc_fetcher_config,
770     .lengthAndIrq  = (uint32_t) AES_128_KEY_BYTES | (BLOCK_S_INCR_ADDR & BLOCK_S_FLAG_MASK_DMA_PROPS),
771     .tag           = DMA_SG_ENGINESELECT_BA411E | DMA_SG_TAG_ISCONFIG | DMA_SG_TAG_SETCFGOFFSET(AES_OFFSET_KEY)
772   };
773 
774   // Start operation
775   sl_status_t status = sli_radioaes_acquire();
776   if (status == SL_STATUS_ISR) {
777     sli_radioaes_save_state(&aes_ctx);
778   } else if (status != SL_STATUS_OK) {
779     return -1;
780   }
781 
782   RADIOAES->CTRL = AES_CTRL_FETCHERSCATTERGATHER | AES_CTRL_PUSHERSCATTERGATHER;
783 
784   #if defined(SLI_RADIOAES_REQUIRES_MASKING)
785   // Start with feeding the mask input
786   sli_radioaes_dma_descr_t mask_descr = SLI_RADIOAES_MASK_DESCRIPTOR(DMA_AXI_DESCR_NEXT_STOP);
787   RADIOAES->FETCHADDR = (uint32_t) &mask_descr;
788   RADIOAES->CMD = AES_CMD_STARTFETCHER;
789   #endif
790 
791   // Start a critical section to avoid preemption in-between loading of the RPA key
792   // and starting the corresponding data pusher.
793   CORE_ENTER_CRITICAL();
794 
795   // Data output contains hash in the most significant word (WORD3).
796   // Descriptors for blocks that are not included in key mask will be skipped.
797   for (block = 0; block < RADIOAES_BLE_RPA_MAX_KEYS; block++) {
798     if ( keymask & (1U << block) ) {  // Skip masked keys
799       // Handle pending interrupts while the peripheral is in 'preemptable' state
800       CORE_YIELD_CRITICAL();
801       // Write key address and start operation
802       while (RADIOAES->STATUS & AES_STATUS_FETCHERBSY) {
803         // Wait for completion
804       }
805       aes_desc_fetcher_key.address = (uint32_t) &keytable[block * AES_128_KEY_BYTES];
806       RADIOAES->FETCHADDR = (uint32_t) &aes_desc_fetcher_key;
807 
808       RADIOAES->CMD = AES_CMD_STARTFETCHER;
809 
810       // Wait for pusher from previous round to finish
811       while (RADIOAES->STATUS & AES_STATUS_PUSHERBSY) {
812         // Wait for completion
813       }
814       RADIOAES->PUSHADDR  = (uint32_t) &aes_desc_pusher_data;
815 
816       // Check previous results while AES is processing
817       if ((previous_block >= 0) && ((rpa_data_out[3] & 0xFFFFFF00) == __REV(hash)) ) {
818         // Make sure AES is finished before returning
819         RADIOAES->CMD = AES_CMD_STARTPUSHER;
820         result = previous_block;
821         break;
822       }
823 
824       // Start pusher so it is ready to push results when encryption is done
825       RADIOAES->CMD = AES_CMD_STARTPUSHER;
826       previous_block = block;
827     }
828   }
829 
830   CORE_EXIT_CRITICAL();
831 
832   // Wait for last data and check it
833   while (RADIOAES->STATUS & AES_STATUS_PUSHERBSY) {
834     // Wait for completion
835   }
836 
837   if (status == SL_STATUS_ISR) {
838     sli_radioaes_restore_state(&aes_ctx);
839   }
840 
841   sli_radioaes_release();
842 
843   if (result >= 0) {
844     return result;
845   }
846 
847   if ((rpa_data_out[3] & 0xFFFFFF00) == __REV(hash) ) {
848     return previous_block;
849   }
850 
851   // No match
852   return -1;
853 }
854 
sli_aes_seed_mask(void)855 void sli_aes_seed_mask(void)
856 {
857   // Acquiring and releasing the peripheral should ensure the mask is properly
858   // set.
859   (void) sli_radioaes_acquire();
860   (void) sli_radioaes_release();
861 }
862 
863 /// @endcond
864 #endif // defined(RADIOAES_PRESENT)
865