1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * CRACEN CryptoMaster, AES engine model
9  *
10  * Notes:
11  *  * Only ECB mode is supported by now
12  *
13  *  * Only SW programmed key is supported by now
14  *
15  *  * This AES model does not bother clearing the AES Keys if they are incorrectly programmed
16  *    or between runs
17  */
18 
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include "bs_tracing.h"
24 #include "NHW_config.h"
25 #include "NHW_CRACEN_CM.h"
26 #include "BLECrypt_if.h"
27 #include "nsi_hws_models_if.h"
28 
29 #define CONFIG_ENCORDEC_MASK 0x1
30 #define CONFIG_MODE_MASK 0x1FF00
31 #define BLOCK_SIZE 128/8
32 
33 static struct CM_AES_regs_t {
34   uint32_t CONFIG;
35   uint32_t reserved;
36   uint32_t KEY[8];
37   uint32_t IV[4];
38   uint32_t IV2[4];
39   uint32_t KEY2[8];
40   uint32_t MASK;
41 } CM_AES_regs;
42 
43 static int t_ecb[] = NHW_CRACEN_CM_AES_t_ECB;
44 
45 static struct CM_AES_st_t {
46   int AES_KEY_size;
47   char data_out[BLOCK_SIZE];
48 } CM_AES_st;
49 
50 bs_time_t Timer_CRACEN_CM_AES;
51 
nhw_CRACEN_CM_AES_init(void)52 void nhw_CRACEN_CM_AES_init(void) {
53   memset(&CM_AES_regs, 0, sizeof(CM_AES_regs));
54   memset(&CM_AES_st, 0, sizeof(CM_AES_st));
55 
56   Timer_CRACEN_CM_AES = TIME_NEVER;
57 }
58 
nhw_CRACEN_CM_AES_get_mode(void)59 static int nhw_CRACEN_CM_AES_get_mode(void) {
60   return (CM_AES_regs.CONFIG & CONFIG_MODE_MASK) >> 8;
61 }
62 
nhw_CRACEN_CM_AES_get_KeySel(void)63 static int nhw_CRACEN_CM_AES_get_KeySel(void) {
64   return ((CM_AES_regs.CONFIG >> 6) & 0x3) | ((CM_AES_regs.CONFIG >> 26) & 0x7);;
65 }
66 
nhw_CRACEN_CM_AES_process_data(struct CM_tag * tag_st,char * buf,size_t len)67 static void nhw_CRACEN_CM_AES_process_data(struct CM_tag *tag_st, char* buf, size_t len) {
68   if (nhw_CRACEN_CM_AES_get_mode() != 1) {
69     bs_trace_error_time_line("%s: Only ECB mode supported by now\n",
70                              __func__);
71   }
72   if (nhw_CRACEN_CM_AES_get_KeySel() != 0) {
73     bs_trace_error_time_line("%s: Only SW programmed key supported by now\n",
74                              __func__);
75   }
76   if (len != BLOCK_SIZE) {
77     bs_trace_error_time_line("Block size of 128b excedded for payload\n");
78   }
79   BLECrypt_if_aes_ecb((uint8_t *)CM_AES_regs.KEY, CM_AES_st.AES_KEY_size,
80                       (uint8_t *)buf, (uint8_t *)CM_AES_st.data_out);
81 
82   Timer_CRACEN_CM_AES = nsi_hws_get_time() + t_ecb[(CM_AES_st.AES_KEY_size - 128)/64];
83   nhw_CRACEN_CM_update_timer();
84 }
85 
nhw_CRACEN_CM_AES_feed_data(struct CM_tag * tag_st,char * buf,size_t len)86 bool nhw_CRACEN_CM_AES_feed_data(struct CM_tag *tag_st, char* buf, size_t len) {
87 
88   if (tag_st->DataOrConf == 1) { // Config
89     int OffsetStartAddr = tag_st->OffsetStartAddr;
90     if (OffsetStartAddr + len > sizeof(CM_AES_regs)) {
91       bs_trace_error_time_line("%s: Attempted to write into non existent CONFIG register (%i..%i)\n",
92                                __func__, OffsetStartAddr, OffsetStartAddr + len);
93     }
94     memcpy(&((char *)&CM_AES_regs)[OffsetStartAddr], buf, len);
95     if (OffsetStartAddr == offsetof(struct CM_AES_regs_t , KEY)) {
96       if ((len*8 != 128) && (len*8 != 192) && (len*8 != 256)) {
97         bs_trace_warning_time_line("%s: Invalid key length (%i)\n", __func__, len*8);
98       } else {
99         CM_AES_st.AES_KEY_size = len*8;
100       }
101     }
102     return false;
103   } else { // Data
104     if (tag_st->DataType == 0) { // Payload
105       if (tag_st->Invalid_bytes != 0) {
106         bs_trace_error_time_line("%s: Invalid_bytes != 0 not supported\n", __func__);
107       }
108       nhw_CRACEN_CM_AES_process_data(tag_st, buf, len);
109     } else { // Header
110       bs_trace_error_time_line("Only ECB mode implemented by now => DataType %i not supported\n",
111                                tag_st->DataType);
112     }
113     return false;
114   }
115 }
116 
nhw_CRACEN_CM_AES_timer_triggered(void)117 void nhw_CRACEN_CM_AES_timer_triggered(void) {
118   Timer_CRACEN_CM_AES = TIME_NEVER;
119   nhw_CRACEN_CM_update_timer();
120   nhw_CRACEN_CM_give_pusher_data(CM_AES_st.data_out, BLOCK_SIZE);
121 }
122 
nhw_CRACEN_CM_AES_hard_stop(void)123 void nhw_CRACEN_CM_AES_hard_stop(void) {
124   nhw_CRACEN_CM_AES_init();
125   nhw_CRACEN_CM_update_timer();
126 }
127