Hi Simon, On Thu, Nov 22, 2012 at 1:12 PM, Simon Glass <s...@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 <s...@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.hershber...@ni.com > + * > + * (C) Copyright 2000 > + * Wolfgang Denk, DENX Software Engineering, w...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot