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