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