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