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