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 * 10460408efSSimon Glass * This program is free software; you can redistribute it and/or 11460408efSSimon Glass * modify it under the terms of the GNU General Public License as 12460408efSSimon Glass * published by the Free Software Foundation; either version 2 of 13460408efSSimon Glass * the License, or (at your option) any later version. 14460408efSSimon Glass * 15460408efSSimon Glass * This program is distributed in the hope that it will be useful, 16460408efSSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 17460408efSSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18460408efSSimon Glass * GNU General Public License for more details. 19460408efSSimon Glass * 20460408efSSimon Glass * You should have received a copy of the GNU General Public License 21460408efSSimon Glass * along with this program; if not, write to the Free Software 22460408efSSimon Glass * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23460408efSSimon Glass * MA 02111-1307 USA 24460408efSSimon Glass */ 25460408efSSimon Glass 26460408efSSimon Glass #include <common.h> 27460408efSSimon Glass #include <command.h> 281f9c9280SAkshay Saraswat #include <hw_sha.h> 29460408efSSimon Glass #include <hash.h> 30460408efSSimon Glass #include <sha1.h> 31460408efSSimon Glass #include <sha256.h> 32bd091b67SSimon Glass #include <asm/io.h> 33*6f907b42SSimon Glass #include <asm/errno.h> 34460408efSSimon Glass 35460408efSSimon Glass /* 36460408efSSimon Glass * These are the hash algorithms we support. Chips which support accelerated 37218da0f3SSimon Glass * crypto could perhaps add named version of these algorithms here. Note that 38218da0f3SSimon Glass * algorithm names must be in lower case. 39460408efSSimon Glass */ 40460408efSSimon Glass static struct hash_algo hash_algo[] = { 41d20a40deSSimon Glass /* 421f9c9280SAkshay Saraswat * CONFIG_SHA_HW_ACCEL is defined if hardware acceleration is 431f9c9280SAkshay Saraswat * available. 441f9c9280SAkshay Saraswat */ 451f9c9280SAkshay Saraswat #ifdef CONFIG_SHA_HW_ACCEL 461f9c9280SAkshay Saraswat { 471f9c9280SAkshay Saraswat "sha1", 481f9c9280SAkshay Saraswat SHA1_SUM_LEN, 491f9c9280SAkshay Saraswat hw_sha1, 501f9c9280SAkshay Saraswat CHUNKSZ_SHA1, 511f9c9280SAkshay Saraswat }, { 521f9c9280SAkshay Saraswat "sha256", 531f9c9280SAkshay Saraswat SHA256_SUM_LEN, 541f9c9280SAkshay Saraswat hw_sha256, 551f9c9280SAkshay Saraswat CHUNKSZ_SHA256, 561f9c9280SAkshay Saraswat }, 571f9c9280SAkshay Saraswat #endif 581f9c9280SAkshay Saraswat /* 59d20a40deSSimon Glass * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise 60d20a40deSSimon Glass * it bloats the code for boards which use SHA1 but not the 'hash' 61d20a40deSSimon Glass * or 'sha1sum' commands. 62d20a40deSSimon Glass */ 63d20a40deSSimon Glass #ifdef CONFIG_CMD_SHA1SUM 64460408efSSimon Glass { 65218da0f3SSimon Glass "sha1", 66460408efSSimon Glass SHA1_SUM_LEN, 67460408efSSimon Glass sha1_csum_wd, 68460408efSSimon Glass CHUNKSZ_SHA1, 69460408efSSimon Glass }, 70d20a40deSSimon Glass #define MULTI_HASH 71460408efSSimon Glass #endif 72460408efSSimon Glass #ifdef CONFIG_SHA256 73460408efSSimon Glass { 74218da0f3SSimon Glass "sha256", 75460408efSSimon Glass SHA256_SUM_LEN, 76460408efSSimon Glass sha256_csum_wd, 77460408efSSimon Glass CHUNKSZ_SHA256, 78460408efSSimon Glass }, 79d20a40deSSimon Glass #define MULTI_HASH 80460408efSSimon Glass #endif 81d20a40deSSimon Glass { 82218da0f3SSimon Glass "crc32", 83d20a40deSSimon Glass 4, 84d20a40deSSimon Glass crc32_wd_buf, 85d20a40deSSimon Glass CHUNKSZ_CRC32, 86d20a40deSSimon Glass }, 87460408efSSimon Glass }; 88460408efSSimon Glass 89d20a40deSSimon Glass #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH) 90d20a40deSSimon Glass #define MULTI_HASH 91d20a40deSSimon Glass #endif 92d20a40deSSimon Glass 93d20a40deSSimon Glass /* Try to minimize code size for boards that don't want much hashing */ 94d20a40deSSimon Glass #ifdef MULTI_HASH 95d20a40deSSimon Glass #define multi_hash() 1 96d20a40deSSimon Glass #else 97d20a40deSSimon Glass #define multi_hash() 0 98d20a40deSSimon Glass #endif 99d20a40deSSimon Glass 100460408efSSimon Glass /** 101460408efSSimon Glass * store_result: Store the resulting sum to an address or variable 102460408efSSimon Glass * 103460408efSSimon Glass * @algo: Hash algorithm being used 104460408efSSimon Glass * @sum: Hash digest (algo->digest_size bytes) 105460408efSSimon Glass * @dest: Destination, interpreted as a hex address if it starts 106d5b76673SSimon Glass * with * (or allow_env_vars is 0) or otherwise as an 107d5b76673SSimon Glass * environment variable. 108d5b76673SSimon Glass * @allow_env_vars: non-zero to permit storing the result to an 109d5b76673SSimon Glass * variable environment 110460408efSSimon Glass */ 111460408efSSimon Glass static void store_result(struct hash_algo *algo, const u8 *sum, 112d5b76673SSimon Glass const char *dest, int allow_env_vars) 113460408efSSimon Glass { 114460408efSSimon Glass unsigned int i; 115d5b76673SSimon Glass int env_var = 0; 116460408efSSimon Glass 117d5b76673SSimon Glass /* 118d5b76673SSimon Glass * If environment variables are allowed, then we assume that 'dest' 119d5b76673SSimon Glass * is an environment variable, unless it starts with *, in which 120d5b76673SSimon Glass * case we assume it is an address. If not allowed, it is always an 121d5b76673SSimon Glass * address. This is to support the crc32 command. 122d5b76673SSimon Glass */ 123d5b76673SSimon Glass if (allow_env_vars) { 124d5b76673SSimon Glass if (*dest == '*') 125d5b76673SSimon Glass dest++; 126d5b76673SSimon Glass else 127d5b76673SSimon Glass env_var = 1; 128d5b76673SSimon Glass } 129460408efSSimon Glass 130d5b76673SSimon Glass if (env_var) { 131460408efSSimon Glass char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; 132460408efSSimon Glass char *str_ptr = str_output; 133460408efSSimon Glass 134460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) { 135460408efSSimon Glass sprintf(str_ptr, "%02x", sum[i]); 136460408efSSimon Glass str_ptr += 2; 137460408efSSimon Glass } 138460408efSSimon Glass str_ptr = '\0'; 139460408efSSimon Glass setenv(dest, str_output); 140d5b76673SSimon Glass } else { 141bd091b67SSimon Glass ulong addr; 142bd091b67SSimon Glass void *buf; 143d5b76673SSimon Glass 144bd091b67SSimon Glass addr = simple_strtoul(dest, NULL, 16); 145bd091b67SSimon Glass buf = map_sysmem(addr, algo->digest_size); 146bd091b67SSimon Glass memcpy(buf, sum, algo->digest_size); 147bd091b67SSimon Glass unmap_sysmem(buf); 148460408efSSimon Glass } 149460408efSSimon Glass } 150460408efSSimon Glass 151460408efSSimon Glass /** 152460408efSSimon Glass * parse_verify_sum: Parse a hash verification parameter 153460408efSSimon Glass * 154460408efSSimon Glass * @algo: Hash algorithm being used 155460408efSSimon Glass * @verify_str: Argument to parse. If it starts with * then it is 156460408efSSimon Glass * interpreted as a hex address containing the hash. 157460408efSSimon Glass * If the length is exactly the right number of hex digits 158460408efSSimon Glass * for the digest size, then we assume it is a hex digest. 159460408efSSimon Glass * Otherwise we assume it is an environment variable, and 160460408efSSimon Glass * look up its value (it must contain a hex digest). 161460408efSSimon Glass * @vsum: Returns binary digest value (algo->digest_size bytes) 162d5b76673SSimon Glass * @allow_env_vars: non-zero to permit storing the result to an environment 163d5b76673SSimon Glass * variable. If 0 then verify_str is assumed to be an 164d5b76673SSimon Glass * address, and the * prefix is not expected. 165460408efSSimon Glass * @return 0 if ok, non-zero on error 166460408efSSimon Glass */ 167d5b76673SSimon Glass static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum, 168d5b76673SSimon Glass int allow_env_vars) 169460408efSSimon Glass { 170d5b76673SSimon Glass int env_var = 0; 171d5b76673SSimon Glass 172d5b76673SSimon Glass /* See comment above in store_result() */ 173d5b76673SSimon Glass if (allow_env_vars) { 174d5b76673SSimon Glass if (*verify_str == '*') 175d5b76673SSimon Glass verify_str++; 176d5b76673SSimon Glass else 177d5b76673SSimon Glass env_var = 1; 178d5b76673SSimon Glass } 179d5b76673SSimon Glass 180d5b76673SSimon Glass if (env_var) { 181bd091b67SSimon Glass ulong addr; 182bd091b67SSimon Glass void *buf; 183460408efSSimon Glass 184bd091b67SSimon Glass addr = simple_strtoul(verify_str, NULL, 16); 185bd091b67SSimon Glass buf = map_sysmem(addr, algo->digest_size); 186bd091b67SSimon Glass memcpy(vsum, buf, algo->digest_size); 187460408efSSimon Glass } else { 188460408efSSimon Glass unsigned int i; 189460408efSSimon Glass char *vsum_str; 190460408efSSimon Glass int digits = algo->digest_size * 2; 191460408efSSimon Glass 192460408efSSimon Glass /* 193460408efSSimon Glass * As with the original code from sha1sum.c, we assume that a 194460408efSSimon Glass * string which matches the digest size exactly is a hex 195460408efSSimon Glass * string and not an environment variable. 196460408efSSimon Glass */ 197460408efSSimon Glass if (strlen(verify_str) == digits) 198460408efSSimon Glass vsum_str = verify_str; 199460408efSSimon Glass else { 200460408efSSimon Glass vsum_str = getenv(verify_str); 201460408efSSimon Glass if (vsum_str == NULL || strlen(vsum_str) != digits) { 202460408efSSimon Glass printf("Expected %d hex digits in env var\n", 203460408efSSimon Glass digits); 204460408efSSimon Glass return 1; 205460408efSSimon Glass } 206460408efSSimon Glass } 207460408efSSimon Glass 208460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) { 209460408efSSimon Glass char *nullp = vsum_str + (i + 1) * 2; 210460408efSSimon Glass char end = *nullp; 211460408efSSimon Glass 212460408efSSimon Glass *nullp = '\0'; 213460408efSSimon Glass vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); 214460408efSSimon Glass *nullp = end; 215460408efSSimon Glass } 216460408efSSimon Glass } 217460408efSSimon Glass return 0; 218460408efSSimon Glass } 219460408efSSimon Glass 220460408efSSimon Glass static struct hash_algo *find_hash_algo(const char *name) 221460408efSSimon Glass { 222460408efSSimon Glass int i; 223460408efSSimon Glass 224460408efSSimon Glass for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { 225218da0f3SSimon Glass if (!strcmp(name, hash_algo[i].name)) 226460408efSSimon Glass return &hash_algo[i]; 227460408efSSimon Glass } 228460408efSSimon Glass 229460408efSSimon Glass return NULL; 230460408efSSimon Glass } 231460408efSSimon Glass 232460408efSSimon Glass static void show_hash(struct hash_algo *algo, ulong addr, ulong len, 233460408efSSimon Glass u8 *output) 234460408efSSimon Glass { 235460408efSSimon Glass int i; 236460408efSSimon Glass 237460408efSSimon Glass printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); 238460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) 239460408efSSimon Glass printf("%02x", output[i]); 240460408efSSimon Glass } 241460408efSSimon Glass 242*6f907b42SSimon Glass int hash_block(const char *algo_name, const void *data, unsigned int len, 243*6f907b42SSimon Glass uint8_t *output, int *output_size) 244*6f907b42SSimon Glass { 245*6f907b42SSimon Glass struct hash_algo *algo; 246*6f907b42SSimon Glass 247*6f907b42SSimon Glass algo = find_hash_algo(algo_name); 248*6f907b42SSimon Glass if (!algo) { 249*6f907b42SSimon Glass debug("Unknown hash algorithm '%s'\n", algo_name); 250*6f907b42SSimon Glass return -EPROTONOSUPPORT; 251*6f907b42SSimon Glass } 252*6f907b42SSimon Glass if (output_size && *output_size < algo->digest_size) { 253*6f907b42SSimon Glass debug("Output buffer size %d too small (need %d bytes)", 254*6f907b42SSimon Glass *output_size, algo->digest_size); 255*6f907b42SSimon Glass return -ENOSPC; 256*6f907b42SSimon Glass } 257*6f907b42SSimon Glass if (output_size) 258*6f907b42SSimon Glass *output_size = algo->digest_size; 259*6f907b42SSimon Glass algo->hash_func_ws(data, len, output, algo->chunk_size); 260*6f907b42SSimon Glass 261*6f907b42SSimon Glass return 0; 262*6f907b42SSimon Glass } 263*6f907b42SSimon Glass 264d5b76673SSimon Glass int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag, 265460408efSSimon Glass int argc, char * const argv[]) 266460408efSSimon Glass { 267460408efSSimon Glass ulong addr, len; 268460408efSSimon Glass 269460408efSSimon Glass if (argc < 2) 270460408efSSimon Glass return CMD_RET_USAGE; 271460408efSSimon Glass 272d5b76673SSimon Glass addr = simple_strtoul(*argv++, NULL, 16); 273d5b76673SSimon Glass len = simple_strtoul(*argv++, NULL, 16); 274d5b76673SSimon Glass 275d20a40deSSimon Glass if (multi_hash()) { 276d20a40deSSimon Glass struct hash_algo *algo; 277d20a40deSSimon Glass u8 output[HASH_MAX_DIGEST_SIZE]; 278d20a40deSSimon Glass u8 vsum[HASH_MAX_DIGEST_SIZE]; 279bd091b67SSimon Glass void *buf; 280d20a40deSSimon Glass 281460408efSSimon Glass algo = find_hash_algo(algo_name); 282460408efSSimon Glass if (!algo) { 283460408efSSimon Glass printf("Unknown hash algorithm '%s'\n", algo_name); 284460408efSSimon Glass return CMD_RET_USAGE; 285460408efSSimon Glass } 286460408efSSimon Glass argc -= 2; 287460408efSSimon Glass 288460408efSSimon Glass if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { 289460408efSSimon Glass puts("HASH_MAX_DIGEST_SIZE exceeded\n"); 290460408efSSimon Glass return 1; 291460408efSSimon Glass } 292460408efSSimon Glass 293bd091b67SSimon Glass buf = map_sysmem(addr, len); 294bd091b67SSimon Glass algo->hash_func_ws(buf, len, output, algo->chunk_size); 295bd091b67SSimon Glass unmap_sysmem(buf); 296460408efSSimon Glass 297460408efSSimon Glass /* Try to avoid code bloat when verify is not needed */ 298460408efSSimon Glass #ifdef CONFIG_HASH_VERIFY 299d5b76673SSimon Glass if (flags & HASH_FLAG_VERIFY) { 300460408efSSimon Glass #else 301460408efSSimon Glass if (0) { 302460408efSSimon Glass #endif 303460408efSSimon Glass if (!argc) 304460408efSSimon Glass return CMD_RET_USAGE; 305d5b76673SSimon Glass if (parse_verify_sum(algo, *argv, vsum, 306d5b76673SSimon Glass flags & HASH_FLAG_ENV)) { 307d20a40deSSimon Glass printf("ERROR: %s does not contain a valid " 308d20a40deSSimon Glass "%s sum\n", *argv, algo->name); 309460408efSSimon Glass return 1; 310460408efSSimon Glass } 311460408efSSimon Glass if (memcmp(output, vsum, algo->digest_size) != 0) { 312460408efSSimon Glass int i; 313460408efSSimon Glass 314460408efSSimon Glass show_hash(algo, addr, len, output); 315460408efSSimon Glass printf(" != "); 316460408efSSimon Glass for (i = 0; i < algo->digest_size; i++) 317460408efSSimon Glass printf("%02x", vsum[i]); 318460408efSSimon Glass puts(" ** ERROR **\n"); 319460408efSSimon Glass return 1; 320460408efSSimon Glass } 321460408efSSimon Glass } else { 322460408efSSimon Glass show_hash(algo, addr, len, output); 323460408efSSimon Glass printf("\n"); 324460408efSSimon Glass 325d5b76673SSimon Glass if (argc) { 326d5b76673SSimon Glass store_result(algo, output, *argv, 327d5b76673SSimon Glass flags & HASH_FLAG_ENV); 328d5b76673SSimon Glass } 329460408efSSimon Glass } 330460408efSSimon Glass 331d20a40deSSimon Glass /* Horrible code size hack for boards that just want crc32 */ 332d20a40deSSimon Glass } else { 333d20a40deSSimon Glass ulong crc; 334d20a40deSSimon Glass ulong *ptr; 335d20a40deSSimon Glass 336d20a40deSSimon Glass crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32); 337d20a40deSSimon Glass 338d20a40deSSimon Glass printf("CRC32 for %08lx ... %08lx ==> %08lx\n", 339d20a40deSSimon Glass addr, addr + len - 1, crc); 340d20a40deSSimon Glass 341d20a40deSSimon Glass if (argc > 3) { 342d20a40deSSimon Glass ptr = (ulong *)simple_strtoul(argv[3], NULL, 16); 343d20a40deSSimon Glass *ptr = crc; 344d20a40deSSimon Glass } 345d20a40deSSimon Glass } 346d20a40deSSimon Glass 347460408efSSimon Glass return 0; 348460408efSSimon Glass } 349