b669a6eeda09ae830038170a4565b6c1ac45ec9c
[platform/upstream/nettle.git] / tools / nettle-hash.c
1 /* nettle-hash.c
2
3    General hashing tool.
4
5    Copyright (C) 2011, 2013 Niels Möller
6
7    This file is part of GNU Nettle.
8
9    GNU Nettle is free software: you can redistribute it and/or
10    modify it under the terms of either:
11
12      * the GNU Lesser General Public License as published by the Free
13        Software Foundation; either version 3 of the License, or (at your
14        option) any later version.
15
16    or
17
18      * the GNU General Public License as published by the Free
19        Software Foundation; either version 2 of the License, or (at your
20        option) any later version.
21
22    or both in parallel, as here.
23
24    GNU Nettle is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27    General Public License for more details.
28
29    You should have received copies of the GNU General Public License and
30    the GNU Lesser General Public License along with this program.  If
31    not, see http://www.gnu.org/licenses/.
32 */
33
34 #if HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "nettle-meta.h"
44 #include "base16.h"
45
46 #include "getopt.h"
47 #include "misc.h"
48
49 #define BUFSIZE 16384
50
51 static void
52 list_algorithms (void)
53 {
54   unsigned i;
55   const struct nettle_hash *alg;
56   printf ("%10s digestsize (internal block size), in units of octets\n", "name");
57
58   for (i = 0; (alg = nettle_hashes[i]); i++)
59     printf ("%10s %d (%d)\n",
60             alg->name, alg->digest_size, alg->block_size);
61 };
62
63 static const struct nettle_hash *
64 find_algorithm (const char *name)
65 {
66   const struct nettle_hash *alg;
67   unsigned i;
68   
69   for (i = 0; (alg = nettle_hashes[i]); i++)
70     if (!strcmp(name, alg->name))
71       return alg;
72
73   return NULL;
74 }
75
76 /* Also in examples/io.c */
77 static int
78 hash_file(const struct nettle_hash *hash, void *ctx, FILE *f)
79 {
80   for (;;)
81     {
82       char buffer[BUFSIZE];
83       size_t res = fread(buffer, 1, sizeof(buffer), f);
84       if (ferror(f))
85         return 0;
86       
87       hash->update(ctx, res, buffer);
88       if (feof(f))
89         return 1;
90     }
91 }
92
93 static int
94 digest_file(const struct nettle_hash *alg,
95             unsigned digest_length, int raw,
96             FILE *f)
97 {
98   void *ctx;
99   uint8_t *digest;
100   ctx = xalloc(alg->context_size);
101
102   alg->init(ctx);
103
104   if (!hash_file (alg, ctx, f))
105     {
106       free (ctx);
107       return 0;
108     }
109
110   digest = xalloc(digest_length);
111   alg->digest(ctx, digest_length, digest);
112   free(ctx);
113
114   if (raw)
115     fwrite (digest, digest_length, 1, stdout);
116
117   else
118     {
119       unsigned i;
120       char hex[BASE16_ENCODE_LENGTH(8) + 1];
121       for (i = 0; i + 8 < digest_length; i += 8)
122         {
123           base16_encode_update(hex, 8, digest + i);
124           hex[BASE16_ENCODE_LENGTH(8)] = 0;
125           printf("%s ", hex);
126         }
127       base16_encode_update(hex, digest_length - i, digest + i);
128       hex[BASE16_ENCODE_LENGTH(digest_length - i)] = 0;
129       printf("%s %s\n", hex, alg->name);
130     }
131   
132   free(digest);
133
134   return 1;
135 }
136
137 static void
138 usage (FILE *f)
139 {
140   fprintf(f, "Usage: nettle-hash -a ALGORITHM [OPTIONS] [FILE ...]\n"
141           "Options:\n"
142           "  --help              Show this help.\n"
143           "  -V, --version       Show version information.\n"
144           "  --list              List supported hash algorithms.\n"
145           "  -a, --algorithm=ALG Hash algorithm to use.\n"
146           "  -l, --length=LENGTH Desired digest length (octets)\n"
147           "  --raw               Raw binary output.\n");
148 }
149
150 /* FIXME: Be more compatible with md5sum and sha1sum. Options -c
151    (check), -b (binary), -t (text), and output format with hex hash
152    sum, optional star (meaning binary mode), and file name. */
153 int
154 main (int argc, char **argv)
155 {
156   const char *alg_name = NULL;
157   const struct nettle_hash *alg;
158   unsigned length = 0;
159   int raw = 0;
160   int c;
161
162   enum { OPT_HELP = 0x300, OPT_RAW, OPT_LIST };
163   static const struct option options[] =
164     {
165       /* Name, args, flag, val */
166       { "help", no_argument, NULL, OPT_HELP },
167       { "version", no_argument, NULL, 'V' },
168       { "algorithm", required_argument, NULL, 'a' },
169       { "length", required_argument, NULL, 'l' },
170       { "list", no_argument, NULL, OPT_LIST },
171       { "raw", no_argument, NULL, OPT_RAW },
172
173       { NULL, 0, NULL, 0 }
174     };
175
176   while ( (c = getopt_long(argc, argv, "Va:l:", options, NULL)) != -1)
177     switch (c)
178       {
179       default:
180         abort();
181       case '?':
182         usage (stderr);
183         return EXIT_FAILURE;
184       case OPT_HELP:
185         usage (stdout);
186         return EXIT_SUCCESS;
187       case 'V':
188         printf("nettle-hash (" PACKAGE_STRING ")\n");
189         return EXIT_SUCCESS;
190       case 'a':
191         alg_name = optarg;
192         break;
193       case 'l':
194         {
195           int arg;
196           arg = atoi (optarg);
197           if (arg <= 0)
198             die ("Invalid length argument: `%s'\n", optarg);
199           length = arg;
200         }
201         break;
202       case OPT_RAW:
203         raw = 1;
204         break;
205       case OPT_LIST:
206         list_algorithms();
207         return EXIT_SUCCESS;
208       }
209
210   if (!alg_name)
211     die("Algorithm argument (-a option) is mandatory.\n"
212         "See nettle-hash --help for further information.\n");
213       
214   alg = find_algorithm (alg_name);
215   if (!alg)
216     die("Hash algorithm `%s' not supported or .\n"
217         "Use nettle-hash --list to list available algorithms.\n",
218         alg_name);
219
220   if (length == 0)
221     length = alg->digest_size;
222   else if (length > alg->digest_size)
223     die ("Length argument %d too large for selected algorithm.\n",
224          length);
225     
226   argv += optind;
227   argc -= optind;
228
229   if (argc == 0)
230     digest_file (alg, length, raw, stdin);
231   else
232     {
233       int i;
234       for (i = 0; i < argc; i++)
235         {
236           FILE *f = fopen (argv[i], "rb");
237           if (!f)
238             die ("Cannot open `%s': %s\n", argv[i], STRERROR(errno));
239           printf("%s: ", argv[i]);
240           if (!digest_file (alg, length, raw, f))
241             die("Reading `%s' failed: %s\n", argv[i], STRERROR(errno));
242           fclose(f);
243         }
244     }
245   if (fflush(stdout) != 0 )
246     die("Write failed: %s\n", STRERROR(errno));
247
248   return EXIT_SUCCESS;
249 }