env: Move env_set() to env.h
[oweals/u-boot.git] / common / hash.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2012 The Chromium OS Authors.
4  *
5  * (C) Copyright 2011
6  * Joe Hershberger, National Instruments, joe.hershberger@ni.com
7  *
8  * (C) Copyright 2000
9  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
10  */
11
12 #ifndef USE_HOSTCC
13 #include <common.h>
14 #include <command.h>
15 #include <env.h>
16 #include <malloc.h>
17 #include <mapmem.h>
18 #include <hw_sha.h>
19 #include <asm/io.h>
20 #include <linux/errno.h>
21 #else
22 #include "mkimage.h"
23 #include <time.h>
24 #include <image.h>
25 #endif /* !USE_HOSTCC*/
26
27 #include <hash.h>
28 #include <u-boot/crc.h>
29 #include <u-boot/sha1.h>
30 #include <u-boot/sha256.h>
31 #include <u-boot/md5.h>
32
33 #if defined(CONFIG_SHA1) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
34 static int hash_init_sha1(struct hash_algo *algo, void **ctxp)
35 {
36         sha1_context *ctx = malloc(sizeof(sha1_context));
37         sha1_starts(ctx);
38         *ctxp = ctx;
39         return 0;
40 }
41
42 static int hash_update_sha1(struct hash_algo *algo, void *ctx, const void *buf,
43                             unsigned int size, int is_last)
44 {
45         sha1_update((sha1_context *)ctx, buf, size);
46         return 0;
47 }
48
49 static int hash_finish_sha1(struct hash_algo *algo, void *ctx, void *dest_buf,
50                             int size)
51 {
52         if (size < algo->digest_size)
53                 return -1;
54
55         sha1_finish((sha1_context *)ctx, dest_buf);
56         free(ctx);
57         return 0;
58 }
59 #endif
60
61 #if defined(CONFIG_SHA256) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
62 static int hash_init_sha256(struct hash_algo *algo, void **ctxp)
63 {
64         sha256_context *ctx = malloc(sizeof(sha256_context));
65         sha256_starts(ctx);
66         *ctxp = ctx;
67         return 0;
68 }
69
70 static int hash_update_sha256(struct hash_algo *algo, void *ctx,
71                               const void *buf, unsigned int size, int is_last)
72 {
73         sha256_update((sha256_context *)ctx, buf, size);
74         return 0;
75 }
76
77 static int hash_finish_sha256(struct hash_algo *algo, void *ctx, void
78                               *dest_buf, int size)
79 {
80         if (size < algo->digest_size)
81                 return -1;
82
83         sha256_finish((sha256_context *)ctx, dest_buf);
84         free(ctx);
85         return 0;
86 }
87 #endif
88
89 static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
90 {
91         uint16_t *ctx = malloc(sizeof(uint16_t));
92         *ctx = 0;
93         *ctxp = ctx;
94         return 0;
95 }
96
97 static int hash_update_crc16_ccitt(struct hash_algo *algo, void *ctx,
98                                    const void *buf, unsigned int size,
99                                    int is_last)
100 {
101         *((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), buf, size);
102         return 0;
103 }
104
105 static int hash_finish_crc16_ccitt(struct hash_algo *algo, void *ctx,
106                                    void *dest_buf, int size)
107 {
108         if (size < algo->digest_size)
109                 return -1;
110
111         *((uint16_t *)dest_buf) = *((uint16_t *)ctx);
112         free(ctx);
113         return 0;
114 }
115
116 static int hash_init_crc32(struct hash_algo *algo, void **ctxp)
117 {
118         uint32_t *ctx = malloc(sizeof(uint32_t));
119         *ctx = 0;
120         *ctxp = ctx;
121         return 0;
122 }
123
124 static int hash_update_crc32(struct hash_algo *algo, void *ctx,
125                              const void *buf, unsigned int size, int is_last)
126 {
127         *((uint32_t *)ctx) = crc32(*((uint32_t *)ctx), buf, size);
128         return 0;
129 }
130
131 static int hash_finish_crc32(struct hash_algo *algo, void *ctx, void *dest_buf,
132                              int size)
133 {
134         if (size < algo->digest_size)
135                 return -1;
136
137         *((uint32_t *)dest_buf) = *((uint32_t *)ctx);
138         free(ctx);
139         return 0;
140 }
141
142 /*
143  * These are the hash algorithms we support.  If we have hardware acceleration
144  * is enable we will use that, otherwise a software version of the algorithm.
145  * Note that algorithm names must be in lower case.
146  */
147 static struct hash_algo hash_algo[] = {
148 #ifdef CONFIG_SHA1
149         {
150                 .name           = "sha1",
151                 .digest_size    = SHA1_SUM_LEN,
152                 .chunk_size     = CHUNKSZ_SHA1,
153 #ifdef CONFIG_SHA_HW_ACCEL
154                 .hash_func_ws   = hw_sha1,
155 #else
156                 .hash_func_ws   = sha1_csum_wd,
157 #endif
158 #ifdef CONFIG_SHA_PROG_HW_ACCEL
159                 .hash_init      = hw_sha_init,
160                 .hash_update    = hw_sha_update,
161                 .hash_finish    = hw_sha_finish,
162 #else
163                 .hash_init      = hash_init_sha1,
164                 .hash_update    = hash_update_sha1,
165                 .hash_finish    = hash_finish_sha1,
166 #endif
167         },
168 #endif
169 #ifdef CONFIG_SHA256
170         {
171                 .name           = "sha256",
172                 .digest_size    = SHA256_SUM_LEN,
173                 .chunk_size     = CHUNKSZ_SHA256,
174 #ifdef CONFIG_SHA_HW_ACCEL
175                 .hash_func_ws   = hw_sha256,
176 #else
177                 .hash_func_ws   = sha256_csum_wd,
178 #endif
179 #ifdef CONFIG_SHA_PROG_HW_ACCEL
180                 .hash_init      = hw_sha_init,
181                 .hash_update    = hw_sha_update,
182                 .hash_finish    = hw_sha_finish,
183 #else
184                 .hash_init      = hash_init_sha256,
185                 .hash_update    = hash_update_sha256,
186                 .hash_finish    = hash_finish_sha256,
187 #endif
188         },
189 #endif
190         {
191                 .name           = "crc16-ccitt",
192                 .digest_size    = 2,
193                 .chunk_size     = CHUNKSZ,
194                 .hash_func_ws   = crc16_ccitt_wd_buf,
195                 .hash_init      = hash_init_crc16_ccitt,
196                 .hash_update    = hash_update_crc16_ccitt,
197                 .hash_finish    = hash_finish_crc16_ccitt,
198         },
199         {
200                 .name           = "crc32",
201                 .digest_size    = 4,
202                 .chunk_size     = CHUNKSZ_CRC32,
203                 .hash_func_ws   = crc32_wd_buf,
204                 .hash_init      = hash_init_crc32,
205                 .hash_update    = hash_update_crc32,
206                 .hash_finish    = hash_finish_crc32,
207         },
208 };
209
210 /* Try to minimize code size for boards that don't want much hashing */
211 #if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
212         defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH)
213 #define multi_hash()    1
214 #else
215 #define multi_hash()    0
216 #endif
217
218 int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
219 {
220         int i;
221
222         for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
223                 if (!strcmp(algo_name, hash_algo[i].name)) {
224                         *algop = &hash_algo[i];
225                         return 0;
226                 }
227         }
228
229         debug("Unknown hash algorithm '%s'\n", algo_name);
230         return -EPROTONOSUPPORT;
231 }
232
233 int hash_progressive_lookup_algo(const char *algo_name,
234                                  struct hash_algo **algop)
235 {
236         int i;
237
238         for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
239                 if (!strcmp(algo_name, hash_algo[i].name)) {
240                         if (hash_algo[i].hash_init) {
241                                 *algop = &hash_algo[i];
242                                 return 0;
243                         }
244                 }
245         }
246
247         debug("Unknown hash algorithm '%s'\n", algo_name);
248         return -EPROTONOSUPPORT;
249 }
250
251 #ifndef USE_HOSTCC
252 int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
253 {
254         struct hash_algo *algo;
255         int ret;
256         int i;
257
258         ret = hash_lookup_algo(algo_name, &algo);
259         if (ret)
260                 return ret;
261
262         for (i = 0; i < algo->digest_size; i++) {
263                 char chr[3];
264
265                 strncpy(chr, &str[i * 2], 2);
266                 result[i] = simple_strtoul(chr, NULL, 16);
267         }
268
269         return 0;
270 }
271
272 int hash_block(const char *algo_name, const void *data, unsigned int len,
273                uint8_t *output, int *output_size)
274 {
275         struct hash_algo *algo;
276         int ret;
277
278         ret = hash_lookup_algo(algo_name, &algo);
279         if (ret)
280                 return ret;
281
282         if (output_size && *output_size < algo->digest_size) {
283                 debug("Output buffer size %d too small (need %d bytes)",
284                       *output_size, algo->digest_size);
285                 return -ENOSPC;
286         }
287         if (output_size)
288                 *output_size = algo->digest_size;
289         algo->hash_func_ws(data, len, output, algo->chunk_size);
290
291         return 0;
292 }
293
294 #if defined(CONFIG_CMD_HASH) || defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)
295 /**
296  * store_result: Store the resulting sum to an address or variable
297  *
298  * @algo:               Hash algorithm being used
299  * @sum:                Hash digest (algo->digest_size bytes)
300  * @dest:               Destination, interpreted as a hex address if it starts
301  *                      with * (or allow_env_vars is 0) or otherwise as an
302  *                      environment variable.
303  * @allow_env_vars:     non-zero to permit storing the result to an
304  *                      variable environment
305  */
306 static void store_result(struct hash_algo *algo, const uint8_t *sum,
307                          const char *dest, int allow_env_vars)
308 {
309         unsigned int i;
310         int env_var = 0;
311
312         /*
313          * If environment variables are allowed, then we assume that 'dest'
314          * is an environment variable, unless it starts with *, in which
315          * case we assume it is an address. If not allowed, it is always an
316          * address. This is to support the crc32 command.
317          */
318         if (allow_env_vars) {
319                 if (*dest == '*')
320                         dest++;
321                 else
322                         env_var = 1;
323         }
324
325         if (env_var) {
326                 char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
327                 char *str_ptr = str_output;
328
329                 for (i = 0; i < algo->digest_size; i++) {
330                         sprintf(str_ptr, "%02x", sum[i]);
331                         str_ptr += 2;
332                 }
333                 *str_ptr = '\0';
334                 env_set(dest, str_output);
335         } else {
336                 ulong addr;
337                 void *buf;
338
339                 addr = simple_strtoul(dest, NULL, 16);
340                 buf = map_sysmem(addr, algo->digest_size);
341                 memcpy(buf, sum, algo->digest_size);
342                 unmap_sysmem(buf);
343         }
344 }
345
346 /**
347  * parse_verify_sum: Parse a hash verification parameter
348  *
349  * @algo:               Hash algorithm being used
350  * @verify_str:         Argument to parse. If it starts with * then it is
351  *                      interpreted as a hex address containing the hash.
352  *                      If the length is exactly the right number of hex digits
353  *                      for the digest size, then we assume it is a hex digest.
354  *                      Otherwise we assume it is an environment variable, and
355  *                      look up its value (it must contain a hex digest).
356  * @vsum:               Returns binary digest value (algo->digest_size bytes)
357  * @allow_env_vars:     non-zero to permit storing the result to an environment
358  *                      variable. If 0 then verify_str is assumed to be an
359  *                      address, and the * prefix is not expected.
360  * @return 0 if ok, non-zero on error
361  */
362 static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
363                             uint8_t *vsum, int allow_env_vars)
364 {
365         int env_var = 0;
366
367         /* See comment above in store_result() */
368         if (allow_env_vars) {
369                 if (*verify_str == '*')
370                         verify_str++;
371                 else
372                         env_var = 1;
373         }
374
375         if (!env_var) {
376                 ulong addr;
377                 void *buf;
378
379                 addr = simple_strtoul(verify_str, NULL, 16);
380                 buf = map_sysmem(addr, algo->digest_size);
381                 memcpy(vsum, buf, algo->digest_size);
382         } else {
383                 char *vsum_str;
384                 int digits = algo->digest_size * 2;
385
386                 /*
387                  * As with the original code from sha1sum.c, we assume that a
388                  * string which matches the digest size exactly is a hex
389                  * string and not an environment variable.
390                  */
391                 if (strlen(verify_str) == digits)
392                         vsum_str = verify_str;
393                 else {
394                         vsum_str = env_get(verify_str);
395                         if (vsum_str == NULL || strlen(vsum_str) != digits) {
396                                 printf("Expected %d hex digits in env var\n",
397                                        digits);
398                                 return 1;
399                         }
400                 }
401
402                 hash_parse_string(algo->name, vsum_str, vsum);
403         }
404         return 0;
405 }
406
407 static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
408 {
409         int i;
410
411         printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
412         for (i = 0; i < algo->digest_size; i++)
413                 printf("%02x", output[i]);
414 }
415
416 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
417                  int argc, char * const argv[])
418 {
419         ulong addr, len;
420
421         if ((argc < 2) || ((flags & HASH_FLAG_VERIFY) && (argc < 3)))
422                 return CMD_RET_USAGE;
423
424         addr = simple_strtoul(*argv++, NULL, 16);
425         len = simple_strtoul(*argv++, NULL, 16);
426
427         if (multi_hash()) {
428                 struct hash_algo *algo;
429                 u8 *output;
430                 uint8_t vsum[HASH_MAX_DIGEST_SIZE];
431                 void *buf;
432
433                 if (hash_lookup_algo(algo_name, &algo)) {
434                         printf("Unknown hash algorithm '%s'\n", algo_name);
435                         return CMD_RET_USAGE;
436                 }
437                 argc -= 2;
438
439                 if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
440                         puts("HASH_MAX_DIGEST_SIZE exceeded\n");
441                         return 1;
442                 }
443
444                 output = memalign(ARCH_DMA_MINALIGN,
445                                   sizeof(uint32_t) * HASH_MAX_DIGEST_SIZE);
446
447                 buf = map_sysmem(addr, len);
448                 algo->hash_func_ws(buf, len, output, algo->chunk_size);
449                 unmap_sysmem(buf);
450
451                 /* Try to avoid code bloat when verify is not needed */
452 #if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
453         defined(CONFIG_HASH_VERIFY)
454                 if (flags & HASH_FLAG_VERIFY) {
455 #else
456                 if (0) {
457 #endif
458                         if (parse_verify_sum(algo, *argv, vsum,
459                                         flags & HASH_FLAG_ENV)) {
460                                 printf("ERROR: %s does not contain a valid "
461                                         "%s sum\n", *argv, algo->name);
462                                 return 1;
463                         }
464                         if (memcmp(output, vsum, algo->digest_size) != 0) {
465                                 int i;
466
467                                 hash_show(algo, addr, len, output);
468                                 printf(" != ");
469                                 for (i = 0; i < algo->digest_size; i++)
470                                         printf("%02x", vsum[i]);
471                                 puts(" ** ERROR **\n");
472                                 return 1;
473                         }
474                 } else {
475                         hash_show(algo, addr, len, output);
476                         printf("\n");
477
478                         if (argc) {
479                                 store_result(algo, output, *argv,
480                                         flags & HASH_FLAG_ENV);
481                         }
482                 unmap_sysmem(output);
483
484                 }
485
486         /* Horrible code size hack for boards that just want crc32 */
487         } else {
488                 ulong crc;
489                 ulong *ptr;
490
491                 crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
492
493                 printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
494                                 addr, addr + len - 1, crc);
495
496                 if (argc >= 3) {
497                         ptr = (ulong *)simple_strtoul(argv[0], NULL, 16);
498                         *ptr = crc;
499                 }
500         }
501
502         return 0;
503 }
504 #endif /* CONFIG_CMD_HASH || CONFIG_CMD_SHA1SUM || CONFIG_CMD_CRC32) */
505 #endif /* !USE_HOSTCC */