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