1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2014 Marek Vasut <marex@denx.de>
4  * Copyright (C) 2025 Ion Agorria <ion@agorria.com>
5  *
6  * Command for AES-[128/192/256] operations.
7  */
8 
9 #include <command.h>
10 #include <uboot_aes.h>
11 #include <malloc.h>
12 #include <asm/byteorder.h>
13 #include <linux/compiler.h>
14 #include <mapmem.h>
15 #include <vsprintf.h>
16 #include <dm/uclass.h>
17 #include <dm/device.h>
18 
aes_get_key_len(char * command)19 u32 aes_get_key_len(char *command)
20 {
21 	u32 key_len = AES128_KEY_LENGTH;
22 
23 	if (!strcmp(command, "aes.192"))
24 		key_len = AES192_KEY_LENGTH;
25 	else if (!strcmp(command, "aes.256"))
26 		key_len = AES256_KEY_LENGTH;
27 
28 	return key_len;
29 }
30 
aes_get_driver(struct udevice ** dev)31 int aes_get_driver(struct udevice **dev)
32 {
33 	int ret;
34 
35 	ret = uclass_get_device(UCLASS_AES, 0, dev);
36 	if (ret) {
37 		printf("Failed to get AES driver: %d\n", ret);
38 		return ret;
39 	}
40 
41 	return 0;
42 }
43 
cmd_aes_cbc_simple(int argc,char * const argv[],u32 key_len)44 int cmd_aes_cbc_simple(int argc, char *const argv[], u32 key_len)
45 {
46 	uint32_t key_addr, iv_addr, src_addr, dst_addr, len;
47 	uint8_t *key_ptr, *iv_ptr, *src_ptr, *dst_ptr;
48 	u8 key_exp[AES256_EXPAND_KEY_LENGTH];
49 	u32 aes_blocks;
50 	int enc;
51 
52 	if (argc != 7)
53 		return CMD_RET_USAGE;
54 
55 	if (!strncmp(argv[1], "enc", 3))
56 		enc = 1;
57 	else if (!strncmp(argv[1], "dec", 3))
58 		enc = 0;
59 	else
60 		return CMD_RET_USAGE;
61 
62 	key_addr = hextoul(argv[2], NULL);
63 	iv_addr = hextoul(argv[3], NULL);
64 	src_addr = hextoul(argv[4], NULL);
65 	dst_addr = hextoul(argv[5], NULL);
66 	len = hextoul(argv[6], NULL);
67 
68 	key_ptr = (uint8_t *)map_sysmem(key_addr, key_len);
69 	iv_ptr = (uint8_t *)map_sysmem(iv_addr, 128 / 8);
70 	src_ptr = (uint8_t *)map_sysmem(src_addr, len);
71 	dst_ptr = (uint8_t *)map_sysmem(dst_addr, len);
72 
73 	/* First we expand the key. */
74 	aes_expand_key(key_ptr, key_len, key_exp);
75 
76 	/* Calculate the number of AES blocks to encrypt. */
77 	aes_blocks = DIV_ROUND_UP(len, AES_BLOCK_LENGTH);
78 
79 	if (enc)
80 		aes_cbc_encrypt_blocks(key_len, key_exp, iv_ptr, src_ptr,
81 				       dst_ptr, aes_blocks);
82 	else
83 		aes_cbc_decrypt_blocks(key_len, key_exp, iv_ptr, src_ptr,
84 				       dst_ptr, aes_blocks);
85 
86 	unmap_sysmem(key_ptr);
87 	unmap_sysmem(iv_ptr);
88 	unmap_sysmem(src_ptr);
89 	unmap_sysmem(dst_ptr);
90 
91 	return CMD_RET_SUCCESS;
92 }
93 
cmd_aes_get_slots(void)94 int cmd_aes_get_slots(void)
95 {
96 	struct udevice *dev;
97 	u8 slots;
98 	int ret;
99 
100 	ret = aes_get_driver(&dev);
101 	if (ret)
102 		return ret;
103 
104 	slots = dm_aes_get_available_key_slots(dev);
105 	printf("Available slots: %d\n", slots);
106 
107 	return CMD_RET_SUCCESS;
108 }
109 
cmd_aes_set_key(int argc,char * const argv[],u32 key_len)110 int cmd_aes_set_key(int argc, char *const argv[], u32 key_len)
111 {
112 	struct udevice *dev;
113 	u32 key_addr, slot;
114 	u8 *key_ptr;
115 	int ret;
116 
117 	if (argc != 4)
118 		return CMD_RET_USAGE;
119 
120 	ret = aes_get_driver(&dev);
121 	if (ret)
122 		return ret;
123 
124 	key_addr = hextoul(argv[2], NULL);
125 	slot = hextoul(argv[3], NULL);
126 
127 	key_ptr = (uint8_t *)map_sysmem(key_addr, key_len);
128 
129 	ret = dm_aes_set_key_for_key_slot(dev, key_len * 8, key_ptr, slot);
130 	unmap_sysmem(key_ptr);
131 	if (ret) {
132 		printf("Unable to set key at slot: %d\n", ret);
133 		return CMD_RET_FAILURE;
134 	}
135 
136 	return CMD_RET_SUCCESS;
137 }
138 
cmd_aes_select_slot(int argc,char * const argv[],u32 key_len)139 int cmd_aes_select_slot(int argc, char *const argv[], u32 key_len)
140 {
141 	struct udevice *dev;
142 	u32 slot;
143 	int ret;
144 
145 	if (argc != 3)
146 		return CMD_RET_USAGE;
147 
148 	ret = aes_get_driver(&dev);
149 	if (ret)
150 		return ret;
151 
152 	slot = hextoul(argv[2], NULL);
153 
154 	ret = dm_aes_select_key_slot(dev, key_len * 8, slot);
155 	if (ret) {
156 		printf("Unable to select key slot: %d\n", ret);
157 		return CMD_RET_FAILURE;
158 	}
159 
160 	return CMD_RET_SUCCESS;
161 }
162 
cmd_aes_ecb(int argc,char * const argv[],u32 key_len)163 int cmd_aes_ecb(int argc, char *const argv[], u32 key_len)
164 {
165 	struct udevice *dev;
166 	u32 src_addr, dst_addr, len;
167 	u8 *src_ptr, *dst_ptr;
168 	u32 aes_blocks;
169 	int enc, ret;
170 
171 	if (argc != 6)
172 		return CMD_RET_USAGE;
173 
174 	ret = aes_get_driver(&dev);
175 	if (ret)
176 		return ret;
177 
178 	if (!strncmp(argv[1], "enc", 3))
179 		enc = 1;
180 	else if (!strncmp(argv[1], "dec", 3))
181 		enc = 0;
182 	else
183 		return CMD_RET_USAGE;
184 
185 	src_addr = hextoul(argv[3], NULL);
186 	dst_addr = hextoul(argv[4], NULL);
187 	len = hextoul(argv[5], NULL);
188 
189 	src_ptr = (uint8_t *)map_sysmem(src_addr, len);
190 	dst_ptr = (uint8_t *)map_sysmem(dst_addr, len);
191 
192 	/* Calculate the number of AES blocks to encrypt. */
193 	aes_blocks = DIV_ROUND_UP(len, AES_BLOCK_LENGTH);
194 
195 	if (enc)
196 		ret = dm_aes_ecb_encrypt(dev, src_ptr, dst_ptr, aes_blocks);
197 	else
198 		ret = dm_aes_ecb_decrypt(dev, src_ptr, dst_ptr, aes_blocks);
199 
200 	unmap_sysmem(src_ptr);
201 	unmap_sysmem(dst_ptr);
202 
203 	if (ret) {
204 		printf("Unable to do ecb operation: %d\n", ret);
205 		return CMD_RET_FAILURE;
206 	}
207 
208 	return CMD_RET_SUCCESS;
209 }
210 
cmd_aes_cbc(int argc,char * const argv[],u32 key_len)211 int cmd_aes_cbc(int argc, char *const argv[], u32 key_len)
212 {
213 	struct udevice *dev;
214 	u32 iv_addr, src_addr, dst_addr, len;
215 	u8 *iv_ptr, *src_ptr, *dst_ptr;
216 	u32 aes_blocks;
217 	int enc, ret;
218 
219 	if (argc != 7)
220 		return CMD_RET_USAGE;
221 
222 	ret = aes_get_driver(&dev);
223 	if (ret)
224 		return ret;
225 
226 	if (!strncmp(argv[1], "enc", 3))
227 		enc = 1;
228 	else if (!strncmp(argv[1], "dec", 3))
229 		enc = 0;
230 	else
231 		return CMD_RET_USAGE;
232 
233 	iv_addr = hextoul(argv[3], NULL);
234 	src_addr = hextoul(argv[4], NULL);
235 	dst_addr = hextoul(argv[5], NULL);
236 	len = hextoul(argv[6], NULL);
237 
238 	iv_ptr = (uint8_t *)map_sysmem(iv_addr, AES_BLOCK_LENGTH);
239 	src_ptr = (uint8_t *)map_sysmem(src_addr, len);
240 	dst_ptr = (uint8_t *)map_sysmem(dst_addr, len);
241 
242 	/* Calculate the number of AES blocks to encrypt. */
243 	aes_blocks = DIV_ROUND_UP(len, AES_BLOCK_LENGTH);
244 
245 	if (enc)
246 		ret = dm_aes_cbc_encrypt(dev, iv_ptr, src_ptr, dst_ptr, aes_blocks);
247 	else
248 		ret = dm_aes_cbc_decrypt(dev, iv_ptr, src_ptr, dst_ptr, aes_blocks);
249 
250 	unmap_sysmem(iv_ptr);
251 	unmap_sysmem(src_ptr);
252 	unmap_sysmem(dst_ptr);
253 
254 	if (ret) {
255 		printf("Unable to do cbc operation: %d\n", ret);
256 		return CMD_RET_FAILURE;
257 	}
258 
259 	return CMD_RET_SUCCESS;
260 }
261 
262 /**
263  * do_aes() - Handle the "aes" command-line command
264  * @cmdtp:	Command data struct pointer
265  * @flag:	Command flag
266  * @argc:	Command-line argument count
267  * @argv:	Array of command-line arguments
268  *
269  * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
270  * on error.
271  */
do_aes(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])272 static int do_aes(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
273 {
274 	u32 key_len;
275 
276 	if (argc < 2)
277 		return CMD_RET_USAGE;
278 
279 	key_len = aes_get_key_len(argv[0]);
280 
281 	if (!strncmp(argv[1], "enc", 3) || !strncmp(argv[1], "dec", 3))
282 		return cmd_aes_cbc_simple(argc, argv, key_len);
283 	else if (CONFIG_IS_ENABLED(DM_AES) && !strncmp(argv[1], "get_slots", 9))
284 		return cmd_aes_get_slots();
285 	else if (CONFIG_IS_ENABLED(DM_AES) && !strncmp(argv[1], "set_key", 7))
286 		return cmd_aes_set_key(argc, argv, key_len);
287 	else if (CONFIG_IS_ENABLED(DM_AES) && !strncmp(argv[1], "select_slot", 11))
288 		return cmd_aes_select_slot(argc, argv, key_len);
289 	else if (CONFIG_IS_ENABLED(DM_AES) && !strncmp(argv[1], "ecb", 3))
290 		return cmd_aes_ecb(argc, argv, key_len);
291 	else if (CONFIG_IS_ENABLED(DM_AES) && !strncmp(argv[1], "cbc", 3))
292 		return cmd_aes_cbc(argc, argv, key_len);
293 	else
294 		return CMD_RET_USAGE;
295 }
296 
297 /***************************************************/
298 U_BOOT_LONGHELP(aes,
299 	"[.128,.192,.256] enc key iv src dst len - CBC encrypt block of data $len bytes long\n"
300 	"                             at address $src using a key at address\n"
301 	"                             $key with initialization vector at address\n"
302 	"                             $iv. Store the result at address $dst.\n"
303 	"                             The $len size must be multiple of 16 bytes.\n"
304 	"                             The $key and $iv must be 16 bytes long.\n"
305 	"aes [.128,.192,.256] dec key iv src dst len - CBC decrypt block of data $len bytes long\n"
306 	"                             at address $src using a key at address\n"
307 	"                             $key with initialization vector at address\n"
308 	"                             $iv. Store the result at address $dst.\n"
309 	"                             The $len size must be multiple of 16 bytes.\n"
310 	"                             The $key and $iv must be 16 bytes long."
311 
312 #if CONFIG_IS_ENABLED(DM_AES)
313 	"\n"
314 	"aes get_slots - Gives number of available key slots\n"
315 	"aes [.128,.192,.256] set_key key slot - Load key at address $key into the slot $slot\n"
316 	"aes [.128,.192,.256] select_slot slot - Select current active key slot\n"
317 	"aes [.128,.192,.256] ecb enc src dst len - ECB encrypt block of data $len bytes long\n"
318 	"                             at address $src using a key at current\n"
319 	"                             slot. Store the result at address $dst.\n"
320 	"                             The $len size must be multiple of 16 bytes.\n"
321 	"aes [.128,.192,.256] ecb dec src dst len - ECB decrypt block of data $len bytes long\n"
322 	"                             at address $src using a key at current\n"
323 	"                             slot. Store the result at address $dst.\n"
324 	"                             The $len size must be multiple of 16 bytes.\n"
325 	"aes [.128,.192,.256] cbc enc iv src dst len - CBC encrypt block of data $len bytes long\n"
326 	"                             at address $src using a key at current\n"
327 	"                             slot with initialization vector at address\n"
328 	"                             $iv. Store the result at address $dst.\n"
329 	"                             The $len size must be multiple of 16 bytes.\n"
330 	"                             The $iv must be 16 bytes long.\n"
331 	"aes [.128,.192,.256] cbc dec iv src dst len - CBC decrypt block of data $len bytes long\n"
332 	"                             at address $src using a key at current\n"
333 	"                             slot with initialization vector at address\n"
334 	"                             $iv. Store the result at address $dst.\n"
335 	"                             The $len size must be multiple of 16 bytes.\n"
336 	"                             The $iv must be 16 bytes long."
337 #endif
338 );
339 
340 U_BOOT_CMD(
341 	aes, 7, 1, do_aes,
342 	"AES 128/192/256 operations",
343 	aes_help_text
344 );
345