]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/md5/md5.c
Add 'contrib/unifdef/' from commit '0da44885831dc0a43c4ca6ff04a2430993cc0a80'
[FreeBSD/FreeBSD.git] / sbin / md5 / md5.c
1 /*
2  * Derived from:
3  *
4  * MDDRIVER.C - test driver for MD2, MD4 and MD5
5  */
6
7 /*
8  *  Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
9  *  rights reserved.
10  *
11  *  RSA Data Security, Inc. makes no representations concerning either
12  *  the merchantability of this software or the suitability of this
13  *  software for any particular purpose. It is provided "as is"
14  *  without express or implied warranty of any kind.
15  *
16  *  These notices must be retained in any copies of any part of this
17  *  documentation and/or software.
18  */
19
20 #include <sys/cdefs.h>
21 #include <sys/param.h>
22 #include <sys/resource.h>
23 #include <sys/stat.h>
24 #include <sys/time.h>
25
26 #include <err.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <getopt.h>
30 #include <md5.h>
31 #include <osreldate.h>
32 #include <ripemd.h>
33 #include <sha.h>
34 #include <sha224.h>
35 #include <sha256.h>
36 #include <sha384.h>
37 #include <sha512.h>
38 #include <sha512t.h>
39 #include <skein.h>
40 #include <stdbool.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46
47 #ifdef HAVE_CAPSICUM
48 #include <sys/capsicum.h>
49 #include <capsicum_helpers.h>
50 #endif
51
52 /*
53  * Length of test block, number of test blocks.
54  */
55 #define TEST_BLOCK_LEN 10000
56 #define TEST_BLOCK_COUNT 100000
57 #define MDTESTCOUNT 8
58
59 static char *progname;
60
61 static bool cflag;
62 static bool pflag;
63 static bool qflag;
64 static bool sflag;
65 static bool wflag;
66 static bool strict;
67 static bool skip;
68 static bool ignoreMissing;
69 static char* checkAgainst;
70 static int checksFailed;
71 static bool failed;
72 static int endl = '\n';
73
74 typedef void (DIGEST_Init)(void *);
75 typedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
76 typedef char *(DIGEST_End)(void *, char *);
77
78 extern const char *MD5TestOutput[MDTESTCOUNT];
79 extern const char *SHA1_TestOutput[MDTESTCOUNT];
80 extern const char *SHA224_TestOutput[MDTESTCOUNT];
81 extern const char *SHA256_TestOutput[MDTESTCOUNT];
82 extern const char *SHA384_TestOutput[MDTESTCOUNT];
83 extern const char *SHA512_TestOutput[MDTESTCOUNT];
84 extern const char *SHA512t224_TestOutput[MDTESTCOUNT];
85 extern const char *SHA512t256_TestOutput[MDTESTCOUNT];
86 extern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
87 extern const char *SKEIN256_TestOutput[MDTESTCOUNT];
88 extern const char *SKEIN512_TestOutput[MDTESTCOUNT];
89 extern const char *SKEIN1024_TestOutput[MDTESTCOUNT];
90
91 typedef struct Algorithm_t {
92         const char *progname;
93         const char *perlname;
94         const char *name;
95         const char *(*TestOutput)[MDTESTCOUNT];
96         DIGEST_Init *Init;
97         DIGEST_Update *Update;
98         DIGEST_End *End;
99         char *(*Data)(const void *, unsigned int, char *);
100 } Algorithm_t;
101
102 static void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
103 static char *MDInput(const Algorithm_t *, FILE *, char *, bool);
104 static void MDOutput(const Algorithm_t *, char *, const char *);
105 static void MDTimeTrial(const Algorithm_t *);
106 static void MDTestSuite(const Algorithm_t *);
107 static void usage(const Algorithm_t *);
108 static void version(void);
109
110 typedef union {
111         MD5_CTX md5;
112         SHA1_CTX sha1;
113         SHA224_CTX sha224;
114         SHA256_CTX sha256;
115         SHA384_CTX sha384;
116         SHA512_CTX sha512;
117         RIPEMD160_CTX ripemd160;
118         SKEIN256_CTX skein256;
119         SKEIN512_CTX skein512;
120         SKEIN1024_CTX skein1024;
121 } DIGEST_CTX;
122
123 /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
124         SHA256_DIGEST_LENGTH, SHA512_DIGEST_LENGTH,
125         RIPEMD160_DIGEST_LENGTH, SKEIN1024_DIGEST_LENGTH)*2+1 */
126 #define HEX_DIGEST_LENGTH 257
127
128 /* algorithm function table */
129
130 static const struct Algorithm_t Algorithm[] = {
131         { "md5", NULL, "MD5",
132                 &MD5TestOutput, (DIGEST_Init*)&MD5Init,
133                 (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
134                 &MD5Data },
135         { "sha1", "1", "SHA1",
136                 &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
137                 (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
138                 &SHA1_Data },
139         { "sha224", "224", "SHA224",
140                 &SHA224_TestOutput, (DIGEST_Init*)&SHA224_Init,
141                 (DIGEST_Update*)&SHA224_Update, (DIGEST_End*)&SHA224_End,
142                 &SHA224_Data },
143         { "sha256", "256", "SHA256",
144                 &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init,
145                 (DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End,
146                 &SHA256_Data },
147         { "sha384", "384", "SHA384",
148                 &SHA384_TestOutput, (DIGEST_Init*)&SHA384_Init,
149                 (DIGEST_Update*)&SHA384_Update, (DIGEST_End*)&SHA384_End,
150                 &SHA384_Data },
151         { "sha512", "512", "SHA512",
152                 &SHA512_TestOutput, (DIGEST_Init*)&SHA512_Init,
153                 (DIGEST_Update*)&SHA512_Update, (DIGEST_End*)&SHA512_End,
154                 &SHA512_Data },
155         { "sha512t224", "512224", "SHA512t224",
156                 &SHA512t224_TestOutput, (DIGEST_Init*)&SHA512_224_Init,
157                 (DIGEST_Update*)&SHA512_224_Update, (DIGEST_End*)&SHA512_224_End,
158                 &SHA512_224_Data },
159         { "sha512t256", "512256", "SHA512t256",
160                 &SHA512t256_TestOutput, (DIGEST_Init*)&SHA512_256_Init,
161                 (DIGEST_Update*)&SHA512_256_Update, (DIGEST_End*)&SHA512_256_End,
162                 &SHA512_256_Data },
163         { "rmd160", NULL, "RMD160",
164                 &RIPEMD160_TestOutput,
165                 (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
166                 (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data },
167         { "skein256", NULL, "Skein256",
168                 &SKEIN256_TestOutput,
169                 (DIGEST_Init*)&SKEIN256_Init, (DIGEST_Update*)&SKEIN256_Update,
170                 (DIGEST_End*)&SKEIN256_End, &SKEIN256_Data },
171         { "skein512", NULL, "Skein512",
172                 &SKEIN512_TestOutput,
173                 (DIGEST_Init*)&SKEIN512_Init, (DIGEST_Update*)&SKEIN512_Update,
174                 (DIGEST_End*)&SKEIN512_End, &SKEIN512_Data },
175         { "skein1024", NULL, "Skein1024",
176                 &SKEIN1024_TestOutput,
177                 (DIGEST_Init*)&SKEIN1024_Init, (DIGEST_Update*)&SKEIN1024_Update,
178                 (DIGEST_End*)&SKEIN1024_End, &SKEIN1024_Data },
179         { }
180 };
181
182 static int digest = -1;
183 static unsigned int malformed;
184
185 static enum mode {
186         mode_bsd,
187         mode_gnu,
188         mode_perl,
189 } mode = mode_bsd;
190
191 static enum input_mode {
192         input_binary     = '*',
193         input_text       = ' ',
194         input_universal  = 'U',
195         input_bits       = '^',
196 } input_mode = input_binary;
197
198 static enum output_mode {
199         output_bare,
200         output_tagged,
201         output_reverse,
202         output_gnu,
203 } output_mode = output_tagged;
204
205 enum optval {
206         opt_end = -1,
207         /* ensure we don't collide with shortopts */
208         opt_dummy = CHAR_MAX,
209         /* BSD options */
210         opt_check,
211         opt_passthrough,
212         opt_quiet,
213         opt_reverse,
214         opt_string,
215         opt_time_trial,
216         opt_self_test,
217         /* GNU options */
218         opt_binary,
219         opt_help,
220         opt_ignore_missing,
221         opt_status,
222         opt_strict,
223         opt_tag,
224         opt_text,
225         opt_warn,
226         opt_version,
227         opt_zero,
228         /* Perl options */
229         opt_algorithm,
230         opt_bits,
231         opt_universal,
232 };
233
234 static const struct option bsd_longopts[] = {
235         { "check",              required_argument,      0, opt_check },
236         { "passthrough",        no_argument,            0, opt_passthrough },
237         { "quiet",              no_argument,            0, opt_quiet },
238         { "reverse",            no_argument,            0, opt_reverse },
239         { "string",             required_argument,      0, opt_string },
240         { "time-trial",         no_argument,            0, opt_time_trial },
241         { "self-test",          no_argument,            0, opt_self_test },
242         { }
243 };
244 static const char *bsd_shortopts = "bc:pqrs:tx";
245
246 static const struct option gnu_longopts[] = {
247         { "binary",             no_argument,            0, opt_binary },
248         { "check",              no_argument,            0, opt_check },
249         { "help",               no_argument,            0, opt_help },
250         { "ignore-missing",     no_argument,            0, opt_ignore_missing },
251         { "quiet",              no_argument,            0, opt_quiet },
252         { "status",             no_argument,            0, opt_status },
253         { "strict",             no_argument,            0, opt_strict },
254         { "tag",                no_argument,            0, opt_tag },
255         { "text",               no_argument,            0, opt_text },
256         { "version",            no_argument,            0, opt_version },
257         { "warn",               no_argument,            0, opt_warn },
258         { "zero",               no_argument,            0, opt_zero },
259         { }
260 };
261 static const char *gnu_shortopts = "bctwz";
262
263 static const struct option perl_longopts[] = {
264         { "algorithm",          required_argument,      0, opt_algorithm },
265         { "check",              required_argument,      0, opt_check },
266         { "help",               no_argument,            0, opt_help },
267         { "ignore-missing",     no_argument,            0, opt_ignore_missing },
268         { "quiet",              no_argument,            0, opt_quiet },
269         { "status",             no_argument,            0, opt_status },
270         { "strict",             no_argument,            0, opt_strict },
271         { "tag",                no_argument,            0, opt_tag },
272         { "text",               no_argument,            0, opt_text },
273         { "UNIVERSAL",          no_argument,            0, opt_universal },
274         { "version",            no_argument,            0, opt_version },
275         { "warn",               no_argument,            0, opt_warn },
276         { "01",                 no_argument,            0, opt_bits },
277         { }
278 };
279 static const char *perl_shortopts = "0a:bchqstUvw";
280
281 static void
282 MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
283 {
284         MD5Update(c, data, len);
285 }
286
287 struct chksumrec {
288         char    *filename;
289         char    *chksum;
290         struct  chksumrec       *next;
291 };
292
293 static struct chksumrec *head = NULL;
294 static struct chksumrec **next = &head;
295 static unsigned int numrecs;
296
297 #define PADDING 7       /* extra padding for "SHA512t256 (...) = ...\n" style */
298 #define CHKFILELINELEN  (HEX_DIGEST_LENGTH + MAXPATHLEN + PADDING)
299
300 static void
301 gnu_check(const char *checksumsfile)
302 {
303         FILE    *inp;
304         char    *linebuf = NULL;
305         size_t  linecap;
306         ssize_t linelen;
307         int     lineno;
308         char    *filename;
309         char    *hashstr;
310         struct chksumrec        *rec;
311         const char      *digestname;
312         size_t  digestnamelen;
313         size_t  hashstrlen;
314
315         if (strcmp(checksumsfile, "-") == 0)
316                 inp = stdin;
317         else if ((inp = fopen(checksumsfile, "r")) == NULL)
318                 err(1, "%s", checksumsfile);
319         digestname = Algorithm[digest].name;
320         digestnamelen = strlen(digestname);
321         hashstrlen = strlen(*(Algorithm[digest].TestOutput[0]));
322         lineno = 0;
323         linecap = CHKFILELINELEN;
324         while ((linelen = getline(&linebuf, &linecap, inp)) > 0) {
325                 lineno++;
326                 while (linelen > 0 && linebuf[linelen - 1] == '\n')
327                         linelen--;
328                 linebuf[linelen] = '\0';
329                 filename = linebuf + digestnamelen + 2;
330                 hashstr = linebuf + linelen - hashstrlen;
331                 /*
332                  * supported formats:
333                  * BSD: <DigestName> (<Filename>): <Digest>
334                  * GNU: <Digest> [ *U^]<Filename>
335                  */
336                 if ((size_t)linelen >= digestnamelen + hashstrlen + 6 &&
337                     strncmp(linebuf, digestname, digestnamelen) == 0 &&
338                     strncmp(filename - 2, " (", 2) == 0 &&
339                     strncmp(hashstr - 4, ") = ", 4) == 0 &&
340                     strspn(hashstr, "0123456789ABCDEFabcdef") == hashstrlen) {
341                         *(hashstr - 4) = '\0';
342                 } else if ((size_t)linelen >= hashstrlen + 3 &&
343                     strspn(linebuf, "0123456789ABCDEFabcdef") == hashstrlen &&
344                     linebuf[hashstrlen] == ' ') {
345                         linebuf[hashstrlen] = '\0';
346                         hashstr = linebuf;
347                         filename = linebuf + hashstrlen + 1;
348                 } else {
349                         if (wflag) {
350                                 warnx("%s: %d: improperly formatted "
351                                     "%s checksum line",
352                                     checksumsfile, lineno,
353                                     mode == mode_perl ? "SHA" : digestname);
354                         }
355                         malformed++;
356                         continue;
357                 }
358                 rec = malloc(sizeof(*rec));
359                 if (rec == NULL)
360                         errx(1, "malloc failed");
361                 rec->chksum = strdup(hashstr);
362                 rec->filename = strdup(filename);
363                 if (rec->chksum == NULL || rec->filename == NULL)
364                         errx(1, "malloc failed");
365                 rec->next = NULL;
366                 *next = rec;
367                 next = &rec->next;
368                 numrecs++;
369         }
370         if (inp != stdin)
371                 fclose(inp);
372 }
373
374 /* Main driver.
375
376 Arguments (may be any combination):
377   -sstring - digests string
378   -t       - runs time trial
379   -x       - runs test script
380   filename - digests file
381   (none)   - digests standard input
382  */
383 int
384 main(int argc, char *argv[])
385 {
386 #ifdef HAVE_CAPSICUM
387         cap_rights_t    rights;
388 #endif
389         const struct option *longopts;
390         const char *shortopts;
391         FILE   *f;
392         int     i, opt;
393         char   *p, *string = NULL;
394         char    buf[HEX_DIGEST_LENGTH];
395         size_t  len;
396         struct chksumrec        *rec;
397
398         if ((progname = strrchr(argv[0], '/')) == NULL)
399                 progname = argv[0];
400         else
401                 progname++;
402
403         /*
404          * GNU coreutils has a number of programs named *sum. These produce
405          * similar results to the BSD version, but in a different format,
406          * similar to BSD's -r flag. We install links to this program with
407          * ending 'sum' to provide this compatibility. Check here to see if the
408          * name of the program ends in 'sum', set the flag and drop the 'sum' so
409          * the digest lookup works. Also, make -t a nop when running in this mode
410          * since that means 'text file' there (though it's a nop in coreutils
411          * on unix-like systems). The -c flag conflicts, so it's just disabled
412          * in this mode (though in the future it might be implemented).
413          *
414          * We also strive to be compatible with the shasum script which is
415          * included in Perl.  It is roughly equivalent to the GNU offering
416          * but uses a command-line argument to select the algorithm, and
417          * supports only SHA-1 and SHA-2.
418          */
419         len = strlen(progname);
420         if (strcmp(progname, "shasum") == 0) {
421                 mode = mode_perl;
422                 input_mode = input_text;
423                 output_mode = output_gnu;
424                 digest = 1;
425                 longopts = perl_longopts;
426                 shortopts = perl_shortopts;
427         } else if (len > 3 && strcmp(progname + len - 3, "sum") == 0) {
428                 len -= 3;
429                 mode = mode_gnu;
430                 input_mode = input_text;
431                 /*
432                  * The historical behavior in GNU emulation mode is
433                  * output_reverse, however this not true to the original
434                  * and the flag that was used to force the correct output
435                  * was -b, which means something else (input_binary) in
436                  * GNU land.  Switch to the correct behavior.
437                  */
438                 output_mode = output_gnu;
439                 longopts = gnu_longopts;
440                 shortopts = gnu_shortopts;
441         } else {
442                 mode = mode_bsd;
443                 input_mode = input_binary;
444                 output_mode = output_tagged;
445                 longopts = bsd_longopts;
446                 shortopts = bsd_shortopts;
447         }
448
449         if (digest < 0) {
450                 for (digest = 0; Algorithm[digest].progname != NULL; digest++)
451                         if (strncasecmp(Algorithm[digest].progname, progname, len) == 0)
452                                 break;
453
454                 if (Algorithm[digest].progname == NULL)
455                         digest = 0;
456         }
457
458         failed = false;
459         checkAgainst = NULL;
460         checksFailed = 0;
461         skip = false;
462         while ((opt = getopt_long(argc, argv, shortopts, longopts, NULL)) != opt_end)
463                 switch (opt) {
464                 case opt_bits:
465                 case '0':
466                         input_mode = input_bits;
467                         break;
468                 case opt_algorithm:
469                 case 'a':
470                         for (i = 0; Algorithm[i].progname != NULL; i++) {
471                                 if (Algorithm[i].perlname != NULL &&
472                                     strcasecmp(Algorithm[i].perlname, optarg) == 0) {
473                                         digest = i;
474                                         break;
475                                 }
476                         }
477                         if (Algorithm[i].progname == NULL)
478                                 usage(&Algorithm[digest]);
479                         break;
480                 case opt_binary:
481                 case 'b':
482                         /* in BSD mode, -b is now a no-op */
483                         if (mode != mode_bsd)
484                                 input_mode = input_binary;
485                         break;
486                 case opt_check:
487                 case 'c':
488                         cflag = true;
489                         if (mode == mode_bsd)
490                                 checkAgainst = optarg;
491                         break;
492                 case opt_passthrough:
493                 case 'p':
494                         pflag = true;
495                         break;
496                 case opt_quiet:
497                 case 'q':
498                         output_mode = output_bare;
499                         qflag = true;
500                         break;
501                 case opt_reverse:
502                 case 'r':
503                         if (!qflag)
504                                 output_mode = output_reverse;
505                         break;
506                 case opt_status:
507                         sflag = true;
508                         break;
509                 case opt_strict:
510                         strict = 1;
511                         break;
512                 case 's':
513                         if (mode == mode_perl) {
514                                 sflag = true;
515                                 break;
516                         }
517                         /* fall through */
518                 case opt_string:
519                         output_mode = output_bare;
520                         string = optarg;
521                         break;
522                 case opt_tag:
523                         output_mode = output_tagged;
524                         break;
525                 case opt_time_trial:
526                 case opt_text:
527                 case 't':
528                         if (mode == mode_bsd) {
529                                 MDTimeTrial(&Algorithm[digest]);
530                                 skip = true;
531                         } else {
532                                 input_mode = input_text;
533                         }
534                         break;
535                 case opt_universal:
536                 case 'U':
537                         input_mode = input_universal;
538                         break;
539                 case opt_version:
540                         version();
541                         break;
542                 case opt_warn:
543                 case 'w':
544                         wflag = true;
545                         break;
546                 case opt_self_test:
547                 case 'x':
548                         MDTestSuite(&Algorithm[digest]);
549                         skip = true;
550                         break;
551                 case opt_zero:
552                 case 'z':
553                         endl = '\0';
554                         break;
555                 case opt_ignore_missing:
556                         ignoreMissing = true;
557                         break;
558                 default:
559                         usage(&Algorithm[digest]);
560                 }
561         argc -= optind;
562         argv += optind;
563
564 #ifdef HAVE_CAPSICUM
565         if (caph_limit_stdout() < 0 || caph_limit_stderr() < 0)
566                 err(1, "unable to limit rights for stdio");
567 #endif
568
569         if (cflag && mode != mode_bsd) {
570                 /*
571                  * Read digest files into a linked list, then replace argv
572                  * with an array of the filenames from that list.
573                  */
574                 if (argc < 1)
575                         usage(&Algorithm[digest]);
576                 while (argc--)
577                         gnu_check(*argv++);
578                 argc = 0;
579                 argv = calloc(sizeof(char *), numrecs + 1);
580                 for (rec = head; rec != NULL; rec = rec->next) {
581                         argv[argc] = rec->filename;
582                         argc++;
583                 }
584                 argv[argc] = NULL;
585                 rec = head;
586         }
587
588         if (*argv) {
589                 do {
590                         struct stat st;
591                         const char *filename = *argv;
592                         const char *filemode = "rb";
593
594                         if (*filename == '*' ||
595                             *filename == ' ' ||
596                             *filename == 'U' ||
597                             *filename == '^') {
598                                 if (lstat(filename, &st) != 0) {
599                                         input_mode = (int)*filename;
600                                         filename++;
601                                 }
602                         }
603                         if (input_mode == input_text)
604                                 filemode = "r";
605                         if ((f = fopen(filename, filemode)) == NULL) {
606                                 if (errno != ENOENT || !(cflag && ignoreMissing)) {
607                                         warn("%s", filename);
608                                         failed = true;
609                                 }
610                                 if (cflag && mode != mode_bsd)
611                                         rec = rec->next;
612                                 continue;
613                         }
614                         /*
615                          * XXX Enter capability mode on the last argv file.
616                          * When a casper file service or other approach is
617                          * available, switch to that and enter capability mode
618                          * earlier.
619                          */
620                         if (*(argv + 1) == NULL) {
621 #ifdef HAVE_CAPSICUM
622                                 cap_rights_init(&rights, CAP_READ, CAP_FSTAT);
623                                 if (caph_rights_limit(fileno(f), &rights) < 0 ||
624                                     caph_enter() < 0)
625                                         err(1, "capsicum");
626 #endif
627                         }
628                         if (cflag && mode != mode_bsd) {
629                                 checkAgainst = rec->chksum;
630                                 rec = rec->next;
631                         }
632                         p = MDInput(&Algorithm[digest], f, buf, false);
633                         (void)fclose(f);
634                         MDOutput(&Algorithm[digest], p, filename);
635                 } while (*++argv);
636         } else if (!cflag && string == NULL && !skip) {
637 #ifdef HAVE_CAPSICUM
638                 if (caph_limit_stdin() < 0 || caph_enter() < 0)
639                         err(1, "capsicum");
640 #endif
641                 if (mode == mode_bsd)
642                         output_mode = output_bare;
643                 p = MDInput(&Algorithm[digest], stdin, buf, pflag);
644                 MDOutput(&Algorithm[digest], p, "-");
645         } else if (string != NULL) {
646                 len = strlen(string);
647                 p = Algorithm[digest].Data(string, len, buf);
648                 MDOutput(&Algorithm[digest], p, string);
649         }
650         if (cflag && mode != mode_bsd) {
651                 if (!sflag && malformed > 1)
652                         warnx("WARNING: %d lines are improperly formatted", malformed);
653                 else if (!sflag && malformed > 0)
654                         warnx("WARNING: %d line is improperly formatted", malformed);
655                 if (!sflag && checksFailed > 1)
656                         warnx("WARNING: %d computed checksums did NOT match", checksFailed);
657                 else if (!sflag && checksFailed > 0)
658                         warnx("WARNING: %d computed checksum did NOT match", checksFailed);
659                 if (checksFailed != 0 || (strict && malformed > 0))
660                         return (1);
661         }
662         if (failed)
663                 return (1);
664         if (checksFailed > 0)
665                 return (2);
666
667         return (0);
668 }
669
670 /*
671  * Common input handling
672  */
673 static char *
674 MDInput(const Algorithm_t *alg, FILE *f, char *buf, bool tee)
675 {
676         char block[4096];
677         DIGEST_CTX context;
678         char *end, *p, *q;
679         size_t len;
680         int bits;
681         uint8_t byte;
682         bool cr = false;
683
684         alg->Init(&context);
685         while ((len = fread(block, 1, sizeof(block), f)) > 0) {
686                 switch (input_mode) {
687                 case input_binary:
688                 case input_text:
689                         if (tee && fwrite(block, 1, len, stdout) != len)
690                                 err(1, "stdout");
691                         alg->Update(&context, block, len);
692                         break;
693                 case input_universal:
694                         end = block + len;
695                         for (p = q = block; p < end; p = q) {
696                                 if (cr) {
697                                         if (*p == '\n')
698                                                 p++;
699                                         if (tee && putchar('\n') == EOF)
700                                                 err(1, "stdout");
701                                         alg->Update(&context, "\n", 1);
702                                         cr = false;
703                                 }
704                                 for (q = p; q < end && *q != '\r'; q++)
705                                         /* nothing */;
706                                 if (q > p) {
707                                         if (tee &&
708                                             fwrite(p, 1, q - p, stdout) !=
709                                             (size_t)(q - p))
710                                                 err(1, "stdout");
711                                         alg->Update(&context, p, q - p);
712                                 }
713                                 if (q < end && *q == '\r') {
714                                         cr = true;
715                                         q++;
716                                 }
717                         }
718                         break;
719                 case input_bits:
720                         end = block + len;
721                         bits = byte = 0;
722                         for (p = block; p < end; p++) {
723                                 if (*p == '0' || *p == '1') {
724                                         byte <<= 1;
725                                         byte |= *p - '0';
726                                         if (++bits == 8) {
727                                                 if (tee && putchar(byte) == EOF)
728                                                         err(1, "stdout");
729                                                 alg->Update(&context, &byte, 1);
730                                                 bits = byte = 0;
731                                         }
732                                 }
733                         }
734                         break;
735                 }
736         }
737         if (ferror(f)) {
738                 alg->End(&context, buf);
739                 return (NULL);
740         }
741         if (cr) {
742                 if (tee && putchar('\n') == EOF)
743                         err(1, "stdout");
744                 alg->Update(&context, "\n", 1);
745         }
746         if (input_mode == input_bits && bits != 0)
747                 errx(1, "input length was not a multiple of 8");
748         return (alg->End(&context, buf));
749 }
750
751 /*
752  * Common output handling
753  */
754 static void
755 MDOutput(const Algorithm_t *alg, char *p, const char *name)
756 {
757         bool checkfailed = false;
758
759         if (p == NULL) {
760                 warn("%s", name);
761                 failed = true;
762         } else if (cflag && mode != mode_bsd) {
763                 checkfailed = strcasecmp(checkAgainst, p) != 0;
764                 if (!sflag && (!qflag || checkfailed))
765                         printf("%s: %s%c", name, checkfailed ? "FAILED" : "OK",
766                             endl);
767         } else {
768                 switch (output_mode) {
769                 case output_bare:
770                         printf("%s", p);
771                         break;
772                 case output_gnu:
773                         printf("%s %c%s", p, input_mode, name);
774                         break;
775                 case output_reverse:
776                         printf("%s %s", p, name);
777                         break;
778                 case output_tagged:
779                         if (mode == mode_perl &&
780                             strncmp(alg->name, "SHA512t", 7) == 0) {
781                                 printf("%.6s/%s", alg->name, alg->name + 7);
782                         } else {
783                                 printf("%s", alg->name);
784                         }
785                         printf(" (%s) = %s", name, p);
786                         break;
787                 }
788                 if (checkAgainst) {
789                         checkfailed = strcasecmp(checkAgainst, p) != 0;
790                         if (!qflag && checkfailed)
791                                 printf(" [ Failed ]");
792                 }
793                 printf("%c", endl);
794         }
795         if (checkfailed)
796                 checksFailed++;
797 }
798
799 /*
800  * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
801  */
802 static void
803 MDTimeTrial(const Algorithm_t *alg)
804 {
805         DIGEST_CTX context;
806         struct rusage before, after;
807         struct timeval total;
808         float seconds;
809         unsigned char block[TEST_BLOCK_LEN];
810         unsigned int i;
811         char *p, buf[HEX_DIGEST_LENGTH];
812
813         printf("%s time trial. Digesting %d %d-byte blocks ...",
814             alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
815         fflush(stdout);
816
817         /* Initialize block */
818         for (i = 0; i < TEST_BLOCK_LEN; i++)
819                 block[i] = (unsigned char) (i & 0xff);
820
821         /* Start timer */
822         getrusage(RUSAGE_SELF, &before);
823
824         /* Digest blocks */
825         alg->Init(&context);
826         for (i = 0; i < TEST_BLOCK_COUNT; i++)
827                 alg->Update(&context, block, TEST_BLOCK_LEN);
828         p = alg->End(&context, buf);
829
830         /* Stop timer */
831         getrusage(RUSAGE_SELF, &after);
832         timersub(&after.ru_utime, &before.ru_utime, &total);
833         seconds = total.tv_sec + (float) total.tv_usec / 1000000;
834
835         printf(" done\n");
836         printf("Digest = %s", p);
837         printf("\nTime = %f seconds\n", seconds);
838         printf("Speed = %f MiB/second\n", (float) TEST_BLOCK_LEN *
839                 (float) TEST_BLOCK_COUNT / seconds / (1 << 20));
840 }
841 /*
842  * Digests a reference suite of strings and prints the results.
843  */
844
845 static const char *MDTestInput[MDTESTCOUNT] = {
846         "",
847         "a",
848         "abc",
849         "message digest",
850         "abcdefghijklmnopqrstuvwxyz",
851         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
852         "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
853         "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
854 that its security is in some doubt"
855 };
856
857 const char *MD5TestOutput[MDTESTCOUNT] = {
858         "d41d8cd98f00b204e9800998ecf8427e",
859         "0cc175b9c0f1b6a831c399e269772661",
860         "900150983cd24fb0d6963f7d28e17f72",
861         "f96b697d7cb7938d525a2f31aaf161d0",
862         "c3fcd3d76192e4007dfb496cca67e13b",
863         "d174ab98d277d9f5a5611c2c9f419d9f",
864         "57edf4a22be3c955ac49da2e2107b67a",
865         "b50663f41d44d92171cb9976bc118538"
866 };
867
868 const char *SHA1_TestOutput[MDTESTCOUNT] = {
869         "da39a3ee5e6b4b0d3255bfef95601890afd80709",
870         "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
871         "a9993e364706816aba3e25717850c26c9cd0d89d",
872         "c12252ceda8be8994d5fa0290a47231c1d16aae3",
873         "32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
874         "761c457bf73b14d27e9e9265c46f4b4dda11f940",
875         "50abf5706a150990a08b2c5ea40fa0e585554732",
876         "18eca4333979c4181199b7b4fab8786d16cf2846"
877 };
878
879 const char *SHA224_TestOutput[MDTESTCOUNT] = {
880         "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
881         "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5",
882         "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
883         "2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb",
884         "45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2",
885         "bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9",
886         "b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e",
887         "5ae55f3779c8a1204210d7ed7689f661fbe140f96f272ab79e19d470"
888 };
889
890 const char *SHA256_TestOutput[MDTESTCOUNT] = {
891         "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
892         "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
893         "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
894         "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650",
895         "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73",
896         "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0",
897         "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e",
898         "e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f"
899 };
900
901 const char *SHA384_TestOutput[MDTESTCOUNT] = {
902         "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
903         "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
904         "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
905         "473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5",
906         "feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4",
907         "1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84",
908         "b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026",
909         "99428d401bf4abcd4ee0695248c9858b7503853acfae21a9cffa7855f46d1395ef38596fcd06d5a8c32d41a839cc5dfb"
910 };
911
912 const char *SHA512_TestOutput[MDTESTCOUNT] = {
913         "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
914         "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
915         "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
916         "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c",
917         "4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1",
918         "1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894",
919         "72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843",
920         "e8a835195e039708b13d9131e025f4441dbdc521ce625f245a436dcd762f54bf5cb298d96235e6c6a304e087ec8189b9512cbdf6427737ea82793460c367b9c3"
921 };
922
923 const char *SHA512t224_TestOutput[MDTESTCOUNT] = {
924         "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
925         "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327",
926         "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa",
927         "ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564",
928         "ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8",
929         "a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3",
930         "ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2",
931         "b3c3b945249b0c8c94aba76ea887bcaad5401665a1fbeb384af4d06b"
932 };
933
934 const char *SHA512t256_TestOutput[MDTESTCOUNT] = {
935         "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
936         "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8",
937         "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23",
938         "0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb",
939         "fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26",
940         "cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8",
941         "2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148",
942         "dd095fc859b336c30a52548b3dc59fcc0d1be8616ebcf3368fad23107db2d736"
943 };
944
945 const char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
946         "9c1185a5c5e9fc54612808977ee8f548b2258d31",
947         "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
948         "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
949         "5d0689ef49d2fae572b881b123a85ffa21595f36",
950         "f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
951         "b0e20b6e3116640286ed3a87a5713079b21f5189",
952         "9b752e45573d4b39f4dbd3323cab82bf63326bfb",
953         "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
954 };
955
956 const char *SKEIN256_TestOutput[MDTESTCOUNT] = {
957         "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba",
958         "7fba44ff1a31d71a0c1f82e6e82fb5e9ac6c92a39c9185b9951fed82d82fe635",
959         "258bdec343b9fde1639221a5ae0144a96e552e5288753c5fec76c05fc2fc1870",
960         "4d2ce0062b5eb3a4db95bc1117dd8aa014f6cd50fdc8e64f31f7d41f9231e488",
961         "46d8440685461b00e3ddb891b2ecc6855287d2bd8834a95fb1c1708b00ea5e82",
962         "7c5eb606389556b33d34eb2536459528dc0af97adbcd0ce273aeb650f598d4b2",
963         "4def7a7e5464a140ae9c3a80279fbebce4bd00f9faad819ab7e001512f67a10d",
964         "d9c017dbe355f318d036469eb9b5fbe129fc2b5786a9dc6746a516eab6fe0126"
965 };
966
967 const char *SKEIN512_TestOutput[MDTESTCOUNT] = {
968         "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a",
969         "b1cd8d33f61b3737adfd59bb13ad82f4a9548e92f22956a8976cca3fdb7fee4fe91698146c4197cec85d38b83c5d93bdba92c01fd9a53870d0c7f967bc62bdce",
970         "8f5dd9ec798152668e35129496b029a960c9a9b88662f7f9482f110b31f9f93893ecfb25c009baad9e46737197d5630379816a886aa05526d3a70df272d96e75",
971         "15b73c158ffb875fed4d72801ded0794c720b121c0c78edf45f900937e6933d9e21a3a984206933d504b5dbb2368000411477ee1b204c986068df77886542fcc",
972         "23793ad900ef12f9165c8080da6fdfd2c8354a2929b8aadf83aa82a3c6470342f57cf8c035ec0d97429b626c4d94f28632c8f5134fd367dca5cf293d2ec13f8c",
973         "0c6bed927e022f5ddcf81877d42e5f75798a9f8fd3ede3d83baac0a2f364b082e036c11af35fe478745459dd8f5c0b73efe3c56ba5bb2009208d5a29cc6e469c",
974         "2ca9fcffb3456f297d1b5f407014ecb856f0baac8eb540f534b1f187196f21e88f31103128c2f03fcc9857d7a58eb66f9525e2302d88833ee069295537a434ce",
975         "1131f2aaa0e97126c9314f9f968cc827259bbfabced2943bb8c9274448998fb3b78738b4580dd500c76105fd3c03e465e1414f2c29664286b1f79d3e51128125"
976 };
977
978 const char *SKEIN1024_TestOutput[MDTESTCOUNT] = {
979         "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6",
980         "6ab4c4ba9814a3d976ec8bffa7fcc638ceba0544a97b3c98411323ffd2dc936315d13dc93c13c4e88cda6f5bac6f2558b2d8694d3b6143e40d644ae43ca940685cb37f809d3d0550c56cba8036dee729a4f8fb960732e59e64d57f7f7710f8670963cdcdc95b41daab4855fcf8b6762a64b173ee61343a2c7689af1d293eba97",
981         "35a599a0f91abcdb4cb73c19b8cb8d947742d82c309137a7caed29e8e0a2ca7a9ff9a90c34c1908cc7e7fd99bb15032fb86e76df21b72628399b5f7c3cc209d7bb31c99cd4e19465622a049afbb87c03b5ce3888d17e6e667279ec0aa9b3e2712624c01b5f5bbe1a564220bdcf6990af0c2539019f313fdd7406cca3892a1f1f",
982         "ea891f5268acd0fac97467fc1aa89d1ce8681a9992a42540e53babee861483110c2d16f49e73bac27653ff173003e40cfb08516cd34262e6af95a5d8645c9c1abb3e813604d508b8511b30f9a5c1b352aa0791c7d2f27b2706dccea54bc7de6555b5202351751c3299f97c09cf89c40f67187e2521c0fad82b30edbb224f0458",
983         "f23d95c2a25fbcd0e797cd058fec39d3c52d2b5afd7a9af1df934e63257d1d3dcf3246e7329c0f1104c1e51e3d22e300507b0c3b9f985bb1f645ef49835080536becf83788e17fed09c9982ba65c3cb7ffe6a5f745b911c506962adf226e435c42f6f6bc08d288f9c810e807e3216ef444f3db22744441deefa4900982a1371f",
984         "cf3889e8a8d11bfd3938055d7d061437962bc5eac8ae83b1b71c94be201b8cf657fdbfc38674997a008c0c903f56a23feb3ae30e012377f1cfa080a9ca7fe8b96138662653fb3335c7d06595bf8baf65e215307532094cfdfa056bd8052ab792a3944a2adaa47b30335b8badb8fe9eb94fe329cdca04e58bbc530f0af709f469",
985         "cf21a613620e6c119eca31fdfaad449a8e02f95ca256c21d2a105f8e4157048f9fe1e897893ea18b64e0e37cb07d5ac947f27ba544caf7cbc1ad094e675aed77a366270f7eb7f46543bccfa61c526fd628408058ed00ed566ac35a9761d002e629c4fb0d430b2f4ad016fcc49c44d2981c4002da0eecc42144160e2eaea4855a",
986         "e6799b78db54085a2be7ff4c8007f147fa88d326abab30be0560b953396d8802feee9a15419b48a467574e9283be15685ca8a079ee52b27166b64dd70b124b1d4e4f6aca37224c3f2685e67e67baef9f94b905698adc794a09672aba977a61b20966912acdb08c21a2c37001785355dc884751a21f848ab36e590331ff938138"
987 };
988
989 static void
990 MDTestSuite(const Algorithm_t *alg)
991 {
992         int i;
993         char buffer[HEX_DIGEST_LENGTH];
994
995         printf("%s test suite:\n", alg->name);
996         for (i = 0; i < MDTESTCOUNT; i++) {
997                 (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
998                 printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
999                 if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) {
1000                         printf(" - verified correct\n");
1001                 } else {
1002                         printf(" - INCORRECT RESULT!\n");
1003                         failed = true;
1004                 }
1005         }
1006 }
1007
1008 static void
1009 usage(const Algorithm_t *alg)
1010 {
1011
1012         switch (mode) {
1013         case mode_gnu:
1014                 fprintf(stderr, "usage: %ssum [-bctwz] [files ...]\n", alg->progname);
1015                 break;
1016         case mode_perl:
1017                 fprintf(stderr, "usage: shasum [-0bchqstUvw] [-a alg] [files ...]\n");
1018                 break;
1019         default:
1020                 fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n",
1021                     alg->progname);
1022         }
1023         exit(1);
1024 }
1025
1026 static void
1027 version(void)
1028 {
1029         if (mode == mode_gnu)
1030                 printf("%s (FreeBSD) ", progname);
1031         printf("%d.%d\n",
1032             __FreeBSD_version / 100000,
1033             (__FreeBSD_version / 1000) % 100);
1034         exit(0);
1035 }