--- /dev/null
+/* nettle-hash.c
+ *
+ * General hashing tool. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2011 Niels Möller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nettle-meta.h"
+#include "base16.h"
+
+#include "getopt.h"
+#include "misc.h"
+
+#define BUFSIZE 16384
+
+static void
+list_algorithms (void)
+{
+ unsigned i;
+ const struct nettle_hash *alg;
+ printf ("%10s digestsize (internal block size), in units of octest\n", "name");
+
+ for (i = 0; (alg = nettle_hashes[i]); i++)
+ printf ("%10s %d (%d)\n",
+ alg->name, alg->digest_size, alg->block_size);
+};
+
+static const struct nettle_hash *
+find_algorithm (const char *name)
+{
+ size_t length = strlen (name);
+ const struct nettle_hash *alg;
+ const struct nettle_hash *found = NULL;
+ unsigned i;
+
+ for (i = 0; (alg = nettle_hashes[i]); i++)
+ {
+ if (!strncmp(name, alg->name, length))
+ {
+ /* Luckily, no valid algorithm name is a prefix of any
+ other, so we don't need to handle exact matches
+ specially. */
+
+ if (found)
+ die("Hash algorithm `%s' is ambiguous (%s or %s or ...?).\n"
+ "Use nettle-hash --list to list all available algorithms.\n",
+ name, alg->name, found->name);
+ found = alg;
+ }
+ }
+ if (!found)
+ die("Hash algorithm `%s' is not supported.\n"
+ "Use nettle-hash --list to list all available algorithms.\n",
+ name);
+ return found;
+}
+
+/* Also in examples/io.c */
+static int
+hash_file(const struct nettle_hash *hash, void *ctx, FILE *f)
+{
+ for (;;)
+ {
+ char buffer[BUFSIZE];
+ size_t res = fread(buffer, 1, sizeof(buffer), f);
+ if (ferror(f))
+ return 0;
+
+ hash->update(ctx, res, buffer);
+ if (feof(f))
+ return 1;
+ }
+}
+
+static int
+digest_file(const struct nettle_hash *alg,
+ unsigned digest_length, int raw,
+ FILE *f)
+{
+ void *ctx;
+ uint8_t *digest;
+ ctx = xalloc(alg->context_size);
+
+ alg->init(ctx);
+
+ if (!hash_file (alg, ctx, f))
+ {
+ free (ctx);
+ return 0;
+ }
+
+ digest = xalloc(digest_length);
+ alg->digest(ctx, digest_length, digest);
+ free(ctx);
+
+ if (raw)
+ fwrite (digest, digest_length, 1, stdout);
+
+ else
+ {
+ unsigned i;
+ char *hex = xalloc(BASE16_ENCODE_LENGTH(8) + 1);
+ for (i = 0; i + 8 < digest_length; i += 8)
+ {
+ base16_encode_update(hex, 8, digest + i);
+ hex[BASE16_ENCODE_LENGTH(8)] = 0;
+ printf("%s ", hex);
+ }
+ base16_encode_update(hex, digest_length - i, digest + i);
+ hex[BASE16_ENCODE_LENGTH(digest_length - i)] = 0;
+ printf("%s %s\n", hex, alg->name);
+ free(hex);
+ }
+
+ free(digest);
+
+ return 1;
+}
+
+int
+main (int argc, char **argv)
+{
+ const char *alg_name = NULL;
+ const struct nettle_hash *alg;
+ unsigned length = 0;
+ int raw = 0;
+ int c;
+
+ enum { OPT_HELP = 0x300, OPT_RAW, OPT_LIST };
+ static const struct option options[] =
+ {
+ /* Name, args, flag, val */
+ { "help", no_argument, NULL, OPT_HELP },
+ { "version", no_argument, NULL, 'V' },
+ { "algorithm", required_argument, NULL, 'a' },
+ { "length", required_argument, NULL, 'l' },
+ { "list", no_argument, NULL, OPT_LIST },
+ { "raw", no_argument, NULL, OPT_RAW },
+
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ( (c = getopt_long(argc, argv, "Va:l:", options, NULL)) != -1)
+ switch (c)
+ {
+ default:
+ abort();
+ case OPT_HELP:
+ printf("nettle-hash -a ALGORITHM [OPTIONS] [FILE ...]\n"
+ "Options:\n"
+ " --help Show this help.\n"
+ " -V, --version Show version information.\n"
+ " --list List supported hash algorithms.\n"
+ " -a, --algorithm=ALG Hash algorithm to use.\n"
+ " -l, --length=LENGTH Desired digest length (octets)\n"
+ " --raw Raw binary output.\n");
+ return EXIT_SUCCESS;
+ case 'V':
+ printf("nettle-hash (" PACKAGE_STRING ")\n");
+ return EXIT_SUCCESS;
+ case 'a':
+ alg_name = optarg;
+ break;
+ case 'l':
+ {
+ int arg;
+ arg = atoi (optarg);
+ if (arg <= 0)
+ die ("Invalid length argument: `%s'\n", optarg);
+ length = arg;
+ }
+ break;
+ case OPT_RAW:
+ raw = 1;
+ break;
+ case OPT_LIST:
+ list_algorithms();
+ return EXIT_SUCCESS;
+ }
+
+ if (!alg_name)
+ die("Algorithm argument (-a option) is mandatory.\n"
+ "See nettle-hash --help for further information.\n");
+
+ alg = find_algorithm (alg_name);
+ if (!alg)
+ die("Hash algorithm `%s' not supported or .\n"
+ "Use nettle-hash --list to list available algorithms.\n",
+ alg_name);
+
+ if (length == 0)
+ length = alg->digest_size;
+ else if (length > alg->digest_size)
+ die ("Length argument %d too large for selected algorithm.\n",
+ length);
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0)
+ digest_file (alg, length, raw, stdin);
+ else
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ {
+ FILE *f = fopen (argv[i], "rb");
+ if (!f)
+ die ("Cannot open `%s': %s\n", argv[i], STRERROR(errno));
+ printf("%s: ", argv[i]);
+ if (!digest_file (alg, length, raw, f))
+ die("Reading `%s' failed: %s\n", argv[i], STRERROR(errno));
+ fclose(f);
+ }
+ }
+ if (fflush(stdout) != 0 )
+ die("Write failed: %s\n", STRERROR(errno));
+
+ return EXIT_SUCCESS;
+}