From patchwork Thu Dec 6 00:46:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 204078 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 350722C00A8 for ; Thu, 6 Dec 2012 11:51:28 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3C9074A13E; Thu, 6 Dec 2012 01:51:19 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id RN19RX5uoNKi; Thu, 6 Dec 2012 01:51:19 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EC63F4A15D; Thu, 6 Dec 2012 01:50:29 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 944EF4A136 for ; Thu, 6 Dec 2012 01:50:23 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KG2Z+iY4MQPi for ; Thu, 6 Dec 2012 01:50:22 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ee0-f74.google.com (mail-ee0-f74.google.com [74.125.83.74]) by theia.denx.de (Postfix) with ESMTPS id EC4364A137 for ; Thu, 6 Dec 2012 01:50:16 +0100 (CET) Received: by mail-ee0-f74.google.com with SMTP id t10so588465eei.3 for ; Wed, 05 Dec 2012 16:50:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=OqJv04OfjiZJ6iJXSrD36z1tLl2vmKPbQ8zbwUvZeBo=; b=JLKvU4hTgc43rRU9k91bc2z3NraIu1WyOEXyjSn1EFpPixrmQgmfgthdr6Hly1ymBy CSkgfs7F6DaX1ahSRgDK8NAS0lJvIftJbuFtf7SqzWduY2b1NsPUwTVnrBRdHZS1eD/H iGdmG8s7M9rLU/EpEwLFTRzU1eb7CjJYdynPP2OMWVR84dI2hCoysaw6N/ob4JUU8FM/ T2K9jrhtUubzzeIHt9Ad3KuNRt3EjqtTITRU60YcMVJ5c2z11cnazr7eaC82BjGGJBcm nvfn8R0hEjDw/j2XIzNRvlQxzS3gWkHw7t7gx9WpiYLmMBeUd53c79nmWtYUjEaJBJog a8PA== Received: by 10.14.224.201 with SMTP id x49mr6828191eep.5.1354755015943; Wed, 05 Dec 2012 16:50:15 -0800 (PST) Received: from hpza10.eem.corp.google.com ([74.125.121.33]) by gmr-mx.google.com with ESMTPS id g9si896902eeo.1.2012.12.05.16.50.15 (version=TLSv1/SSLv3 cipher=AES128-SHA); Wed, 05 Dec 2012 16:50:15 -0800 (PST) Received: from kaka.mtv.corp.google.com (kaka.mtv.corp.google.com [172.22.73.79]) by hpza10.eem.corp.google.com (Postfix) with ESMTP id 6AC1F20004E; Wed, 5 Dec 2012 16:50:15 -0800 (PST) Received: by kaka.mtv.corp.google.com (Postfix, from userid 121222) id CFED31609AD; Wed, 5 Dec 2012 16:50:14 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Date: Wed, 5 Dec 2012 16:46:36 -0800 Message-Id: <1354754807-21449-10-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.7.7.3 In-Reply-To: <1354754807-21449-1-git-send-email-sjg@chromium.org> References: <1354754807-21449-1-git-send-email-sjg@chromium.org> X-Gm-Message-State: ALoCoQmsBV25Nwt3MXwiScPS0KIokv/Rt8gzl425rpb92zeAS9qg6RoPBcWfHpC7gDFAoh4JPZrm0atzP6eUGvt9p6fAys2AvIlNdMRRkeZ0baGNz4VR9qd5StZ9wDSRitzpWfmRVbPyRO36ut2+hbnWZFFHcL5PaOMB0QUrGu45r5a47qqePNQvlbmsenKggYg3DBnH9apL Cc: Tom Rini Subject: [U-Boot] [PATCH v3 09/20] Add generic hash API X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- Changes in v3: - Rename stricmp() to strcasecmp() to match Linux / POSIX - Correct hash error message to show the algorithm name, not always SHA1 - Fix ordering of hash.o in Makefile 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..c451c3d 100644 --- a/common/Makefile +++ b/common/Makefile @@ -30,6 +30,7 @@ ifndef CONFIG_SPL_BUILD COBJS-y += main.o COBJS-y += command.o COBJS-y += exports.o +COBJS-y += hash.o COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o COBJS-y += s_record.o COBJS-y += xyzModem.o diff --git a/common/hash.c b/common/hash.c new file mode 100644 index 0000000..e3a6e43 --- /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@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@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 +#include +#include +#include +#include + +/* + * 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 (!strcasecmp(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 %s sum\n", + *argv, algo->name); + 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