1460408efSSimon Glass /* 2460408efSSimon Glass * Copyright (c) 2012 The Chromium OS Authors. 3460408efSSimon Glass * 4460408efSSimon Glass * (C) Copyright 2011 5460408efSSimon Glass * Joe Hershberger, National Instruments, joe.hershberger@ni.com 6460408efSSimon Glass * 7460408efSSimon Glass * (C) Copyright 2000 8460408efSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9460408efSSimon Glass * 10*1a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 11460408efSSimon Glass */ 12460408efSSimon Glass 13460408efSSimon Glass #include <common.h> 14460408efSSimon Glass #include <command.h> 151f9c9280SAkshay Saraswat #include <hw_sha.h> 16460408efSSimon Glass #include <hash.h> 17460408efSSimon Glass #include <sha1.h> 18460408efSSimon Glass #include <sha256.h> 19bd091b67SSimon Glass #include <asm/io.h> 206f907b42SSimon Glass #include <asm/errno.h> 21460408efSSimon Glass 22460408efSSimon Glass /* 23460408efSSimon Glass * These are the hash algorithms we support. Chips which support accelerated 24218da0f3SSimon Glass * crypto could perhaps add named version of these algorithms here. Note that 25218da0f3SSimon Glass * algorithm names must be in lower case. 26460408efSSimon Glass */ 27460408efSSimon Glass static struct hash_algo hash_algo[] = { 28d20a40deSSimon Glass /* 291f9c9280SAkshay Saraswat * CONFIG_SHA_HW_ACCEL is defined if hardware acceleration is 301f9c9280SAkshay Saraswat * available. 311f9c9280SAkshay Saraswat */ 321f9c9280SAkshay Saraswat #ifdef CONFIG_SHA_HW_ACCEL 331f9c9280SAkshay Saraswat { 341f9c9280SAkshay Saraswat "sha1", 351f9c9280SAkshay Saraswat SHA1_SUM_LEN, 361f9c9280SAkshay Saraswat hw_sha1, 371f9c9280SAkshay Saraswat CHUNKSZ_SHA1, 381f9c9280SAkshay Saraswat }, { 391f9c9280SAkshay Saraswat "sha256", 401f9c9280SAkshay Saraswat SHA256_SUM_LEN, 411f9c9280SAkshay Saraswat hw_sha256, 421f9c9280SAkshay Saraswat CHUNKSZ_SHA256, 431f9c9280SAkshay Saraswat }, 441f9c9280SAkshay Saraswat #endif 451f9c9280SAkshay Saraswat /* 46d20a40deSSimon Glass * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise 47d20a40deSSimon Glass * it bloats the code for boards which use SHA1 but not the 'hash' 48d20a40deSSimon Glass * or 'sha1sum' commands. 49d20a40deSSimon Glass */ 50d20a40deSSimon Glass #ifdef CONFIG_CMD_SHA1SUM 51460408efSSimon Glass { 52218da0f3SSimon Glass "sha1", 53460408efSSimon Glass SHA1_SUM_LEN, 54460408efSSimon Glass sha1_csum_wd, 55460408efSSimon Glass CHUNKSZ_SHA1, 56460408efSSimon Glass }, 57d20a40deSSimon Glass #define MULTI_HASH 58460408efSSimon Glass #endif 59460408efSSimon Glass #ifdef CONFIG_SHA256 60460408efSSimon Glass { 61218da0f3SSimon Glass "sha256", 62460408efSSimon Glass SHA256_SUM_LEN, 63460408efSSimon Glass sha256_csum_wd, 64460408efSSimon Glass CHUNKSZ_SHA256, 65460408efSSimon Glass }, 66d20a40deSSimon Glass #define MULTI_HASH 67460408efSSimon Glass #endif 68d20a40deSSimon Glass { 69218da0f3SSimon Glass "crc32", 70d20a40deSSimon Glass 4, 71d20a40deSSimon Glass crc32_wd_buf, 72d20a40deSSimon Glass CHUNKSZ_CRC32, 73d20a40deSSimon Glass }, 74460408efSSimon Glass }; 75460408efSSimon Glass 76d20a40deSSimon Glass #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH) 77d20a40deSSimon Glass #define MULTI_HASH 78d20a40deSSimon Glass #endif 79d20a40deSSimon Glass 80d20a40deSSimon Glass /* Try to minimize code size for boards that don't want much hashing */ 81d20a40deSSimon Glass #ifdef MULTI_HASH 82d20a40deSSimon Glass #define multi_hash() 1 83d20a40deSSimon Glass #else 84d20a40deSSimon Glass #define multi_hash() 0 85d20a40deSSimon Glass #endif 86d20a40deSSimon Glass 87460408efSSimon Glass /** 88460408efSSimon Glass * store_result: Store the resulting sum to an address or variable 89460408efSSimon Glass * 90460408efSSimon Glass * @algo: Hash algorithm being used 91460408efSSimon Glass * @sum: Hash digest (algo->digest_size bytes) 92460408efSSimon Glass * @dest: Destination, interpreted as a hex address if it starts 93d5b76673SSimon Glass * with * (or allow_env_vars is 0) or otherwise as an 94d5b76673SSimon Glass * environment variable. 95d5b76673SSimon Glass * @allow_env_vars: non-zero to permit storing the result to an 96d5b76673SSimon Glass * variable environment 97460408efSSimon Glass */ 98460408efSSimon Glass static void store_result(struct hash_algo *algo, const u8 *sum, 99d5b76673SSimon Glass const char *dest, int allow_env_vars) 100460408efSSimon Glass { 101460408efSSimon Glass unsigned int i; 102d5b76673SSimon Glass int env_var = 0; 103460408efSSimon Glass 104d5b76673SSimon Glass /* 105d5b76673SSimon Glass * If environment variables are allowed, then we assume that 'dest' 106d5b76673SSimon Glass * is an environment variable, unless it starts with *, in which 107d5b76673SSimon Glass * case we assume it is an address. If not allowed, it is always an 108d5b76673SSimon Glass * address. This is to support the crc32 command. 109d5b76673SSimon Glass */ 110d5b76673SSimon Glass if (allow_env_vars) { 111d5b76673SSimon Glass if (*dest == '*') 112d5b76673SSimon Glass dest++; 113d5b76673SSimon Glass else 114d5b76673SSimon Glass env_var = 1; 115d5b76673SSimon Glass } 116460408efSSimon Glass 117d5b76673SSimon Glass if (env_var) { 118460408efSSimon Glass char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; 119460408efSSimon Glass char *str_ptr = str_output; 120460408efSSimon Glass 121460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) { 122460408efSSimon Glass sprintf(str_ptr, "%02x", sum[i]); 123460408efSSimon Glass str_ptr += 2; 124460408efSSimon Glass } 125460408efSSimon Glass str_ptr = '\0'; 126460408efSSimon Glass setenv(dest, str_output); 127d5b76673SSimon Glass } else { 128bd091b67SSimon Glass ulong addr; 129bd091b67SSimon Glass void *buf; 130d5b76673SSimon Glass 131bd091b67SSimon Glass addr = simple_strtoul(dest, NULL, 16); 132bd091b67SSimon Glass buf = map_sysmem(addr, algo->digest_size); 133bd091b67SSimon Glass memcpy(buf, sum, algo->digest_size); 134bd091b67SSimon Glass unmap_sysmem(buf); 135460408efSSimon Glass } 136460408efSSimon Glass } 137460408efSSimon Glass 138460408efSSimon Glass /** 139460408efSSimon Glass * parse_verify_sum: Parse a hash verification parameter 140460408efSSimon Glass * 141460408efSSimon Glass * @algo: Hash algorithm being used 142460408efSSimon Glass * @verify_str: Argument to parse. If it starts with * then it is 143460408efSSimon Glass * interpreted as a hex address containing the hash. 144460408efSSimon Glass * If the length is exactly the right number of hex digits 145460408efSSimon Glass * for the digest size, then we assume it is a hex digest. 146460408efSSimon Glass * Otherwise we assume it is an environment variable, and 147460408efSSimon Glass * look up its value (it must contain a hex digest). 148460408efSSimon Glass * @vsum: Returns binary digest value (algo->digest_size bytes) 149d5b76673SSimon Glass * @allow_env_vars: non-zero to permit storing the result to an environment 150d5b76673SSimon Glass * variable. If 0 then verify_str is assumed to be an 151d5b76673SSimon Glass * address, and the * prefix is not expected. 152460408efSSimon Glass * @return 0 if ok, non-zero on error 153460408efSSimon Glass */ 154d5b76673SSimon Glass static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum, 155d5b76673SSimon Glass int allow_env_vars) 156460408efSSimon Glass { 157d5b76673SSimon Glass int env_var = 0; 158d5b76673SSimon Glass 159d5b76673SSimon Glass /* See comment above in store_result() */ 160d5b76673SSimon Glass if (allow_env_vars) { 161d5b76673SSimon Glass if (*verify_str == '*') 162d5b76673SSimon Glass verify_str++; 163d5b76673SSimon Glass else 164d5b76673SSimon Glass env_var = 1; 165d5b76673SSimon Glass } 166d5b76673SSimon Glass 167d5b76673SSimon Glass if (env_var) { 168bd091b67SSimon Glass ulong addr; 169bd091b67SSimon Glass void *buf; 170460408efSSimon Glass 171bd091b67SSimon Glass addr = simple_strtoul(verify_str, NULL, 16); 172bd091b67SSimon Glass buf = map_sysmem(addr, algo->digest_size); 173bd091b67SSimon Glass memcpy(vsum, buf, algo->digest_size); 174460408efSSimon Glass } else { 175460408efSSimon Glass unsigned int i; 176460408efSSimon Glass char *vsum_str; 177460408efSSimon Glass int digits = algo->digest_size * 2; 178460408efSSimon Glass 179460408efSSimon Glass /* 180460408efSSimon Glass * As with the original code from sha1sum.c, we assume that a 181460408efSSimon Glass * string which matches the digest size exactly is a hex 182460408efSSimon Glass * string and not an environment variable. 183460408efSSimon Glass */ 184460408efSSimon Glass if (strlen(verify_str) == digits) 185460408efSSimon Glass vsum_str = verify_str; 186460408efSSimon Glass else { 187460408efSSimon Glass vsum_str = getenv(verify_str); 188460408efSSimon Glass if (vsum_str == NULL || strlen(vsum_str) != digits) { 189460408efSSimon Glass printf("Expected %d hex digits in env var\n", 190460408efSSimon Glass digits); 191460408efSSimon Glass return 1; 192460408efSSimon Glass } 193460408efSSimon Glass } 194460408efSSimon Glass 195460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) { 196460408efSSimon Glass char *nullp = vsum_str + (i + 1) * 2; 197460408efSSimon Glass char end = *nullp; 198460408efSSimon Glass 199460408efSSimon Glass *nullp = '\0'; 200460408efSSimon Glass vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); 201460408efSSimon Glass *nullp = end; 202460408efSSimon Glass } 203460408efSSimon Glass } 204460408efSSimon Glass return 0; 205460408efSSimon Glass } 206460408efSSimon Glass 207460408efSSimon Glass static struct hash_algo *find_hash_algo(const char *name) 208460408efSSimon Glass { 209460408efSSimon Glass int i; 210460408efSSimon Glass 211460408efSSimon Glass for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { 212218da0f3SSimon Glass if (!strcmp(name, hash_algo[i].name)) 213460408efSSimon Glass return &hash_algo[i]; 214460408efSSimon Glass } 215460408efSSimon Glass 216460408efSSimon Glass return NULL; 217460408efSSimon Glass } 218460408efSSimon Glass 219460408efSSimon Glass static void show_hash(struct hash_algo *algo, ulong addr, ulong len, 220460408efSSimon Glass u8 *output) 221460408efSSimon Glass { 222460408efSSimon Glass int i; 223460408efSSimon Glass 224460408efSSimon Glass printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); 225460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) 226460408efSSimon Glass printf("%02x", output[i]); 227460408efSSimon Glass } 228460408efSSimon Glass 2296f907b42SSimon Glass int hash_block(const char *algo_name, const void *data, unsigned int len, 2306f907b42SSimon Glass uint8_t *output, int *output_size) 2316f907b42SSimon Glass { 2326f907b42SSimon Glass struct hash_algo *algo; 2336f907b42SSimon Glass 2346f907b42SSimon Glass algo = find_hash_algo(algo_name); 2356f907b42SSimon Glass if (!algo) { 2366f907b42SSimon Glass debug("Unknown hash algorithm '%s'\n", algo_name); 2376f907b42SSimon Glass return -EPROTONOSUPPORT; 2386f907b42SSimon Glass } 2396f907b42SSimon Glass if (output_size && *output_size < algo->digest_size) { 2406f907b42SSimon Glass debug("Output buffer size %d too small (need %d bytes)", 2416f907b42SSimon Glass *output_size, algo->digest_size); 2426f907b42SSimon Glass return -ENOSPC; 2436f907b42SSimon Glass } 2446f907b42SSimon Glass if (output_size) 2456f907b42SSimon Glass *output_size = algo->digest_size; 2466f907b42SSimon Glass algo->hash_func_ws(data, len, output, algo->chunk_size); 2476f907b42SSimon Glass 2486f907b42SSimon Glass return 0; 2496f907b42SSimon Glass } 2506f907b42SSimon Glass 251d5b76673SSimon Glass int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag, 252460408efSSimon Glass int argc, char * const argv[]) 253460408efSSimon Glass { 254460408efSSimon Glass ulong addr, len; 255460408efSSimon Glass 256460408efSSimon Glass if (argc < 2) 257460408efSSimon Glass return CMD_RET_USAGE; 258460408efSSimon Glass 259d5b76673SSimon Glass addr = simple_strtoul(*argv++, NULL, 16); 260d5b76673SSimon Glass len = simple_strtoul(*argv++, NULL, 16); 261d5b76673SSimon Glass 262d20a40deSSimon Glass if (multi_hash()) { 263d20a40deSSimon Glass struct hash_algo *algo; 264d20a40deSSimon Glass u8 output[HASH_MAX_DIGEST_SIZE]; 265d20a40deSSimon Glass u8 vsum[HASH_MAX_DIGEST_SIZE]; 266bd091b67SSimon Glass void *buf; 267d20a40deSSimon Glass 268460408efSSimon Glass algo = find_hash_algo(algo_name); 269460408efSSimon Glass if (!algo) { 270460408efSSimon Glass printf("Unknown hash algorithm '%s'\n", algo_name); 271460408efSSimon Glass return CMD_RET_USAGE; 272460408efSSimon Glass } 273460408efSSimon Glass argc -= 2; 274460408efSSimon Glass 275460408efSSimon Glass if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { 276460408efSSimon Glass puts("HASH_MAX_DIGEST_SIZE exceeded\n"); 277460408efSSimon Glass return 1; 278460408efSSimon Glass } 279460408efSSimon Glass 280bd091b67SSimon Glass buf = map_sysmem(addr, len); 281bd091b67SSimon Glass algo->hash_func_ws(buf, len, output, algo->chunk_size); 282bd091b67SSimon Glass unmap_sysmem(buf); 283460408efSSimon Glass 284460408efSSimon Glass /* Try to avoid code bloat when verify is not needed */ 285460408efSSimon Glass #ifdef CONFIG_HASH_VERIFY 286d5b76673SSimon Glass if (flags & HASH_FLAG_VERIFY) { 287460408efSSimon Glass #else 288460408efSSimon Glass if (0) { 289460408efSSimon Glass #endif 290460408efSSimon Glass if (!argc) 291460408efSSimon Glass return CMD_RET_USAGE; 292d5b76673SSimon Glass if (parse_verify_sum(algo, *argv, vsum, 293d5b76673SSimon Glass flags & HASH_FLAG_ENV)) { 294d20a40deSSimon Glass printf("ERROR: %s does not contain a valid " 295d20a40deSSimon Glass "%s sum\n", *argv, algo->name); 296460408efSSimon Glass return 1; 297460408efSSimon Glass } 298460408efSSimon Glass if (memcmp(output, vsum, algo->digest_size) != 0) { 299460408efSSimon Glass int i; 300460408efSSimon Glass 301460408efSSimon Glass show_hash(algo, addr, len, output); 302460408efSSimon Glass printf(" != "); 303460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) 304460408efSSimon Glass printf("%02x", vsum[i]); 305460408efSSimon Glass puts(" ** ERROR **\n"); 306460408efSSimon Glass return 1; 307460408efSSimon Glass } 308460408efSSimon Glass } else { 309460408efSSimon Glass show_hash(algo, addr, len, output); 310460408efSSimon Glass printf("\n"); 311460408efSSimon Glass 312d5b76673SSimon Glass if (argc) { 313d5b76673SSimon Glass store_result(algo, output, *argv, 314d5b76673SSimon Glass flags & HASH_FLAG_ENV); 315d5b76673SSimon Glass } 316460408efSSimon Glass } 317460408efSSimon Glass 318d20a40deSSimon Glass /* Horrible code size hack for boards that just want crc32 */ 319d20a40deSSimon Glass } else { 320d20a40deSSimon Glass ulong crc; 321d20a40deSSimon Glass ulong *ptr; 322d20a40deSSimon Glass 323d20a40deSSimon Glass crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32); 324d20a40deSSimon Glass 325d20a40deSSimon Glass printf("CRC32 for %08lx ... %08lx ==> %08lx\n", 326d20a40deSSimon Glass addr, addr + len - 1, crc); 327d20a40deSSimon Glass 328d20a40deSSimon Glass if (argc > 3) { 329d20a40deSSimon Glass ptr = (ulong *)simple_strtoul(argv[3], NULL, 16); 330d20a40deSSimon Glass *ptr = crc; 331d20a40deSSimon Glass } 332d20a40deSSimon Glass } 333d20a40deSSimon Glass 334460408efSSimon Glass return 0; 335460408efSSimon Glass } 336