1 /* $OpenBSD: md5.c,v 1.88 2016/12/16 17:44:59 krw 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; 213 #if !defined(SHA2_ONLY) 214 int i; 215 #endif 216 int bflag, cflag, pflag, rflag, tflag, xflag; 217 218 if (pledge("stdio rpath wpath cpath", NULL) == -1) 219 err(1, "pledge"); 220 221 TAILQ_INIT(&hl); 222 input_string = NULL; 223 selective_checklist = NULL; 224 error = bflag = cflag = pflag = qflag = rflag = tflag = xflag = 0; 225 226 #if !defined(SHA2_ONLY) 227 if (strcmp(__progname, "cksum") == 0) 228 optstr = "a:bC:ch:pqrs:tx"; 229 else 230 #endif /* !defined(SHA2_ONLY) */ 231 optstr = "bC:ch:pqrs:tx"; 232 233 /* Check for -b option early since it changes behavior. */ 234 while ((fl = getopt(argc, argv, optstr)) != -1) { 235 switch (fl) { 236 case 'b': 237 bflag = 1; 238 break; 239 case '?': 240 usage(); 241 } 242 } 243 optind = 1; 244 optreset = 1; 245 while ((fl = getopt(argc, argv, optstr)) != -1) { 246 switch (fl) { 247 case 'a': 248 while ((cp = strsep(&optarg, " \t,")) != NULL) { 249 if (*cp == '\0') 250 continue; 251 base64 = -1; 252 for (hf = functions; hf->name != NULL; hf++) { 253 len = strlen(hf->name); 254 if (strncasecmp(cp, hf->name, len) != 0) 255 continue; 256 if (cp[len] == '\0') { 257 if (hf->base64 != -1) 258 base64 = bflag; 259 break; /* exact match */ 260 } 261 if (cp[len + 1] == '\0' && 262 (cp[len] == 'b' || cp[len] == 'x')) { 263 base64 = 264 cp[len] == 'b' ? 1 : 0; 265 break; /* match w/ suffix */ 266 } 267 } 268 if (hf->name == NULL) { 269 warnx("unknown algorithm \"%s\"", cp); 270 usage(); 271 } 272 if (hf->base64 == -1 && base64 != -1) { 273 warnx("%s doesn't support %s", 274 hf->name, 275 base64 ? "base64" : "hex"); 276 usage(); 277 } 278 /* Check for dupes. */ 279 TAILQ_FOREACH(hftmp, &hl, tailq) { 280 if (hftmp->base64 == base64 && 281 strcmp(hf->name, hftmp->name) == 0) 282 break; 283 } 284 if (hftmp == NULL) 285 hash_insert(&hl, hf, base64); 286 } 287 break; 288 case 'b': 289 /* has already been parsed */ 290 break; 291 case 'h': 292 ofile = fopen(optarg, "w"); 293 if (ofile == NULL) 294 err(1, "%s", optarg); 295 break; 296 #if !defined(SHA2_ONLY) 297 case 'C': 298 selective_checklist = optarg; 299 break; 300 case 'c': 301 cflag = 1; 302 break; 303 #endif /* !defined(SHA2_ONLY) */ 304 case 'p': 305 pflag = 1; 306 break; 307 case 'q': 308 qflag = 1; 309 break; 310 case 'r': 311 rflag = 1; 312 break; 313 case 's': 314 input_string = optarg; 315 break; 316 case 't': 317 tflag++; 318 break; 319 case 'x': 320 xflag = 1; 321 break; 322 default: 323 usage(); 324 } 325 } 326 argc -= optind; 327 argv += optind; 328 329 if (ofile == NULL) 330 ofile = stdout; 331 332 if (pledge("stdio rpath", NULL) == -1) 333 err(1, "pledge"); 334 335 /* Most arguments are mutually exclusive */ 336 fl = pflag + (tflag ? 1 : 0) + xflag + cflag + (input_string != NULL); 337 if (fl > 1 || (fl && argc && cflag == 0) || (rflag && qflag) || 338 (selective_checklist != NULL && argc == 0)) 339 usage(); 340 if (selective_checklist || cflag) { 341 if (TAILQ_FIRST(&hl) != TAILQ_LAST(&hl, hash_list)) 342 errx(1, "only a single algorithm may be specified " 343 "in -C or -c mode"); 344 } 345 346 /* No algorithm specified, check the name we were called as. */ 347 if (TAILQ_EMPTY(&hl)) { 348 for (hf = functions; hf->name != NULL; hf++) { 349 if (strcasecmp(hf->name, __progname) == 0) 350 break; 351 } 352 if (hf->name == NULL) 353 hf = &functions[0]; /* default to cksum */ 354 hash_insert(&hl, hf, (hf->base64 == -1 ? 0 : bflag)); 355 } 356 357 if (rflag || qflag) { 358 const int new_style = rflag ? STYLE_CKSUM : STYLE_TERSE; 359 TAILQ_FOREACH(hf, &hl, tailq) { 360 hf->style = new_style; 361 } 362 } 363 364 #if !defined(SHA2_ONLY) 365 if (tflag) 366 digest_time(&hl, tflag); 367 else if (xflag) 368 digest_test(&hl); 369 else if (input_string) 370 digest_string(input_string, &hl); 371 else if (selective_checklist) { 372 error = digest_filelist(selective_checklist, TAILQ_FIRST(&hl), 373 argc, argv); 374 for (i = 0; i < argc; i++) { 375 if (argv[i] != NULL) { 376 warnx("%s does not exist in %s", argv[i], 377 selective_checklist); 378 error++; 379 } 380 } 381 } else if (cflag) { 382 if (argc == 0) 383 error = digest_filelist("-", TAILQ_FIRST(&hl), 0, NULL); 384 else 385 while (argc--) 386 error += digest_filelist(*argv++, 387 TAILQ_FIRST(&hl), 0, NULL); 388 } else 389 #endif /* !defined(SHA2_ONLY) */ 390 if (pflag || argc == 0) 391 error = digest_file("-", &hl, pflag); 392 else 393 while (argc--) 394 error += digest_file(*argv++, &hl, 0); 395 396 return(error ? EXIT_FAILURE : EXIT_SUCCESS); 397 } 398 399 void 400 hash_insert(struct hash_list *hl, struct hash_function *hf, int base64) 401 { 402 struct hash_function *hftmp; 403 404 hftmp = malloc(sizeof(*hftmp)); 405 if (hftmp == NULL) 406 err(1, NULL); 407 *hftmp = *hf; 408 hftmp->base64 = base64; 409 TAILQ_INSERT_TAIL(hl, hftmp, tailq); 410 } 411 412 void 413 digest_end(const struct hash_function *hf, void *ctx, char *buf, size_t bsize, 414 int base64) 415 { 416 u_char *digest; 417 418 if (base64 == 1) { 419 if ((digest = malloc(hf->digestlen)) == NULL) 420 err(1, NULL); 421 hf->final(digest, ctx); 422 if (b64_ntop(digest, hf->digestlen, buf, bsize) == -1) 423 errx(1, "error encoding base64"); 424 memset(digest, 0, hf->digestlen); 425 free(digest); 426 } else { 427 hf->end(ctx, buf); 428 } 429 } 430 431 #if !defined(SHA2_ONLY) 432 void 433 digest_string(char *string, struct hash_list *hl) 434 { 435 struct hash_function *hf; 436 char digest[MAX_DIGEST_LEN + 1]; 437 union ANY_CTX context; 438 439 TAILQ_FOREACH(hf, hl, tailq) { 440 hf->init(&context); 441 hf->update(&context, string, strlen(string)); 442 digest_end(hf, &context, digest, sizeof(digest), 443 hf->base64); 444 digest_printstr(hf, string, digest); 445 } 446 } 447 #endif /* !defined(SHA2_ONLY) */ 448 449 void 450 digest_print(const struct hash_function *hf, const char *what, 451 const char *digest) 452 { 453 switch (hf->style) { 454 case STYLE_MD5: 455 (void)fprintf(ofile, "%s (%s) = %s\n", hf->name, what, digest); 456 break; 457 case STYLE_CKSUM: 458 (void)fprintf(ofile, "%s %s\n", digest, what); 459 break; 460 case STYLE_TERSE: 461 (void)fprintf(ofile, "%s\n", digest); 462 break; 463 } 464 } 465 466 #if !defined(SHA2_ONLY) 467 void 468 digest_printstr(const struct hash_function *hf, const char *what, 469 const char *digest) 470 { 471 switch (hf->style) { 472 case STYLE_MD5: 473 (void)fprintf(ofile, "%s (\"%s\") = %s\n", hf->name, what, digest); 474 break; 475 case STYLE_CKSUM: 476 (void)fprintf(ofile, "%s %s\n", digest, what); 477 break; 478 case STYLE_TERSE: 479 (void)fprintf(ofile, "%s\n", digest); 480 break; 481 } 482 } 483 #endif /* !defined(SHA2_ONLY) */ 484 485 int 486 digest_file(const char *file, struct hash_list *hl, int echo) 487 { 488 struct hash_function *hf; 489 FILE *fp; 490 size_t nread; 491 u_char data[32 * 1024]; 492 char digest[MAX_DIGEST_LEN + 1]; 493 494 if (strcmp(file, "-") == 0) 495 fp = stdin; 496 else if ((fp = fopen(file, "r")) == NULL) { 497 warn("cannot open %s", file); 498 return(1); 499 } 500 501 TAILQ_FOREACH(hf, hl, tailq) { 502 if ((hf->ctx = malloc(sizeof(union ANY_CTX))) == NULL) 503 err(1, NULL); 504 hf->init(hf->ctx); 505 } 506 while ((nread = fread(data, 1UL, sizeof(data), fp)) != 0) { 507 if (echo) { 508 (void)fwrite(data, nread, 1UL, stdout); 509 if (fflush(stdout) != 0) 510 err(1, "stdout: write error"); 511 } 512 TAILQ_FOREACH(hf, hl, tailq) 513 hf->update(hf->ctx, data, nread); 514 } 515 if (ferror(fp)) { 516 warn("%s: read error", file); 517 if (fp != stdin) 518 fclose(fp); 519 TAILQ_FOREACH(hf, hl, tailq) { 520 free(hf->ctx); 521 hf->ctx = NULL; 522 } 523 return(1); 524 } 525 if (fp != stdin) 526 fclose(fp); 527 TAILQ_FOREACH(hf, hl, tailq) { 528 digest_end(hf, hf->ctx, digest, sizeof(digest), hf->base64); 529 free(hf->ctx); 530 hf->ctx = NULL; 531 if (fp == stdin) 532 fprintf(ofile, "%s\n", digest); 533 else 534 digest_print(hf, file, digest); 535 } 536 return(0); 537 } 538 539 #if !defined(SHA2_ONLY) 540 /* 541 * Parse through the input file looking for valid lines. 542 * If one is found, use this checksum and file as a reference and 543 * generate a new checksum against the file on the filesystem. 544 * Print out the result of each comparison. 545 */ 546 int 547 digest_filelist(const char *file, struct hash_function *defhash, int selcount, 548 char **sel) 549 { 550 int found, base64, error, cmp, i; 551 size_t algorithm_max, algorithm_min; 552 const char *algorithm; 553 char *filename, *checksum, *buf, *p; 554 char digest[MAX_DIGEST_LEN + 1]; 555 char *lbuf = NULL; 556 FILE *listfp, *fp; 557 size_t len, nread; 558 u_char data[32 * 1024]; 559 union ANY_CTX context; 560 struct hash_function *hf; 561 562 if (strcmp(file, "-") == 0) { 563 listfp = stdin; 564 } else if ((listfp = fopen(file, "r")) == NULL) { 565 warn("cannot open %s", file); 566 return(1); 567 } 568 569 algorithm_max = algorithm_min = strlen(functions[0].name); 570 for (hf = &functions[1]; hf->name != NULL; hf++) { 571 len = strlen(hf->name); 572 algorithm_max = MAXIMUM(algorithm_max, len); 573 algorithm_min = MINIMUM(algorithm_min, len); 574 } 575 576 error = found = 0; 577 while ((buf = fgetln(listfp, &len))) { 578 base64 = 0; 579 if (buf[len - 1] == '\n') 580 buf[len - 1] = '\0'; 581 else { 582 if ((lbuf = malloc(len + 1)) == NULL) 583 err(1, NULL); 584 585 (void)memcpy(lbuf, buf, len); 586 lbuf[len] = '\0'; 587 buf = lbuf; 588 } 589 while (isspace((unsigned char)*buf)) 590 buf++; 591 592 /* 593 * Crack the line into an algorithm, filename, and checksum. 594 * Lines are of the form: 595 * ALGORITHM (FILENAME) = CHECKSUM 596 * 597 * Fallback on GNU form: 598 * CHECKSUM FILENAME 599 */ 600 p = strchr(buf, ' '); 601 if (p != NULL && *(p + 1) == '(') { 602 /* BSD form */ 603 *p = '\0'; 604 algorithm = buf; 605 len = strlen(algorithm); 606 if (len > algorithm_max || len < algorithm_min) 607 continue; 608 609 filename = p + 2; 610 p = strrchr(filename, ')'); 611 if (p == NULL || strncmp(p + 1, " = ", (size_t)3) != 0) 612 continue; 613 *p = '\0'; 614 615 checksum = p + 4; 616 p = strpbrk(checksum, " \t\r"); 617 if (p != NULL) 618 *p = '\0'; 619 620 /* 621 * Check that the algorithm is one we recognize. 622 */ 623 for (hf = functions; hf->name != NULL; hf++) { 624 if (strcasecmp(algorithm, hf->name) == 0) 625 break; 626 } 627 if (hf->name == NULL || *checksum == '\0') 628 continue; 629 /* 630 * Check the length to see if this could be 631 * a valid checksum. If hex, it will be 2x the 632 * size of the binary data. For base64, we have 633 * to check both with and without the '=' padding. 634 */ 635 len = strlen(checksum); 636 if (len != hf->digestlen * 2) { 637 size_t len2; 638 639 if (checksum[len - 1] == '=') { 640 /* use padding */ 641 len2 = 4 * ((hf->digestlen + 2) / 3); 642 } else { 643 /* no padding */ 644 len2 = (4 * hf->digestlen + 2) / 3; 645 } 646 if (len != len2) 647 continue; 648 base64 = 1; 649 } 650 } else { 651 /* could be GNU form */ 652 if ((hf = defhash) == NULL) 653 continue; 654 algorithm = hf->name; 655 checksum = buf; 656 if ((p = strchr(checksum, ' ')) == NULL) 657 continue; 658 if (hf->style == STYLE_CKSUM) { 659 if ((p = strchr(p + 1, ' ')) == NULL) 660 continue; 661 } 662 *p++ = '\0'; 663 while (isspace((unsigned char)*p)) 664 p++; 665 if (*p == '\0') 666 continue; 667 filename = p; 668 p = strpbrk(filename, "\t\r"); 669 if (p != NULL) 670 *p = '\0'; 671 } 672 found = 1; 673 674 /* 675 * If only a selection of files is wanted, proceed only 676 * if the filename matches one of those in the selection. 677 * Mark found files by setting them to NULL so that we can 678 * detect files that are missing from the checklist later. 679 */ 680 if (sel) { 681 for (i = 0; i < selcount; i++) { 682 if (sel[i] && strcmp(sel[i], filename) == 0) { 683 sel[i] = NULL; 684 break; 685 } 686 } 687 if (i == selcount) 688 continue; 689 } 690 691 if ((fp = fopen(filename, "r")) == NULL) { 692 warn("cannot open %s", filename); 693 (void)printf("(%s) %s: %s\n", algorithm, filename, 694 (errno == ENOENT ? "MISSING" : "FAILED")); 695 error = 1; 696 continue; 697 } 698 699 hf->init(&context); 700 while ((nread = fread(data, 1UL, sizeof(data), fp)) > 0) 701 hf->update(&context, data, nread); 702 if (ferror(fp)) { 703 warn("%s: read error", file); 704 error = 1; 705 fclose(fp); 706 continue; 707 } 708 fclose(fp); 709 digest_end(hf, &context, digest, sizeof(digest), base64); 710 711 if (base64) 712 cmp = strncmp(checksum, digest, len); 713 else 714 cmp = strcasecmp(checksum, digest); 715 if (cmp == 0) { 716 if (qflag == 0) 717 (void)printf("(%s) %s: OK\n", algorithm, 718 filename); 719 } else { 720 (void)printf("(%s) %s: FAILED\n", algorithm, filename); 721 error = 1; 722 } 723 } 724 if (listfp != stdin) 725 fclose(listfp); 726 if (!found) 727 warnx("%s: no properly formatted checksum lines found", file); 728 free(lbuf); 729 return(error || !found); 730 } 731 732 #define TEST_BLOCK_LEN 10000 733 #define TEST_BLOCK_COUNT 10000 734 735 void 736 digest_time(struct hash_list *hl, int times) 737 { 738 struct hash_function *hf; 739 struct timeval start, stop, res; 740 union ANY_CTX context; 741 u_int i; 742 u_char data[TEST_BLOCK_LEN]; 743 char digest[MAX_DIGEST_LEN + 1]; 744 double elapsed; 745 int count = TEST_BLOCK_COUNT; 746 while (--times > 0 && count < INT_MAX / 10) 747 count *= 10; 748 749 TAILQ_FOREACH(hf, hl, tailq) { 750 (void)printf("%s time trial. Processing %d %d-byte blocks...", 751 hf->name, count, TEST_BLOCK_LEN); 752 fflush(stdout); 753 754 /* Initialize data based on block number. */ 755 for (i = 0; i < TEST_BLOCK_LEN; i++) 756 data[i] = (u_char)(i & 0xff); 757 758 gettimeofday(&start, NULL); 759 hf->init(&context); 760 for (i = 0; i < count; i++) 761 hf->update(&context, data, (size_t)TEST_BLOCK_LEN); 762 digest_end(hf, &context, digest, sizeof(digest), hf->base64); 763 gettimeofday(&stop, NULL); 764 timersub(&stop, &start, &res); 765 elapsed = res.tv_sec + res.tv_usec / 1000000.0; 766 767 (void)printf("\nDigest = %s\n", digest); 768 (void)printf("Time = %f seconds\n", elapsed); 769 (void)printf("Speed = %f bytes/second\n", 770 (double)TEST_BLOCK_LEN * count / elapsed); 771 } 772 } 773 774 void 775 digest_test(struct hash_list *hl) 776 { 777 struct hash_function *hf; 778 union ANY_CTX context; 779 int i; 780 char digest[MAX_DIGEST_LEN + 1]; 781 unsigned char buf[1000]; 782 unsigned const char *test_strings[] = { 783 "", 784 "a", 785 "abc", 786 "message digest", 787 "abcdefghijklmnopqrstuvwxyz", 788 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 789 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 790 "0123456789", 791 "12345678901234567890123456789012345678901234567890123456789" 792 "012345678901234567890", 793 }; 794 795 TAILQ_FOREACH(hf, hl, tailq) { 796 (void)printf("%s test suite:\n", hf->name); 797 798 for (i = 0; i < 8; i++) { 799 hf->init(&context); 800 hf->update(&context, test_strings[i], 801 strlen(test_strings[i])); 802 digest_end(hf, &context, digest, sizeof(digest), 803 hf->base64); 804 digest_printstr(hf, test_strings[i], digest); 805 } 806 807 /* Now simulate a string of a million 'a' characters. */ 808 memset(buf, 'a', sizeof(buf)); 809 hf->init(&context); 810 for (i = 0; i < 1000; i++) 811 hf->update(&context, buf, sizeof(buf)); 812 digest_end(hf, &context, digest, sizeof(digest), hf->base64); 813 digest_print(hf, "one million 'a' characters", 814 digest); 815 } 816 } 817 #endif /* !defined(SHA2_ONLY) */ 818 819 void 820 usage(void) 821 { 822 #if !defined(SHA2_ONLY) 823 if (strcmp(__progname, "cksum") == 0) 824 fprintf(stderr, "usage: %s [-bcpqrtx] [-a algorithms] [-C checklist] " 825 "[-h hashfile]\n" 826 " [-s string] [file ...]\n", 827 __progname); 828 else 829 #endif /* !defined(SHA2_ONLY) */ 830 fprintf(stderr, "usage:" 831 "\t%s [-bcpqrtx] [-C checklist] [-h hashfile] [-s string] " 832 "[file ...]\n", 833 __progname); 834 835 exit(EXIT_FAILURE); 836 } 837