1 /* 2 * Copyright (c) 2012 The Chromium OS Authors. 3 * 4 * (C) Copyright 2011 5 * Joe Hershberger, National Instruments, joe.hershberger@ni.com 6 * 7 * (C) Copyright 2000 8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 13 #include <common.h> 14 #include <command.h> 15 #include <hw_sha.h> 16 #include <hash.h> 17 #include <sha1.h> 18 #include <sha256.h> 19 #include <asm/io.h> 20 #include <asm/errno.h> 21 22 /* 23 * These are the hash algorithms we support. Chips which support accelerated 24 * crypto could perhaps add named version of these algorithms here. Note that 25 * algorithm names must be in lower case. 26 */ 27 static struct hash_algo hash_algo[] = { 28 /* 29 * CONFIG_SHA_HW_ACCEL is defined if hardware acceleration is 30 * available. 31 */ 32 #ifdef CONFIG_SHA_HW_ACCEL 33 { 34 "sha1", 35 SHA1_SUM_LEN, 36 hw_sha1, 37 CHUNKSZ_SHA1, 38 }, { 39 "sha256", 40 SHA256_SUM_LEN, 41 hw_sha256, 42 CHUNKSZ_SHA256, 43 }, 44 #endif 45 /* 46 * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise 47 * it bloats the code for boards which use SHA1 but not the 'hash' 48 * or 'sha1sum' commands. 49 */ 50 #ifdef CONFIG_CMD_SHA1SUM 51 { 52 "sha1", 53 SHA1_SUM_LEN, 54 sha1_csum_wd, 55 CHUNKSZ_SHA1, 56 }, 57 #define MULTI_HASH 58 #endif 59 #ifdef CONFIG_SHA256 60 { 61 "sha256", 62 SHA256_SUM_LEN, 63 sha256_csum_wd, 64 CHUNKSZ_SHA256, 65 }, 66 #define MULTI_HASH 67 #endif 68 { 69 "crc32", 70 4, 71 crc32_wd_buf, 72 CHUNKSZ_CRC32, 73 }, 74 }; 75 76 #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH) 77 #define MULTI_HASH 78 #endif 79 80 /* Try to minimize code size for boards that don't want much hashing */ 81 #ifdef MULTI_HASH 82 #define multi_hash() 1 83 #else 84 #define multi_hash() 0 85 #endif 86 87 /** 88 * store_result: Store the resulting sum to an address or variable 89 * 90 * @algo: Hash algorithm being used 91 * @sum: Hash digest (algo->digest_size bytes) 92 * @dest: Destination, interpreted as a hex address if it starts 93 * with * (or allow_env_vars is 0) or otherwise as an 94 * environment variable. 95 * @allow_env_vars: non-zero to permit storing the result to an 96 * variable environment 97 */ 98 static void store_result(struct hash_algo *algo, const u8 *sum, 99 const char *dest, int allow_env_vars) 100 { 101 unsigned int i; 102 int env_var = 0; 103 104 /* 105 * If environment variables are allowed, then we assume that 'dest' 106 * is an environment variable, unless it starts with *, in which 107 * case we assume it is an address. If not allowed, it is always an 108 * address. This is to support the crc32 command. 109 */ 110 if (allow_env_vars) { 111 if (*dest == '*') 112 dest++; 113 else 114 env_var = 1; 115 } 116 117 if (env_var) { 118 char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; 119 char *str_ptr = str_output; 120 121 for (i = 0; i < algo->digest_size; i++) { 122 sprintf(str_ptr, "%02x", sum[i]); 123 str_ptr += 2; 124 } 125 str_ptr = '\0'; 126 setenv(dest, str_output); 127 } else { 128 ulong addr; 129 void *buf; 130 131 addr = simple_strtoul(dest, NULL, 16); 132 buf = map_sysmem(addr, algo->digest_size); 133 memcpy(buf, sum, algo->digest_size); 134 unmap_sysmem(buf); 135 } 136 } 137 138 /** 139 * parse_verify_sum: Parse a hash verification parameter 140 * 141 * @algo: Hash algorithm being used 142 * @verify_str: Argument to parse. If it starts with * then it is 143 * interpreted as a hex address containing the hash. 144 * If the length is exactly the right number of hex digits 145 * for the digest size, then we assume it is a hex digest. 146 * Otherwise we assume it is an environment variable, and 147 * look up its value (it must contain a hex digest). 148 * @vsum: Returns binary digest value (algo->digest_size bytes) 149 * @allow_env_vars: non-zero to permit storing the result to an environment 150 * variable. If 0 then verify_str is assumed to be an 151 * address, and the * prefix is not expected. 152 * @return 0 if ok, non-zero on error 153 */ 154 static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum, 155 int allow_env_vars) 156 { 157 int env_var = 0; 158 159 /* See comment above in store_result() */ 160 if (allow_env_vars) { 161 if (*verify_str == '*') 162 verify_str++; 163 else 164 env_var = 1; 165 } 166 167 if (env_var) { 168 ulong addr; 169 void *buf; 170 171 addr = simple_strtoul(verify_str, NULL, 16); 172 buf = map_sysmem(addr, algo->digest_size); 173 memcpy(vsum, buf, algo->digest_size); 174 } else { 175 unsigned int i; 176 char *vsum_str; 177 int digits = algo->digest_size * 2; 178 179 /* 180 * As with the original code from sha1sum.c, we assume that a 181 * string which matches the digest size exactly is a hex 182 * string and not an environment variable. 183 */ 184 if (strlen(verify_str) == digits) 185 vsum_str = verify_str; 186 else { 187 vsum_str = getenv(verify_str); 188 if (vsum_str == NULL || strlen(vsum_str) != digits) { 189 printf("Expected %d hex digits in env var\n", 190 digits); 191 return 1; 192 } 193 } 194 195 for (i = 0; i < algo->digest_size; i++) { 196 char *nullp = vsum_str + (i + 1) * 2; 197 char end = *nullp; 198 199 *nullp = '\0'; 200 vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); 201 *nullp = end; 202 } 203 } 204 return 0; 205 } 206 207 static struct hash_algo *find_hash_algo(const char *name) 208 { 209 int i; 210 211 for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { 212 if (!strcmp(name, hash_algo[i].name)) 213 return &hash_algo[i]; 214 } 215 216 return NULL; 217 } 218 219 static void show_hash(struct hash_algo *algo, ulong addr, ulong len, 220 u8 *output) 221 { 222 int i; 223 224 printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); 225 for (i = 0; i < algo->digest_size; i++) 226 printf("%02x", output[i]); 227 } 228 229 int hash_block(const char *algo_name, const void *data, unsigned int len, 230 uint8_t *output, int *output_size) 231 { 232 struct hash_algo *algo; 233 234 algo = find_hash_algo(algo_name); 235 if (!algo) { 236 debug("Unknown hash algorithm '%s'\n", algo_name); 237 return -EPROTONOSUPPORT; 238 } 239 if (output_size && *output_size < algo->digest_size) { 240 debug("Output buffer size %d too small (need %d bytes)", 241 *output_size, algo->digest_size); 242 return -ENOSPC; 243 } 244 if (output_size) 245 *output_size = algo->digest_size; 246 algo->hash_func_ws(data, len, output, algo->chunk_size); 247 248 return 0; 249 } 250 251 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag, 252 int argc, char * const argv[]) 253 { 254 ulong addr, len; 255 256 if (argc < 2) 257 return CMD_RET_USAGE; 258 259 addr = simple_strtoul(*argv++, NULL, 16); 260 len = simple_strtoul(*argv++, NULL, 16); 261 262 if (multi_hash()) { 263 struct hash_algo *algo; 264 u8 output[HASH_MAX_DIGEST_SIZE]; 265 u8 vsum[HASH_MAX_DIGEST_SIZE]; 266 void *buf; 267 268 algo = find_hash_algo(algo_name); 269 if (!algo) { 270 printf("Unknown hash algorithm '%s'\n", algo_name); 271 return CMD_RET_USAGE; 272 } 273 argc -= 2; 274 275 if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { 276 puts("HASH_MAX_DIGEST_SIZE exceeded\n"); 277 return 1; 278 } 279 280 buf = map_sysmem(addr, len); 281 algo->hash_func_ws(buf, len, output, algo->chunk_size); 282 unmap_sysmem(buf); 283 284 /* Try to avoid code bloat when verify is not needed */ 285 #ifdef CONFIG_HASH_VERIFY 286 if (flags & HASH_FLAG_VERIFY) { 287 #else 288 if (0) { 289 #endif 290 if (!argc) 291 return CMD_RET_USAGE; 292 if (parse_verify_sum(algo, *argv, vsum, 293 flags & HASH_FLAG_ENV)) { 294 printf("ERROR: %s does not contain a valid " 295 "%s sum\n", *argv, algo->name); 296 return 1; 297 } 298 if (memcmp(output, vsum, algo->digest_size) != 0) { 299 int i; 300 301 show_hash(algo, addr, len, output); 302 printf(" != "); 303 for (i = 0; i < algo->digest_size; i++) 304 printf("%02x", vsum[i]); 305 puts(" ** ERROR **\n"); 306 return 1; 307 } 308 } else { 309 show_hash(algo, addr, len, output); 310 printf("\n"); 311 312 if (argc) { 313 store_result(algo, output, *argv, 314 flags & HASH_FLAG_ENV); 315 } 316 } 317 318 /* Horrible code size hack for boards that just want crc32 */ 319 } else { 320 ulong crc; 321 ulong *ptr; 322 323 crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32); 324 325 printf("CRC32 for %08lx ... %08lx ==> %08lx\n", 326 addr, addr + len - 1, crc); 327 328 if (argc > 3) { 329 ptr = (ulong *)simple_strtoul(argv[3], NULL, 16); 330 *ptr = crc; 331 } 332 } 333 334 return 0; 335 } 336