1 /*-
2  * Copyright (c) 2001-2003 Allan Saddi <allan@saddi.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $Id: sha.c 351 2003-02-23 23:24:40Z asaddi $
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif /* HAVE_CONFIG_H */
32 
33 #if HAVE_INTTYPES_H
34 # include <inttypes.h>
35 #else
36 # if HAVE_STDINT_H
37 #  include <stdint.h>
38 # endif
39 #endif
40 
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #if HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif /* HAVE_UNISTD_H */
48 
49 #include "sha1.h"
50 #include "sha256.h"
51 #include "sha384.h"
52 #include "sha512.h"
53 
54 #include "version.h"
55 
56 #ifndef lint
57 static const char rcsid[] =
58 	"$Id: sha.c 351 2003-02-23 23:24:40Z asaddi $";
59 #endif /* !lint */
60 
61 static char *prog;
62 
63 #define SHA_BUFFER_SIZE 65536
64 static uint8_t *buffer;
65 
66 static int
shaFile(char * name,FILE * f,int which)67 shaFile (char *name, FILE *f, int which)
68 {
69   union {
70     SHA1Context sha1;
71     SHA256Context sha256;
72     SHA384Context sha384;
73     SHA512Context sha512;
74   } s;
75   size_t len;
76   uint8_t hash[SHA512_HASH_SIZE];
77   int hashLen, i;
78   int success = 1;
79 
80   switch (which) {
81   case 1:
82     SHA1Init (&s.sha1);
83     break;
84   case 2:
85     SHA256Init (&s.sha256);
86     break;
87   case 3:
88     SHA384Init (&s.sha384);
89     break;
90   case 5:
91     SHA512Init (&s.sha512);
92     break;
93   default:
94     abort ();
95   }
96 
97   while ((len = fread (buffer, 1, SHA_BUFFER_SIZE, f)) > 0) {
98     switch (which) {
99     case 1:
100       SHA1Update (&s.sha1, buffer, len);
101       break;
102     case 2:
103       SHA256Update (&s.sha256, buffer, len);
104       break;
105     case 3:
106       SHA384Update (&s.sha384, buffer, len);
107       break;
108     case 5:
109       SHA512Update (&s.sha512, buffer, len);
110       break;
111     default:
112       abort ();
113     }
114   }
115 
116   if (ferror (f)) {
117 #if HAVE_STRERROR
118     fprintf (stderr, "%s: %s: %s\n", prog, name ? name : "stdin",
119 	     strerror (errno));
120 #else
121     fprintf (stderr, "%s: %s: %s\n", prog, name ? name : "stdin",
122 	     "Read error");
123 #endif
124     success = 0;
125   }
126   else {
127     switch (which) {
128     case 1:
129       SHA1Final (&s.sha1, hash);
130       hashLen = SHA1_HASH_SIZE;
131       break;
132     case 2:
133       SHA256Final (&s.sha256, hash);
134       hashLen = SHA256_HASH_SIZE;
135       break;
136     case 3:
137       SHA384Final (&s.sha384, hash);
138       hashLen = SHA384_HASH_SIZE;
139       break;
140     case 5:
141       SHA512Final (&s.sha512, hash);
142       hashLen = SHA512_HASH_SIZE;
143       break;
144     default:
145       abort ();
146     }
147 
148     for (i = 0; i < hashLen; i++)
149       printf ("%02x", hash[i]);
150 
151     if (name)
152       printf (" %s\n", name);
153     else
154       printf ("\n");
155   }
156 
157   memset (&s, 0, sizeof (s));
158 
159   return success;
160 }
161 
162 static void
help(int which)163 help (int which)
164 {
165   fprintf (stderr, "\nOptions:\n"
166 	   "\t-1\tUse SHA-1 %s\n"
167 	   "\t-2\tUse SHA-256 %s\n"
168 	   "\t-3\tUse SHA-384 %s\n"
169 	   "\t-5\tUse SHA-512 %s\n"
170 	   "\t-V\tDisplay version information\n"
171 	   "\t-h\tDisplay this summary\n\n"
172 	   "Only one of -1, -2, -3, -5 may be specified\n",
173 	   which == 1 ? "(Default)" : "",
174 	   which == 2 ? "(Default)" : "",
175 	   which == 3 ? "(Default)" : "",
176 	   which == 5 ? "(Default)" : "");
177 }
178 
179 static void
usage(void)180 usage (void)
181 {
182   fprintf (stderr, "Usage: %s [-1235Vh] [file ...]\n", prog);
183 }
184 
185 static void
burnBuffer(void)186 burnBuffer (void)
187 {
188   memset (buffer, 0, SHA_BUFFER_SIZE);
189 }
190 
191 int
main(int argc,char * argv[])192 main (int argc, char *argv[])
193 {
194   int ch;
195   char *whichStr;
196   int whichDef = 1;
197   int which = 0;
198   long offs;
199   int i;
200   FILE *f;
201   int failure = 0;
202 
203   prog = argv[0];
204 
205   if ((whichStr = getenv ("SHA_DEFAULT")) && *whichStr) {
206     switch (*whichStr) {
207     case '1':
208       whichDef = 1;
209       break;
210     case '2':
211       whichDef = 2;
212       break;
213     case '3':
214       whichDef = 3;
215       break;
216     case '5':
217       whichDef = 5;
218       break;
219     }
220   }
221 
222   while ((ch = getopt (argc, argv, "1235Vh")) != -1) {
223     switch (ch) {
224     case '1':
225     case '2':
226     case '3':
227     case '5':
228       if (!which)
229 	which = ch - '0';
230       else {
231 	usage ();
232 	help (whichDef);
233 	exit (1);
234       }
235       break;
236     case 'V':
237       fprintf (stderr, "%s version " VERSION_STRING " (" VERSION_DATE ")\n",
238 	       prog);
239       exit (1);
240     case 'h':
241       usage ();
242       help (whichDef);
243       exit (1);
244     case '?':
245     default:
246       usage ();
247       exit (1);
248     }
249   }
250   argc -= optind;
251   argv += optind;
252 
253   if (!which)
254     which = whichDef;
255 
256   /* Allocate a suitable buffer. */
257   if (!(buffer = malloc (SHA_BUFFER_SIZE + 7))) {
258     perror (prog);
259     exit (1);
260   }
261 
262   /* Ensure it is on a 64-bit boundary. */
263   if ((offs = (long) buffer & 7L))
264     buffer += 8 - offs;
265 
266   atexit (burnBuffer);
267 
268   /* If given no arguments, process stdin. */
269   if (!argc) {
270     if (shaFile (NULL, stdin, which))
271       exit (0);
272     else
273       exit (1);
274   }
275 
276   for (i = 0; i < argc; i++) {
277     if ((f = fopen (argv[i], "rb"))) {
278       if (!shaFile (argv[i], f, which))
279 	failure = 1;
280       fclose (f);
281     }
282     else {
283 #if HAVE_STRERROR
284       fprintf (stderr, "%s: %s: %s\n", prog, argv[i], strerror (errno));
285 #else
286       fprintf (stderr, "%s: %s: %s\n", prog, argv[i],
287 	       "No such file or directory");
288 #endif
289       failure = 1;
290     }
291   }
292 
293   exit (failure);
294 }
295