GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/md5/md5.c Lines: 132 328 40.2 %
Date: 2016-12-06 Branches: 86 269 32.0 %

Line Branch Exec Source
1
/*	$OpenBSD: md5.c,v 1.84 2015/12/09 19:36:17 mmcc 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
22
{
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
22
	if (pledge("stdio rpath wpath cpath", NULL) == -1)
204
		err(1, "pledge");
205
206
22
	TAILQ_INIT(&hl);
207
22
	input_string = NULL;
208
22
	selective_checklist = NULL;
209
22
	error = bflag = cflag = pflag = qflag = rflag = tflag = xflag = 0;
210
211
#if !defined(SHA2_ONLY)
212
22
	if (strcmp(__progname, "cksum") == 0)
213
6
		optstr = "a:bC:ch:pqrs:tx";
214
	else
215
#endif /* !defined(SHA2_ONLY) */
216
16
		optstr = "bC:ch:pqrs:tx";
217
218
	/* Check for -b option early since it changes behavior. */
219
46
	while ((fl = getopt(argc, argv, optstr)) != -1) {
220
24
		switch (fl) {
221
		case 'b':
222
			bflag = 1;
223
			break;
224
		case '?':
225
			usage();
226
		}
227
	}
228
22
	optind = 1;
229
22
	optreset = 1;
230
68
	while ((fl = getopt(argc, argv, optstr)) != -1) {
231



24
		switch (fl) {
232
		case 'a':
233
8
			while ((cp = strsep(&optarg, " \t,")) != NULL) {
234
4
				if (*cp == '\0')
235
					continue;
236
4
				base64 = -1;
237
24
				for (hf = functions; hf->name != NULL; hf++) {
238
24
					len = strlen(hf->name);
239
24
					if (strncasecmp(cp, hf->name, len) != 0)
240
20
						continue;
241
4
					if (cp[len] == '\0') {
242
4
						if (hf->base64 != -1)
243
4
							base64 = bflag;
244
						break;	/* exact match */
245
					}
246
					if (cp[len + 1] == '\0' &&
247
					    (cp[len] == 'b' || cp[len] == 'x')) {
248
						base64 =
249
						    cp[len] == 'b' ?  1 : 0;
250
						break;	/* match w/ suffix */
251
					}
252
				}
253
4
				if (hf->name == NULL) {
254
					warnx("unknown algorithm \"%s\"", cp);
255
					usage();
256
				}
257
4
				if (hf->base64 == -1 && base64 != -1) {
258
					warnx("%s doesn't support %s",
259
					    hf->name,
260
					    base64 ? "base64" : "hex");
261
					usage();
262
				}
263
				/* Check for dupes. */
264
4
				TAILQ_FOREACH(hftmp, &hl, tailq) {
265
					if (hftmp->base64 == base64 &&
266
					    strcmp(hf->name, hftmp->name) == 0)
267
						break;
268
				}
269
4
				if (hftmp == NULL)
270
4
					hash_insert(&hl, hf, base64);
271
			}
272
			break;
273
		case 'b':
274
			/* has already been parsed */
275
			break;
276
		case 'h':
277
			ofile = fopen(optarg, "w");
278
			if (ofile == NULL)
279
				err(1, "%s", optarg);
280
			break;
281
#if !defined(SHA2_ONLY)
282
		case 'C':
283
			selective_checklist = optarg;
284
			break;
285
		case 'c':
286
			cflag = 1;
287
			break;
288
#endif /* !defined(SHA2_ONLY) */
289
		case 'p':
290
4
			pflag = 1;
291
4
			break;
292
		case 'q':
293
			qflag = 1;
294
			break;
295
		case 'r':
296
			rflag = 1;
297
			break;
298
		case 's':
299
2
			input_string = optarg;
300
2
			break;
301
		case 't':
302
			tflag++;
303
			break;
304
		case 'x':
305
14
			xflag = 1;
306
14
			break;
307
		default:
308
			usage();
309
		}
310
	}
311
22
	argc -= optind;
312
22
	argv += optind;
313
314
22
	if (ofile == NULL)
315
22
		ofile = stdout;
316
317
22
	if (pledge("stdio rpath wpath cpath", NULL) == -1)
318
		err(1, "pledge");
319
320
	/* Most arguments are mutually exclusive */
321
22
	fl = pflag + (tflag ? 1 : 0) + xflag + cflag + (input_string != NULL);
322



22
	if (fl > 1 || (fl && argc && cflag == 0) || (rflag && qflag) ||
323
	    (selective_checklist != NULL && argc == 0))
324
4
		usage();
325
18
	if (selective_checklist || cflag) {
326
		if (TAILQ_FIRST(&hl) != TAILQ_LAST(&hl, hash_list))
327
			errx(1, "only a single algorithm may be specified "
328
			    "in -C or -c mode");
329
	}
330
331
	/* No algorithm specified, check the name we were called as. */
332
18
	if (TAILQ_EMPTY(&hl)) {
333
50
		for (hf = functions; hf->name != NULL; hf++) {
334
50
			if (strcasecmp(hf->name, __progname) == 0)
335
14
				break;
336
		}
337
14
		if (hf->name == NULL)
338
			hf = &functions[0];	/* default to cksum */
339
14
		hash_insert(&hl, hf, (hf->base64 == -1 ? 0 : bflag));
340
	}
341
342

18
	if (rflag || qflag) {
343
		const int new_style = rflag ? STYLE_CKSUM : STYLE_TERSE;
344
		TAILQ_FOREACH(hf, &hl, tailq) {
345
			hf->style = new_style;
346
		}
347
	}
348
349
#if !defined(SHA2_ONLY)
350
18
	if (tflag)
351
		digest_time(&hl, tflag);
352
18
	else if (xflag)
353
14
		digest_test(&hl);
354
4
	else if (input_string)
355
		digest_string(input_string, &hl);
356
4
	else if (selective_checklist) {
357
		error = digest_filelist(selective_checklist, TAILQ_FIRST(&hl),
358
		    argc, argv);
359
		for (i = 0; i < argc; i++) {
360
			if (argv[i] != NULL) {
361
				warnx("%s does not exist in %s", argv[i],
362
				    selective_checklist);
363
				error++;
364
			}
365
		}
366
4
	} else if (cflag) {
367
		if (argc == 0)
368
			error = digest_filelist("-", TAILQ_FIRST(&hl), 0, NULL);
369
		else
370
			while (argc--)
371
				error += digest_filelist(*argv++,
372
				    TAILQ_FIRST(&hl), 0, NULL);
373
	} else
374
#endif /* !defined(SHA2_ONLY) */
375
4
	if (pflag || argc == 0)
376
2
		error = digest_file("-", &hl, pflag);
377
	else
378
6
		while (argc--)
379
4
			error += digest_file(*argv++, &hl, 0);
380
381
18
	return(error ? EXIT_FAILURE : EXIT_SUCCESS);
382
}
383
384
void
385
hash_insert(struct hash_list *hl, struct hash_function *hf, int base64)
386
18
{
387
	struct hash_function *hftmp;
388
389
18
	hftmp = malloc(sizeof(*hftmp));
390
18
	if (hftmp == NULL)
391
		err(1, NULL);
392
18
	*hftmp = *hf;
393
18
	hftmp->base64 = base64;
394
18
	TAILQ_INSERT_TAIL(hl, hftmp, tailq);
395
18
}
396
397
void
398
digest_end(const struct hash_function *hf, void *ctx, char *buf, size_t bsize,
399
    int base64)
400
132
{
401
	u_char *digest;
402
403
132
	if (base64 == 1) {
404
		if ((digest = malloc(hf->digestlen)) == NULL)
405
			err(1, NULL);
406
		hf->final(digest, ctx);
407
		if (b64_ntop(digest, hf->digestlen, buf, bsize) == -1)
408
			errx(1, "error encoding base64");
409
		memset(digest, 0, hf->digestlen);
410
		free(digest);
411
	} else {
412
132
		hf->end(ctx, buf);
413
	}
414
132
}
415
416
#if !defined(SHA2_ONLY)
417
void
418
digest_string(char *string, struct hash_list *hl)
419
{
420
	struct hash_function *hf;
421
	char digest[MAX_DIGEST_LEN + 1];
422
	union ANY_CTX context;
423
424
	TAILQ_FOREACH(hf, hl, tailq) {
425
		hf->init(&context);
426
		hf->update(&context, string, (unsigned int)strlen(string));
427
		digest_end(hf, &context, digest, sizeof(digest),
428
		    hf->base64);
429
		digest_printstr(hf, string, digest);
430
	}
431
}
432
#endif /* !defined(SHA2_ONLY) */
433
434
void
435
digest_print(const struct hash_function *hf, const char *what,
436
    const char *digest)
437
18
{
438

18
	switch (hf->style) {
439
	case STYLE_MD5:
440
16
		(void)fprintf(ofile, "%s (%s) = %s\n", hf->name, what, digest);
441
16
		break;
442
	case STYLE_CKSUM:
443
2
		(void)fprintf(ofile, "%s %s\n", digest, what);
444
2
		break;
445
	case STYLE_TERSE:
446
		(void)fprintf(ofile, "%s\n", digest);
447
		break;
448
	}
449
18
}
450
451
#if !defined(SHA2_ONLY)
452
void
453
digest_printstr(const struct hash_function *hf, const char *what,
454
    const char *digest)
455
112
{
456

112
	switch (hf->style) {
457
	case STYLE_MD5:
458
96
		(void)fprintf(ofile, "%s (\"%s\") = %s\n", hf->name, what, digest);
459
96
		break;
460
	case STYLE_CKSUM:
461
16
		(void)fprintf(ofile, "%s %s\n", digest, what);
462
16
		break;
463
	case STYLE_TERSE:
464
		(void)fprintf(ofile, "%s\n", digest);
465
		break;
466
	}
467
112
}
468
#endif /* !defined(SHA2_ONLY) */
469
470
int
471
digest_file(const char *file, struct hash_list *hl, int echo)
472
6
{
473
	struct hash_function *hf;
474
	FILE *fp;
475
	size_t nread;
476
	u_char data[32 * 1024];
477
	char digest[MAX_DIGEST_LEN + 1];
478
479
6
	if (strcmp(file, "-") == 0)
480
2
		fp = stdin;
481
4
	else if ((fp = fopen(file, "r")) == NULL) {
482
		warn("cannot open %s", file);
483
		return(1);
484
	}
485
486
12
	TAILQ_FOREACH(hf, hl, tailq) {
487
6
		if ((hf->ctx = malloc(sizeof(union ANY_CTX))) == NULL)
488
			err(1, NULL);
489
6
		hf->init(hf->ctx);
490
	}
491
8
	while ((nread = fread(data, 1UL, sizeof(data), fp)) != 0) {
492
2
		if (echo) {
493
2
			(void)fwrite(data, nread, 1UL, stdout);
494
2
			if (fflush(stdout) != 0)
495
				err(1, "stdout: write error");
496
		}
497
4
		TAILQ_FOREACH(hf, hl, tailq)
498
2
			hf->update(hf->ctx, data, (unsigned int)nread);
499
	}
500

6
	if (ferror(fp)) {
501
		warn("%s: read error", file);
502
		if (fp != stdin)
503
			fclose(fp);
504
		TAILQ_FOREACH(hf, hl, tailq) {
505
			free(hf->ctx);
506
			hf->ctx = NULL;
507
		}
508
		return(1);
509
	}
510
6
	if (fp != stdin)
511
4
		fclose(fp);
512
12
	TAILQ_FOREACH(hf, hl, tailq) {
513
6
		digest_end(hf, hf->ctx, digest, sizeof(digest), hf->base64);
514
6
		free(hf->ctx);
515
6
		hf->ctx = NULL;
516
6
		if (fp == stdin)
517
2
			fprintf(ofile, "%s\n", digest);
518
		else
519
4
			digest_print(hf, file, digest);
520
	}
521
6
	return(0);
522
}
523
524
#if !defined(SHA2_ONLY)
525
/*
526
 * Parse through the input file looking for valid lines.
527
 * If one is found, use this checksum and file as a reference and
528
 * generate a new checksum against the file on the filesystem.
529
 * Print out the result of each comparison.
530
 */
531
int
532
digest_filelist(const char *file, struct hash_function *defhash, int selcount,
533
    char **sel)
534
{
535
	int found, base64, error, cmp, i;
536
	size_t algorithm_max, algorithm_min;
537
	const char *algorithm;
538
	char *filename, *checksum, *buf, *p;
539
	char digest[MAX_DIGEST_LEN + 1];
540
	char *lbuf = NULL;
541
	FILE *listfp, *fp;
542
	size_t len, nread;
543
	u_char data[32 * 1024];
544
	union ANY_CTX context;
545
	struct hash_function *hf;
546
547
	if (strcmp(file, "-") == 0) {
548
		listfp = stdin;
549
	} else if ((listfp = fopen(file, "r")) == NULL) {
550
		warn("cannot open %s", file);
551
		return(1);
552
	}
553
554
	algorithm_max = algorithm_min = strlen(functions[0].name);
555
	for (hf = &functions[1]; hf->name != NULL; hf++) {
556
		len = strlen(hf->name);
557
		algorithm_max = MAXIMUM(algorithm_max, len);
558
		algorithm_min = MINIMUM(algorithm_min, len);
559
	}
560
561
	error = found = 0;
562
	while ((buf = fgetln(listfp, &len))) {
563
		base64 = 0;
564
		if (buf[len - 1] == '\n')
565
			buf[len - 1] = '\0';
566
		else {
567
			if ((lbuf = malloc(len + 1)) == NULL)
568
				err(1, NULL);
569
570
			(void)memcpy(lbuf, buf, len);
571
			lbuf[len] = '\0';
572
			buf = lbuf;
573
		}
574
		while (isspace((unsigned char)*buf))
575
			buf++;
576
577
		/*
578
		 * Crack the line into an algorithm, filename, and checksum.
579
		 * Lines are of the form:
580
		 *  ALGORITHM (FILENAME) = CHECKSUM
581
		 *
582
		 * Fallback on GNU form:
583
		 *  CHECKSUM  FILENAME
584
		 */
585
		p = strchr(buf, ' ');
586
		if (p != NULL && *(p + 1) == '(') {
587
			/* BSD form */
588
			*p = '\0';
589
			algorithm = buf;
590
			len = strlen(algorithm);
591
			if (len > algorithm_max || len < algorithm_min)
592
				continue;
593
594
			filename = p + 2;
595
			p = strrchr(filename, ')');
596
			if (p == NULL || strncmp(p + 1, " = ", (size_t)3) != 0)
597
				continue;
598
			*p = '\0';
599
600
			checksum = p + 4;
601
			p = strpbrk(checksum, " \t\r");
602
			if (p != NULL)
603
				*p = '\0';
604
605
			/*
606
			 * Check that the algorithm is one we recognize.
607
			 */
608
			for (hf = functions; hf->name != NULL; hf++) {
609
				if (strcasecmp(algorithm, hf->name) == 0)
610
					break;
611
			}
612
			if (hf->name == NULL || *checksum == '\0')
613
				continue;
614
			/*
615
			 * Check the length to see if this could be
616
			 * a valid checksum.  If hex, it will be 2x the
617
			 * size of the binary data.  For base64, we have
618
			 * to check both with and without the '=' padding.
619
			 */
620
			len = strlen(checksum);
621
			if (len != hf->digestlen * 2) {
622
				size_t len2;
623
624
				if (checksum[len - 1] == '=') {
625
					/* use padding */
626
					len2 = 4 * ((hf->digestlen + 2) / 3);
627
				} else {
628
					/* no padding */
629
					len2 = (4 * hf->digestlen + 2) / 3;
630
				}
631
				if (len != len2)
632
					continue;
633
				base64 = 1;
634
			}
635
		} else {
636
			/* could be GNU form */
637
			if ((hf = defhash) == NULL)
638
				continue;
639
			algorithm = hf->name;
640
			checksum = buf;
641
			if ((p = strchr(checksum, ' ')) == NULL)
642
				continue;
643
			if (hf->style == STYLE_CKSUM) {
644
				if ((p = strchr(p + 1, ' ')) == NULL)
645
					continue;
646
			}
647
			*p++ = '\0';
648
			while (isspace((unsigned char)*p))
649
				p++;
650
			if (*p == '\0')
651
				continue;
652
			filename = p;
653
			p = strpbrk(filename, "\t\r");
654
			if (p != NULL)
655
				*p = '\0';
656
		}
657
		found = 1;
658
659
		/*
660
		 * If only a selection of files is wanted, proceed only
661
		 * if the filename matches one of those in the selection.
662
		 * Mark found files by setting them to NULL so that we can
663
		 * detect files that are missing from the checklist later.
664
		 */
665
		if (sel) {
666
			for (i = 0; i < selcount; i++) {
667
				if (sel[i] && strcmp(sel[i], filename) == 0) {
668
					sel[i] = NULL;
669
					break;
670
				}
671
			}
672
			if (i == selcount)
673
				continue;
674
		}
675
676
		if ((fp = fopen(filename, "r")) == NULL) {
677
			warn("cannot open %s", filename);
678
			(void)printf("(%s) %s: %s\n", algorithm, filename,
679
			    (errno == ENOENT ? "MISSING" : "FAILED"));
680
			error = 1;
681
			continue;
682
		}
683
684
		hf->init(&context);
685
		while ((nread = fread(data, 1UL, sizeof(data), fp)) > 0)
686
			hf->update(&context, data, (unsigned int)nread);
687
		if (ferror(fp)) {
688
			warn("%s: read error", file);
689
			error = 1;
690
			fclose(fp);
691
			continue;
692
		}
693
		fclose(fp);
694
		digest_end(hf, &context, digest, sizeof(digest), base64);
695
696
		if (base64)
697
			cmp = strncmp(checksum, digest, len);
698
		else
699
			cmp = strcasecmp(checksum, digest);
700
		if (cmp == 0) {
701
			if (qflag == 0)
702
				(void)printf("(%s) %s: OK\n", algorithm,
703
				    filename);
704
		} else {
705
			(void)printf("(%s) %s: FAILED\n", algorithm, filename);
706
			error = 1;
707
		}
708
	}
709
	if (listfp != stdin)
710
		fclose(listfp);
711
	if (!found)
712
		warnx("%s: no properly formatted checksum lines found", file);
713
	free(lbuf);
714
	return(error || !found);
715
}
716
717
#define TEST_BLOCK_LEN 10000
718
#define TEST_BLOCK_COUNT 10000
719
720
void
721
digest_time(struct hash_list *hl, int times)
722
{
723
	struct hash_function *hf;
724
	struct timeval start, stop, res;
725
	union ANY_CTX context;
726
	u_int i;
727
	u_char data[TEST_BLOCK_LEN];
728
	char digest[MAX_DIGEST_LEN + 1];
729
	double elapsed;
730
	int count = TEST_BLOCK_COUNT;
731
	while (--times > 0 && count < INT_MAX / 10)
732
		count *= 10;
733
734
	TAILQ_FOREACH(hf, hl, tailq) {
735
		(void)printf("%s time trial.  Processing %d %d-byte blocks...",
736
		    hf->name, count, TEST_BLOCK_LEN);
737
		fflush(stdout);
738
739
		/* Initialize data based on block number. */
740
		for (i = 0; i < TEST_BLOCK_LEN; i++)
741
			data[i] = (u_char)(i & 0xff);
742
743
		gettimeofday(&start, NULL);
744
		hf->init(&context);
745
		for (i = 0; i < count; i++)
746
			hf->update(&context, data, TEST_BLOCK_LEN);
747
		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
748
		gettimeofday(&stop, NULL);
749
		timersub(&stop, &start, &res);
750
		elapsed = res.tv_sec + res.tv_usec / 1000000.0;
751
752
		(void)printf("\nDigest = %s\n", digest);
753
		(void)printf("Time   = %f seconds\n", elapsed);
754
		(void)printf("Speed  = %f bytes/second\n",
755
		    (double)TEST_BLOCK_LEN * count / elapsed);
756
	}
757
}
758
759
void
760
digest_test(struct hash_list *hl)
761
14
{
762
	struct hash_function *hf;
763
	union ANY_CTX context;
764
	int i;
765
	char digest[MAX_DIGEST_LEN + 1];
766
	unsigned char buf[1000];
767
	unsigned const char *test_strings[] = {
768
		"",
769
		"a",
770
		"abc",
771
		"message digest",
772
		"abcdefghijklmnopqrstuvwxyz",
773
		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
774
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
775
		    "0123456789",
776
		"12345678901234567890123456789012345678901234567890123456789"
777
		    "012345678901234567890",
778
14
	};
779
780
28
	TAILQ_FOREACH(hf, hl, tailq) {
781
14
		(void)printf("%s test suite:\n", hf->name);
782
783
126
		for (i = 0; i < 8; i++) {
784
112
			hf->init(&context);
785
112
			hf->update((void *)&context, test_strings[i],
786
			    (unsigned int)strlen(test_strings[i]));
787
112
			digest_end(hf, &context, digest, sizeof(digest),
788
			    hf->base64);
789
112
			digest_printstr(hf, test_strings[i], digest);
790
		}
791
792
		/* Now simulate a string of a million 'a' characters. */
793
14
		memset(buf, 'a', sizeof(buf));
794
14
		hf->init(&context);
795
14014
		for (i = 0; i < 1000; i++)
796
14000
			hf->update(&context, buf,
797
			    (unsigned int)sizeof(buf));
798
14
		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
799
14
		digest_print(hf, "one million 'a' characters",
800
		    digest);
801
	}
802
14
}
803
#endif /* !defined(SHA2_ONLY) */
804
805
void
806
usage(void)
807
4
{
808
#if !defined(SHA2_ONLY)
809
4
	if (strcmp(__progname, "cksum") == 0)
810
		fprintf(stderr, "usage: %s [-bcpqrtx] [-a algorithms] [-C checklist] "
811
		    "[-h hashfile]\n"
812
		    "	[-s string] [file ...]\n",
813
		    __progname);
814
	else
815
#endif /* !defined(SHA2_ONLY) */
816
4
		fprintf(stderr, "usage:"
817
		    "\t%s [-bcpqrtx] [-C checklist] [-h hashfile] [-s string] "
818
		    "[file ...]\n",
819
		    __progname);
820
821
4
	exit(EXIT_FAILURE);
822
}