xref: /openbsd/bin/md5/md5.c (revision 7ef3bb0b)
1 /*	$OpenBSD: md5.c,v 1.79 2015/01/19 16:43:28 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2001,2003,2005-2007,2010,2013,2014
5  *	Todd C. Miller <Todd.Miller@courtesan.com>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  *
19  * Sponsored in part by the Defense Advanced Research Projects
20  * Agency (DARPA) and Air Force Research Laboratory, Air Force
21  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22  */
23 
24 #include <sys/types.h>
25 #include <sys/queue.h>
26 #include <netinet/in.h>
27 #include <ctype.h>
28 #include <err.h>
29 #include <fcntl.h>
30 #include <resolv.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <errno.h>
38 
39 #include <md5.h>
40 #include <rmd160.h>
41 #include <sha1.h>
42 #include <sha2.h>
43 #include <crc.h>
44 
45 #define STYLE_MD5	0
46 #define STYLE_CKSUM	1
47 #define STYLE_TERSE	2
48 
49 #define MAX_DIGEST_LEN	128
50 
51 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
52 #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
53 
54 union ANY_CTX {
55 #if !defined(SHA2_ONLY)
56 	CKSUM_CTX cksum;
57 	MD5_CTX md5;
58 	RMD160_CTX rmd160;
59 	SHA1_CTX sha1;
60 #endif /* !defined(SHA2_ONLY) */
61 	SHA2_CTX sha2;
62 };
63 
64 struct hash_function {
65 	const char *name;
66 	size_t digestlen;
67 	int style;
68 	int base64;
69 	void *ctx;	/* XXX - only used by digest_file() */
70 	void (*init)(void *);
71 	void (*update)(void *, const unsigned char *, unsigned int);
72 	void (*final)(unsigned char *, void *);
73 	char * (*end)(void *, char *);
74 	TAILQ_ENTRY(hash_function) tailq;
75 } functions[] = {
76 #if !defined(SHA2_ONLY)
77 	{
78 		"CKSUM",
79 		CKSUM_DIGEST_LENGTH,
80 		STYLE_CKSUM,
81 		-1,
82 		NULL,
83 		(void (*)(void *))CKSUM_Init,
84 		(void (*)(void *, const unsigned char *, unsigned int))CKSUM_Update,
85 		(void (*)(unsigned char *, void *))CKSUM_Final,
86 		(char *(*)(void *, char *))CKSUM_End
87 	},
88 	{
89 		"MD5",
90 		MD5_DIGEST_LENGTH,
91 		STYLE_MD5,
92 		0,
93 		NULL,
94 		(void (*)(void *))MD5Init,
95 		(void (*)(void *, const unsigned char *, unsigned int))MD5Update,
96 		(void (*)(unsigned char *, void *))MD5Final,
97 		(char *(*)(void *, char *))MD5End
98 	},
99 	{
100 		"RMD160",
101 		RMD160_DIGEST_LENGTH,
102 		STYLE_MD5,
103 		0,
104 		NULL,
105 		(void (*)(void *))RMD160Init,
106 		(void (*)(void *, const unsigned char *, unsigned int))RMD160Update,
107 		(void (*)(unsigned char *, void *))RMD160Final,
108 		(char *(*)(void *, char *))RMD160End
109 	},
110 	{
111 		"SHA1",
112 		SHA1_DIGEST_LENGTH,
113 		STYLE_MD5,
114 		0,
115 		NULL,
116 		(void (*)(void *))SHA1Init,
117 		(void (*)(void *, const unsigned char *, unsigned int))SHA1Update,
118 		(void (*)(unsigned char *, void *))SHA1Final,
119 		(char *(*)(void *, char *))SHA1End
120 	},
121 	{
122 		"SHA224",
123 		SHA224_DIGEST_LENGTH,
124 		STYLE_MD5,
125 		0,
126 		NULL,
127 		(void (*)(void *))SHA224Init,
128 		(void (*)(void *, const unsigned char *, unsigned int))SHA224Update,
129 		(void (*)(unsigned char *, void *))SHA224Final,
130 		(char *(*)(void *, char *))SHA224End
131 	},
132 #endif /* !defined(SHA2_ONLY) */
133 	{
134 		"SHA256",
135 		SHA256_DIGEST_LENGTH,
136 		STYLE_MD5,
137 		0,
138 		NULL,
139 		(void (*)(void *))SHA256Init,
140 		(void (*)(void *, const unsigned char *, unsigned int))SHA256Update,
141 		(void (*)(unsigned char *, void *))SHA256Final,
142 		(char *(*)(void *, char *))SHA256End
143 	},
144 #if !defined(SHA2_ONLY)
145 	{
146 		"SHA384",
147 		SHA384_DIGEST_LENGTH,
148 		STYLE_MD5,
149 		0,
150 		NULL,
151 		(void (*)(void *))SHA384Init,
152 		(void (*)(void *, const unsigned char *, unsigned int))SHA384Update,
153 		(void (*)(unsigned char *, void *))SHA384Final,
154 		(char *(*)(void *, char *))SHA384End
155 	},
156 #endif /* !defined(SHA2_ONLY) */
157 	{
158 		"SHA512",
159 		SHA512_DIGEST_LENGTH,
160 		STYLE_MD5,
161 		0,
162 		NULL,
163 		(void (*)(void *))SHA512Init,
164 		(void (*)(void *, const unsigned char *, unsigned int))SHA512Update,
165 		(void (*)(unsigned char *, void *))SHA512Final,
166 		(char *(*)(void *, char *))SHA512End
167 	},
168 	{
169 		NULL,
170 	}
171 };
172 
173 TAILQ_HEAD(hash_list, hash_function);
174 
175 void digest_end(const struct hash_function *, void *, char *, size_t, int);
176 int  digest_file(const char *, struct hash_list *, int);
177 void digest_print(const struct hash_function *, const char *, const char *);
178 #if !defined(SHA2_ONLY)
179 int  digest_filelist(const char *, struct hash_function *, int, char **);
180 void digest_printstr(const struct hash_function *, const char *, const char *);
181 void digest_string(char *, struct hash_list *);
182 void digest_test(struct hash_list *);
183 void digest_time(struct hash_list *, int);
184 #endif /* !defined(SHA2_ONLY) */
185 void hash_insert(struct hash_list *, struct hash_function *, int);
186 void usage(void) __attribute__((__noreturn__));
187 
188 extern char *__progname;
189 int qflag = 0;
190 FILE *ofile = NULL;
191 
192 int
193 main(int argc, char **argv)
194 {
195 	struct hash_function *hf, *hftmp;
196 	struct hash_list hl;
197 	size_t len;
198 	char *cp, *input_string, *selective_checklist;
199 	const char *optstr;
200 	int fl, error, base64, i;
201 	int bflag, cflag, pflag, rflag, tflag, xflag;
202 
203 	TAILQ_INIT(&hl);
204 	input_string = NULL;
205 	selective_checklist = NULL;
206 	error = bflag = cflag = pflag = qflag = rflag = tflag = xflag = 0;
207 
208 #if !defined(SHA2_ONLY)
209 	if (strcmp(__progname, "cksum") == 0)
210 		optstr = "a:bC:ch:pqrs:tx";
211 	else
212 #endif /* !defined(SHA2_ONLY) */
213 		optstr = "bC:ch:pqrs:tx";
214 
215 	/* Check for -b option early since it changes behavior. */
216 	while ((fl = getopt(argc, argv, optstr)) != -1) {
217 		switch (fl) {
218 		case 'b':
219 			bflag = 1;
220 			break;
221 		case '?':
222 			usage();
223 		}
224 	}
225 	optind = 1;
226 	optreset = 1;
227 	while ((fl = getopt(argc, argv, optstr)) != -1) {
228 		switch (fl) {
229 		case 'a':
230 			while ((cp = strsep(&optarg, " \t,")) != NULL) {
231 				if (*cp == '\0')
232 					continue;
233 				base64 = -1;
234 				for (hf = functions; hf->name != NULL; hf++) {
235 					len = strlen(hf->name);
236 					if (strncasecmp(cp, hf->name, len) != 0)
237 						continue;
238 					if (cp[len] == '\0') {
239 						if (hf->base64 != -1)
240 							base64 = bflag;
241 						break;	/* exact match */
242 					}
243 					if (cp[len + 1] == '\0' &&
244 					    (cp[len] == 'b' || cp[len] == 'x')) {
245 						base64 =
246 						    cp[len] == 'b' ?  1 : 0;
247 						break;	/* match w/ suffix */
248 					}
249 				}
250 				if (hf->name == NULL) {
251 					warnx("unknown algorithm \"%s\"", cp);
252 					usage();
253 				}
254 				if (hf->base64 == -1 && base64 != -1) {
255 					warnx("%s doesn't support %s",
256 					    hf->name,
257 					    base64 ? "base64" : "hex");
258 					usage();
259 				}
260 				/* Check for dupes. */
261 				TAILQ_FOREACH(hftmp, &hl, tailq) {
262 					if (hftmp->base64 == base64 &&
263 					    strcmp(hf->name, hftmp->name) == 0)
264 						break;
265 				}
266 				if (hftmp == NULL)
267 					hash_insert(&hl, hf, base64);
268 			}
269 			break;
270 		case 'b':
271 			/* has already been parsed */
272 			break;
273 		case 'h':
274 			ofile = fopen(optarg, "w");
275 			if (ofile == NULL)
276 				err(1, "%s", optarg);
277 			break;
278 #if !defined(SHA2_ONLY)
279 		case 'C':
280 			selective_checklist = optarg;
281 			break;
282 		case 'c':
283 			cflag = 1;
284 			break;
285 #endif /* !defined(SHA2_ONLY) */
286 		case 'p':
287 			pflag = 1;
288 			break;
289 		case 'q':
290 			qflag = 1;
291 			break;
292 		case 'r':
293 			rflag = 1;
294 			break;
295 		case 's':
296 			input_string = optarg;
297 			break;
298 		case 't':
299 			tflag++;
300 			break;
301 		case 'x':
302 			xflag = 1;
303 			break;
304 		default:
305 			usage();
306 		}
307 	}
308 	argc -= optind;
309 	argv += optind;
310 
311 	if (ofile == NULL)
312 		ofile = stdout;
313 
314 	/* Most arguments are mutually exclusive */
315 	fl = pflag + (tflag ? 1 : 0) + xflag + cflag + (input_string != NULL);
316 	if (fl > 1 || (fl && argc && cflag == 0) || (rflag && qflag) ||
317 	    (selective_checklist != NULL && argc == 0))
318 		usage();
319 	if (selective_checklist || cflag) {
320 		if (TAILQ_FIRST(&hl) != TAILQ_LAST(&hl, hash_list))
321 			errx(1, "only a single algorithm may be specified "
322 			    "in -C or -c mode");
323 	}
324 
325 	/* No algorithm specified, check the name we were called as. */
326 	if (TAILQ_EMPTY(&hl)) {
327 		for (hf = functions; hf->name != NULL; hf++) {
328 			if (strcasecmp(hf->name, __progname) == 0)
329 				break;
330 		}
331 		if (hf->name == NULL)
332 			hf = &functions[0];	/* default to cksum */
333 		hash_insert(&hl, hf, (hf->base64 == -1 ? 0 : bflag));
334 	}
335 
336 	if (rflag || qflag) {
337 		const int new_style = rflag ? STYLE_CKSUM : STYLE_TERSE;
338 		TAILQ_FOREACH(hf, &hl, tailq) {
339 			hf->style = new_style;
340 		}
341 	}
342 
343 #if !defined(SHA2_ONLY)
344 	if (tflag)
345 		digest_time(&hl, tflag);
346 	else if (xflag)
347 		digest_test(&hl);
348 	else if (input_string)
349 		digest_string(input_string, &hl);
350 	else if (selective_checklist) {
351 		error = digest_filelist(selective_checklist, TAILQ_FIRST(&hl),
352 		    argc, argv);
353 		for (i = 0; i < argc; i++) {
354 			if (argv[i] != NULL) {
355 				warnx("%s does not exist in %s", argv[i],
356 				    selective_checklist);
357 				error++;
358 			}
359 		}
360 	} else if (cflag) {
361 		if (argc == 0)
362 			error = digest_filelist("-", TAILQ_FIRST(&hl), 0, NULL);
363 		else
364 			while (argc--)
365 				error += digest_filelist(*argv++,
366 				    TAILQ_FIRST(&hl), 0, NULL);
367 	} else
368 #endif /* !defined(SHA2_ONLY) */
369 	if (pflag || argc == 0)
370 		error = digest_file("-", &hl, pflag);
371 	else
372 		while (argc--)
373 			error += digest_file(*argv++, &hl, 0);
374 
375 	return(error ? EXIT_FAILURE : EXIT_SUCCESS);
376 }
377 
378 void
379 hash_insert(struct hash_list *hl, struct hash_function *hf, int base64)
380 {
381 	struct hash_function *hftmp;
382 
383 	hftmp = malloc(sizeof(*hftmp));
384 	if (hftmp == NULL)
385 		err(1, NULL);
386 	*hftmp = *hf;
387 	hftmp->base64 = base64;
388 	TAILQ_INSERT_TAIL(hl, hftmp, tailq);
389 }
390 
391 void
392 digest_end(const struct hash_function *hf, void *ctx, char *buf, size_t bsize,
393     int base64)
394 {
395 	u_char *digest;
396 
397 	if (base64 == 1) {
398 		if ((digest = malloc(hf->digestlen)) == NULL)
399 			err(1, NULL);
400 		hf->final(digest, ctx);
401 		if (b64_ntop(digest, hf->digestlen, buf, bsize) == -1)
402 			errx(1, "error encoding base64");
403 		memset(digest, 0, hf->digestlen);
404 		free(digest);
405 	} else {
406 		hf->end(ctx, buf);
407 	}
408 }
409 
410 #if !defined(SHA2_ONLY)
411 void
412 digest_string(char *string, struct hash_list *hl)
413 {
414 	struct hash_function *hf;
415 	char digest[MAX_DIGEST_LEN + 1];
416 	union ANY_CTX context;
417 
418 	TAILQ_FOREACH(hf, hl, tailq) {
419 		hf->init(&context);
420 		hf->update(&context, string, (unsigned int)strlen(string));
421 		digest_end(hf, &context, digest, sizeof(digest),
422 		    hf->base64);
423 		digest_printstr(hf, string, digest);
424 	}
425 }
426 #endif /* !defined(SHA2_ONLY) */
427 
428 void
429 digest_print(const struct hash_function *hf, const char *what,
430     const char *digest)
431 {
432 	switch (hf->style) {
433 	case STYLE_MD5:
434 		(void)fprintf(ofile, "%s (%s) = %s\n", hf->name, what, digest);
435 		break;
436 	case STYLE_CKSUM:
437 		(void)fprintf(ofile, "%s %s\n", digest, what);
438 		break;
439 	case STYLE_TERSE:
440 		(void)fprintf(ofile, "%s\n", digest);
441 		break;
442 	}
443 }
444 
445 #if !defined(SHA2_ONLY)
446 void
447 digest_printstr(const struct hash_function *hf, const char *what,
448     const char *digest)
449 {
450 	switch (hf->style) {
451 	case STYLE_MD5:
452 		(void)fprintf(ofile, "%s (\"%s\") = %s\n", hf->name, what, digest);
453 		break;
454 	case STYLE_CKSUM:
455 		(void)fprintf(ofile, "%s %s\n", digest, what);
456 		break;
457 	case STYLE_TERSE:
458 		(void)fprintf(ofile, "%s\n", digest);
459 		break;
460 	}
461 }
462 #endif /* !defined(SHA2_ONLY) */
463 
464 int
465 digest_file(const char *file, struct hash_list *hl, int echo)
466 {
467 	struct hash_function *hf;
468 	FILE *fp;
469 	size_t nread;
470 	u_char data[32 * 1024];
471 	char digest[MAX_DIGEST_LEN + 1];
472 
473 	if (strcmp(file, "-") == 0)
474 		fp = stdin;
475 	else if ((fp = fopen(file, "r")) == NULL) {
476 		warn("cannot open %s", file);
477 		return(1);
478 	}
479 
480 	TAILQ_FOREACH(hf, hl, tailq) {
481 		if ((hf->ctx = malloc(sizeof(union ANY_CTX))) == NULL)
482 			err(1, NULL);
483 		hf->init(hf->ctx);
484 	}
485 	while ((nread = fread(data, 1UL, sizeof(data), fp)) != 0) {
486 		if (echo) {
487 			(void)fwrite(data, nread, 1UL, stdout);
488 			if (fflush(stdout) != 0)
489 				err(1, "stdout: write error");
490 		}
491 		TAILQ_FOREACH(hf, hl, tailq)
492 			hf->update(hf->ctx, data, (unsigned int)nread);
493 	}
494 	if (ferror(fp)) {
495 		warn("%s: read error", file);
496 		if (fp != stdin)
497 			fclose(fp);
498 		TAILQ_FOREACH(hf, hl, tailq) {
499 			free(hf->ctx);
500 			hf->ctx = NULL;
501 		}
502 		return(1);
503 	}
504 	if (fp != stdin)
505 		fclose(fp);
506 	TAILQ_FOREACH(hf, hl, tailq) {
507 		digest_end(hf, hf->ctx, digest, sizeof(digest), hf->base64);
508 		free(hf->ctx);
509 		hf->ctx = NULL;
510 		if (fp == stdin)
511 			fprintf(ofile, "%s\n", digest);
512 		else
513 			digest_print(hf, file, digest);
514 	}
515 	return(0);
516 }
517 
518 #if !defined(SHA2_ONLY)
519 /*
520  * Parse through the input file looking for valid lines.
521  * If one is found, use this checksum and file as a reference and
522  * generate a new checksum against the file on the filesystem.
523  * Print out the result of each comparison.
524  */
525 int
526 digest_filelist(const char *file, struct hash_function *defhash, int selcount,
527     char **sel)
528 {
529 	int found, base64, error, cmp, i;
530 	size_t algorithm_max, algorithm_min;
531 	const char *algorithm;
532 	char *filename, *checksum, *buf, *p;
533 	char digest[MAX_DIGEST_LEN + 1];
534 	char *lbuf = NULL;
535 	FILE *listfp, *fp;
536 	size_t len, nread;
537 	u_char data[32 * 1024];
538 	union ANY_CTX context;
539 	struct hash_function *hf;
540 
541 	if (strcmp(file, "-") == 0) {
542 		listfp = stdin;
543 	} else if ((listfp = fopen(file, "r")) == NULL) {
544 		warn("cannot open %s", file);
545 		return(1);
546 	}
547 
548 	algorithm_max = algorithm_min = strlen(functions[0].name);
549 	for (hf = &functions[1]; hf->name != NULL; hf++) {
550 		len = strlen(hf->name);
551 		algorithm_max = MAXIMUM(algorithm_max, len);
552 		algorithm_min = MINIMUM(algorithm_min, len);
553 	}
554 
555 	error = found = 0;
556 	while ((buf = fgetln(listfp, &len))) {
557 		base64 = 0;
558 		if (buf[len - 1] == '\n')
559 			buf[len - 1] = '\0';
560 		else {
561 			if ((lbuf = malloc(len + 1)) == NULL)
562 				err(1, NULL);
563 
564 			(void)memcpy(lbuf, buf, len);
565 			lbuf[len] = '\0';
566 			buf = lbuf;
567 		}
568 		while (isspace((unsigned char)*buf))
569 			buf++;
570 
571 		/*
572 		 * Crack the line into an algorithm, filename, and checksum.
573 		 * Lines are of the form:
574 		 *  ALGORITHM (FILENAME) = CHECKSUM
575 		 *
576 		 * Fallback on GNU form:
577 		 *  CHECKSUM  FILENAME
578 		 */
579 		p = strchr(buf, ' ');
580 		if (p != NULL && *(p + 1) == '(') {
581 			/* BSD form */
582 			*p = '\0';
583 			algorithm = buf;
584 			len = strlen(algorithm);
585 			if (len > algorithm_max || len < algorithm_min)
586 				continue;
587 
588 			filename = p + 2;
589 			p = strrchr(filename, ')');
590 			if (p == NULL || strncmp(p + 1, " = ", (size_t)3) != 0)
591 				continue;
592 			*p = '\0';
593 
594 			checksum = p + 4;
595 			p = strpbrk(checksum, " \t\r");
596 			if (p != NULL)
597 				*p = '\0';
598 
599 			/*
600 			 * Check that the algorithm is one we recognize.
601 			 */
602 			for (hf = functions; hf->name != NULL; hf++) {
603 				if (strcasecmp(algorithm, hf->name) == 0)
604 					break;
605 			}
606 			if (hf->name == NULL || *checksum == '\0')
607 				continue;
608 			/*
609 			 * Check the length to see if this could be
610 			 * a valid checksum.  If hex, it will be 2x the
611 			 * size of the binary data.  For base64, we have
612 			 * to check both with and without the '=' padding.
613 			 */
614 			len = strlen(checksum);
615 			if (len != hf->digestlen * 2) {
616 				size_t len2;
617 
618 				if (checksum[len - 1] == '=') {
619 					/* use padding */
620 					len2 = 4 * ((hf->digestlen + 2) / 3);
621 				} else {
622 					/* no padding */
623 					len2 = (4 * hf->digestlen + 2) / 3;
624 				}
625 				if (len != len2)
626 					continue;
627 				base64 = 1;
628 			}
629 		} else {
630 			/* could be GNU form */
631 			if ((hf = defhash) == NULL)
632 				continue;
633 			algorithm = hf->name;
634 			checksum = buf;
635 			if ((p = strchr(checksum, ' ')) == NULL)
636 				continue;
637 			if (hf->style == STYLE_CKSUM) {
638 				if ((p = strchr(p + 1, ' ')) == NULL)
639 					continue;
640 			}
641 			*p++ = '\0';
642 			while (isspace((unsigned char)*p))
643 				p++;
644 			if (*p == '\0')
645 				continue;
646 			filename = p;
647 			p = strpbrk(filename, "\t\r");
648 			if (p != NULL)
649 				*p = '\0';
650 		}
651 		found = 1;
652 
653 		/*
654 		 * If only a selection of files is wanted, proceed only
655 		 * if the filename matches one of those in the selection.
656 		 * Mark found files by setting them to NULL so that we can
657 		 * detect files that are missing from the checklist later.
658 		 */
659 		if (sel) {
660 			for (i = 0; i < selcount; i++) {
661 				if (sel[i] && strcmp(sel[i], filename) == 0) {
662 					sel[i] = NULL;
663 					break;
664 				}
665 			}
666 			if (i == selcount)
667 				continue;
668 		}
669 
670 		if ((fp = fopen(filename, "r")) == NULL) {
671 			warn("cannot open %s", filename);
672 			(void)printf("(%s) %s: %s\n", algorithm, filename,
673 			    (errno == ENOENT ? "MISSING" : "FAILED"));
674 			error = 1;
675 			continue;
676 		}
677 
678 		hf->init(&context);
679 		while ((nread = fread(data, 1UL, sizeof(data), fp)) > 0)
680 			hf->update(&context, data, (unsigned int)nread);
681 		if (ferror(fp)) {
682 			warn("%s: read error", file);
683 			error = 1;
684 			fclose(fp);
685 			continue;
686 		}
687 		fclose(fp);
688 		digest_end(hf, &context, digest, sizeof(digest), base64);
689 
690 		if (base64)
691 			cmp = strncmp(checksum, digest, len);
692 		else
693 			cmp = strcasecmp(checksum, digest);
694 		if (cmp == 0) {
695 			if (qflag == 0)
696 				(void)printf("(%s) %s: OK\n", algorithm,
697 				    filename);
698 		} else {
699 			(void)printf("(%s) %s: FAILED\n", algorithm, filename);
700 			error = 1;
701 		}
702 	}
703 	if (listfp != stdin)
704 		fclose(listfp);
705 	if (!found)
706 		warnx("%s: no properly formatted checksum lines found", file);
707 	if (lbuf != NULL)
708 		free(lbuf);
709 	return(error || !found);
710 }
711 
712 #define TEST_BLOCK_LEN 10000
713 #define TEST_BLOCK_COUNT 10000
714 
715 void
716 digest_time(struct hash_list *hl, int times)
717 {
718 	struct hash_function *hf;
719 	struct timeval start, stop, res;
720 	union ANY_CTX context;
721 	u_int i;
722 	u_char data[TEST_BLOCK_LEN];
723 	char digest[MAX_DIGEST_LEN + 1];
724 	double elapsed;
725 	int count = TEST_BLOCK_COUNT;
726 	while (--times > 0 && count < INT_MAX / 10)
727 		count *= 10;
728 
729 	TAILQ_FOREACH(hf, hl, tailq) {
730 		(void)printf("%s time trial.  Processing %d %d-byte blocks...",
731 		    hf->name, count, TEST_BLOCK_LEN);
732 		fflush(stdout);
733 
734 		/* Initialize data based on block number. */
735 		for (i = 0; i < TEST_BLOCK_LEN; i++)
736 			data[i] = (u_char)(i & 0xff);
737 
738 		gettimeofday(&start, NULL);
739 		hf->init(&context);
740 		for (i = 0; i < count; i++)
741 			hf->update(&context, data, TEST_BLOCK_LEN);
742 		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
743 		gettimeofday(&stop, NULL);
744 		timersub(&stop, &start, &res);
745 		elapsed = res.tv_sec + res.tv_usec / 1000000.0;
746 
747 		(void)printf("\nDigest = %s\n", digest);
748 		(void)printf("Time   = %f seconds\n", elapsed);
749 		(void)printf("Speed  = %f bytes/second\n",
750 		    (double)TEST_BLOCK_LEN * count / elapsed);
751 	}
752 }
753 
754 void
755 digest_test(struct hash_list *hl)
756 {
757 	struct hash_function *hf;
758 	union ANY_CTX context;
759 	int i;
760 	char digest[MAX_DIGEST_LEN + 1];
761 	unsigned char buf[1000];
762 	unsigned const char *test_strings[] = {
763 		"",
764 		"a",
765 		"abc",
766 		"message digest",
767 		"abcdefghijklmnopqrstuvwxyz",
768 		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
769 		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
770 		    "0123456789",
771 		"12345678901234567890123456789012345678901234567890123456789"
772 		    "012345678901234567890",
773 	};
774 
775 	TAILQ_FOREACH(hf, hl, tailq) {
776 		(void)printf("%s test suite:\n", hf->name);
777 
778 		for (i = 0; i < 8; i++) {
779 			hf->init(&context);
780 			hf->update((void *)&context, test_strings[i],
781 			    (unsigned int)strlen(test_strings[i]));
782 			digest_end(hf, &context, digest, sizeof(digest),
783 			    hf->base64);
784 			digest_printstr(hf, test_strings[i], digest);
785 		}
786 
787 		/* Now simulate a string of a million 'a' characters. */
788 		memset(buf, 'a', sizeof(buf));
789 		hf->init(&context);
790 		for (i = 0; i < 1000; i++)
791 			hf->update(&context, buf,
792 			    (unsigned int)sizeof(buf));
793 		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
794 		digest_print(hf, "one million 'a' characters",
795 		    digest);
796 	}
797 }
798 #endif /* !defined(SHA2_ONLY) */
799 
800 void
801 usage(void)
802 {
803 #if !defined(SHA2_ONLY)
804 	if (strcmp(__progname, "cksum") == 0)
805 		fprintf(stderr, "usage: %s [-bcpqrtx] [-a algorithms] [-C checklist] "
806 		    "[-h hashfile]\n"
807 		    "	[-s string] [file ...]\n",
808 		    __progname);
809 	else
810 #endif /* !defined(SHA2_ONLY) */
811 		fprintf(stderr, "usage:"
812 		    "\t%s [-bcpqrtx] [-C checklist] [-h hashfile] [-s string] "
813 		    "[file ...]\n",
814 		    __progname);
815 
816 	exit(EXIT_FAILURE);
817 }
818