[U-Boot] [PATCH v2 10/23] Add generic hash API
Joe Hershberger
joe.hershberger at gmail.com
Sat Dec 1 20:35:34 CET 2012
Hi Simon,
On Thu, Nov 22, 2012 at 1:12 PM, Simon Glass <sjg at chromium.org> wrote:
> We have a SHA1 command and want to add a SHA256 command also. Instead of
> duplicating the code, create a generic hash API which can process
> commands for different algorithms.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> Changes in v2:
> - Add generic hash API to allow SHA256 command to be added without duplication
>
> common/Makefile | 1 +
> common/hash.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/hash.h | 69 +++++++++++++++++
> 3 files changed, 291 insertions(+), 0 deletions(-)
> create mode 100644 common/hash.c
> create mode 100644 include/hash.h
>
> diff --git a/common/Makefile b/common/Makefile
> index 84968f8..eb175c1 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -31,6 +31,7 @@ COBJS-y += main.o
> COBJS-y += command.o
> COBJS-y += exports.o
> COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o
> +COBJS-y += hash.o
Why not put them in alphabetical order?
> COBJS-y += s_record.o
> COBJS-y += xyzModem.o
> COBJS-y += cmd_disk.o
> diff --git a/common/hash.c b/common/hash.c
> new file mode 100644
> index 0000000..9a844b8
> --- /dev/null
> +++ b/common/hash.c
> @@ -0,0 +1,221 @@
> +/*
> + * Copyright (c) 2012 The Chromium OS Authors.
> + *
> + * (C) Copyright 2011
> + * Joe Hershberger, National Instruments, joe.hershberger at ni.com
> + *
> + * (C) Copyright 2000
> + * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <hash.h>
> +#include <sha1.h>
> +#include <sha256.h>
> +
> +/*
> + * These are the hash algorithms we support. Chips which support accelerated
> + * crypto could perhaps add named version of these algorithms here.
> + */
> +static struct hash_algo hash_algo[] = {
> +#ifdef CONFIG_SHA1
> + {
> + "SHA1",
> + SHA1_SUM_LEN,
> + sha1_csum_wd,
> + CHUNKSZ_SHA1,
> + },
> +#endif
> +#ifdef CONFIG_SHA256
> + {
> + "SHA256",
> + SHA256_SUM_LEN,
> + sha256_csum_wd,
> + CHUNKSZ_SHA256,
> + },
> +#endif
> +};
> +
> +/**
> + * store_result: Store the resulting sum to an address or variable
> + *
> + * @algo: Hash algorithm being used
> + * @sum: Hash digest (algo->digest_size bytes)
> + * @dest: Destination, interpreted as a hex address if it starts
> + * with * or otherwise as an environment variable.
> + */
> +static void store_result(struct hash_algo *algo, const u8 *sum,
> + const char *dest)
> +{
> + unsigned int i;
> +
> + if (*dest == '*') {
> + u8 *ptr;
> +
> + ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16);
> + memcpy(ptr, sum, algo->digest_size);
> + } else {
> + char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
> + char *str_ptr = str_output;
> +
> + for (i = 0; i < algo->digest_size; i++) {
> + sprintf(str_ptr, "%02x", sum[i]);
> + str_ptr += 2;
> + }
> + str_ptr = '\0';
> + setenv(dest, str_output);
> + }
> +}
> +
> +/**
> + * parse_verify_sum: Parse a hash verification parameter
> + *
> + * @algo: Hash algorithm being used
> + * @verify_str: Argument to parse. If it starts with * then it is
> + * interpreted as a hex address containing the hash.
> + * If the length is exactly the right number of hex digits
> + * for the digest size, then we assume it is a hex digest.
> + * Otherwise we assume it is an environment variable, and
> + * look up its value (it must contain a hex digest).
> + * @vsum: Returns binary digest value (algo->digest_size bytes)
> + * @return 0 if ok, non-zero on error
> + */
> +static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum)
> +{
> + if (*verify_str == '*') {
> + u8 *ptr;
> +
> + ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16);
> + memcpy(vsum, ptr, algo->digest_size);
> + } else {
> + unsigned int i;
> + char *vsum_str;
> + int digits = algo->digest_size * 2;
> +
> + /*
> + * As with the original code from sha1sum.c, we assume that a
> + * string which matches the digest size exactly is a hex
> + * string and not an environment variable.
> + */
> + if (strlen(verify_str) == digits)
> + vsum_str = verify_str;
> + else {
> + vsum_str = getenv(verify_str);
> + if (vsum_str == NULL || strlen(vsum_str) != digits) {
> + printf("Expected %d hex digits in env var\n",
> + digits);
> + return 1;
> + }
> + }
> +
> + for (i = 0; i < algo->digest_size; i++) {
> + char *nullp = vsum_str + (i + 1) * 2;
> + char end = *nullp;
> +
> + *nullp = '\0';
> + vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16);
> + *nullp = end;
> + }
> + }
> + return 0;
> +}
> +
> +static struct hash_algo *find_hash_algo(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
> + if (!stricmp(name, hash_algo[i].name))
> + return &hash_algo[i];
> + }
> +
> + return NULL;
> +}
> +
> +static void show_hash(struct hash_algo *algo, ulong addr, ulong len,
> + u8 *output)
> +{
> + int i;
> +
> + printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
> + for (i = 0; i < algo->digest_size; i++)
> + printf("%02x", output[i]);
> +}
> +
> +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag,
> + int argc, char * const argv[])
> +{
> + struct hash_algo *algo;
> + ulong addr, len;
> + u8 output[HASH_MAX_DIGEST_SIZE];
> + u8 vsum[HASH_MAX_DIGEST_SIZE];
> +
> + if (argc < 2)
> + return CMD_RET_USAGE;
> +
> + algo = find_hash_algo(algo_name);
> + if (!algo) {
> + printf("Unknown hash algorithm '%s'\n", algo_name);
> + return CMD_RET_USAGE;
> + }
> + addr = simple_strtoul(*argv++, NULL, 16);
> + len = simple_strtoul(*argv++, NULL, 16);
> + argc -= 2;
> +
> + if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
> + puts("HASH_MAX_DIGEST_SIZE exceeded\n");
> + return 1;
> + }
> +
> + algo->hash_func_ws((const unsigned char *)addr, len, output,
> + algo->chunk_size);
> +
> + /* Try to avoid code bloat when verify is not needed */
> +#ifdef CONFIG_HASH_VERIFY
> + if (verify) {
> +#else
> + if (0) {
> +#endif
> + if (!argc)
> + return CMD_RET_USAGE;
> + if (parse_verify_sum(algo, *argv, vsum)) {
> + printf("ERROR: %s does not contain a valid SHA1 sum\n",
> + *argv);
You should probably use the name of the algo in the error message, not
a fixed SHA1.
> + return 1;
> + }
> + if (memcmp(output, vsum, algo->digest_size) != 0) {
> + int i;
> +
> + show_hash(algo, addr, len, output);
> + printf(" != ");
> + for (i = 0; i < algo->digest_size; i++)
> + printf("%02x", vsum[i]);
> + puts(" ** ERROR **\n");
> + return 1;
> + }
> + } else {
> + show_hash(algo, addr, len, output);
> + printf("\n");
> +
> + if (argc)
> + store_result(algo, output, *argv);
> + }
> +
> + return 0;
> +}
> diff --git a/include/hash.h b/include/hash.h
> new file mode 100644
> index 0000000..34ba558
> --- /dev/null
> +++ b/include/hash.h
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (c) 2012 The Chromium OS Authors.
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef _HASH_H
> +#define _HASH_H
> +
> +#ifdef CONFIG_SHA1SUM_VERIFY
> +#define CONFIG_HASH_VERIFY
> +#endif
> +
> +struct hash_algo {
> + const char *name; /* Name of algorithm */
> + int digest_size; /* Length of digest */
> + /**
> + * hash_func_ws: Generic hashing function
> + *
> + * This is the generic prototype for a hashing function. We only
> + * have the watchdog version at present.
> + *
> + * @input: Input buffer
> + * @ilen: Input buffer length
> + * @output: Checksum result (length depends on algorithm)
> + * @chunk_sz: Trigger watchdog after processing this many bytes
> + */
> + void (*hash_func_ws)(const unsigned char *input, unsigned int ilen,
> + unsigned char *output, unsigned int chunk_sz);
> + int chunk_size; /* Watchdog chunk size */
> +};
> +
> +/*
> + * Maximum digest size for all algorithms we support. Having this value
> + * avoids a malloc() or C99 local declaration in common/cmd_hash.c.
> + */
> +#define HASH_MAX_DIGEST_SIZE 32
> +
> +/**
> + * hash_command: Process a hash command for a particular algorithm
> + *
> + * This common function is used to implement specific hash commands.
> + *
> + * @algo_name: Hash algorithm being used
> + * @verify: Non-zero to enable verify mode
> + * @cmdtp: Pointer to command table entry
> + * @flag: Some flags normally 0 (see CMD_FLAG_.. above)
> + * @argc: Number of arguments (arg 0 must be the command text)
> + * @argv: Arguments
> + */
> +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag,
> + int argc, char * const argv[]);
> +
> +#endif
Otherwise, looks good.
-Joe
More information about the U-Boot
mailing list