modified: makefile
[GalaxyCodeBases.git] / c_cpp / etc / md5_sha / shs1drvr.c
blob8927f08fa1954cecb91bc01b7d1e6c78ef943b8a
1 /*
2 * shs1drvr - NIST Secure Hash Standard-1 implimentation driver code
4 * @(#) $Revision: 13.4 $
5 * @(#) $Id: shs1drvr.c,v 13.4 2010/10/12 21:09:35 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/shs1drvr.c,v $
8 * This file was written by Landon Curt Noll.
10 * This code has been placed in the public domain. Please do not
11 * copyright this code.
13 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
14 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
15 * CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
16 * NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
19 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * chongo (was here) /\oo/\
23 * http://www.isthe.com/chongo/index.html
25 * Share and enjoy! :-)
27 ***
29 * NOTE: The version information below refers to all shs1 code, not
30 * just this file. In particular, this file was created by
31 * Landon Curt Noll.
33 * Version 1.1: 02 Sep 1992? original authors
34 * This code is based on code by Peter C. Gutmann. Much thanks goes
35 * to Peter C. Gutman (pgut1@cs.aukuni.ac.nz) , Shawn A. Clifford
36 * (sac@eng.ufl.edu), Pat Myrto (pat@rwing.uucp) and others who wrote
37 * and/or worked on the original code.
39 * Version 2.1: 31 Dec 1993 Landon Curt Noll
40 * Reformatted, performance improvements and bug fixes
42 * Version 2.2: 02 Jan 1994 Landon Curt Noll
43 * fixed -p usage
44 * better error messages
45 * added -c help
46 * added -c 0 (concatenation)
47 * reordered -i stat buffer pre-pending
49 * Version 2.3: 03 Jan 1994 Landon Curt Noll
50 * added -c 1 (side by side)
51 * added -c 2 (even force to be odd)
52 * added -c x (shs1 dual test suite)
53 * changed -c help to be -c h
54 * changed -c operand to type[,opt[,...]]
55 * prefix & string ABI now can take arbitrary binary data
56 * fixed memory leak
57 * fixed even/odd byte split bug
58 * added -P file
59 * added -q
60 * added UNROLL_LOOPS to control shs1.c loop unrolling
61 * major performance improvements
63 * Version 2.4: 05 Jan 1994 Landon Curt Noll
64 * renamed calc mode to dual mode
65 * removed all -c code
66 * added -d (dual digests, space separated)
67 * rewrote most of the file, string and stream logic using shs1dual code
69 * Version 2.5: 08 Jan 1994 Landon Curt Noll
70 * added (new) -c (print 0x in front of digests)
71 * removed st_blksize and st_blocks from -i preprocessing data
72 * only print .0 suffix if -i and digesting a file
73 * non-zero edit codes are now unique
74 * changed the dual test suite (shorter, added non alpha numeric chars)
75 * -i requires filenames
76 * fixed @(#) what string code
77 * boolean logic simplication by Rich Schroeppel (rcs@cs.arizona.edu)
78 * on the fly in a circular buffer by Colin Plumb (colin@nyx10.cs.du.edu)
80 * Version 2.6: 11 Jan 1994 Landon Curt Noll
81 * Merged the shs1 and md5 Makefiles to build both in the same directory
82 * alignment and byte order performance improvements
83 * eliminate wateful memory copies
84 * shs1 transform contains no function calls
85 * beta release
87 * Version 2.7: 13 Jan 1994 Landon Curt Noll
88 * code cleanup
89 * chunk is now 64 bytes, block is determined by blocking factor
90 * magic 64 and 64 related values defined in terms of #defines
91 * added blocking code (-b block_len)
92 * added xor feedback code (-f)
93 * added xor feedback and block options to performance test
94 * performance improvements
96 * Version 2.8: 16 Jan 1994 Landon Curt Noll
97 * code cleanup
98 * performance improvements
99 * removed blocking and feedback code
100 * count bytes in driver, convert to 64 bit count in final transform
101 * added debug mode
102 * handle read errors and EOF better
103 * prefix strings not multiple of 64 bytes in length do not slow down hash
104 * renumbered exit codes
105 * fixed dual digest split bug
106 * byte sex swapping is now controlled thru the SHS1_TRANSFORM macro
107 * shs1Transform() is now called via the SHS1_TRANSFORM macro
109 * Version 2.9: 12 Feb 1994 Landon Curt Noll
110 * prep for beta release
111 * removed all feedback code
113 * Version 2.10: 25 Mar 1994 Landon Curt Noll
114 * must_align catchs signal to detect misaligned access
116 * Version 3.1: 09 Mar 1995 Landon Curt Noll
117 * Changed to implement the new Secure Hash Standard-1 (SHS1).
118 * The Secure Hash Standard-1 (SHS1) is a United States Department
119 * of Commerce National Institute of Standards and Technology approved
120 * standard (FIPS Pub 180-1).
122 * The only substantial change was made to the exor() macro in shs1.c
123 * Changed name to shs1. Bumped version from 2.10 to 3.1.
125 * Moved stream and file routines into shs1io.c.
127 * Version 3.2: 17 Nov 1995 Landon Curt Noll
128 * Fixed help string.
130 * Added multiple digests capability instead of just dual. Added
131 * -m num to denote 2 or more multiple digests.
133 * Added -C to prevent spaces (and later 0x if -c) between multi digests.
135 * Version 3.3: 01 Sep 1996 Landon Curt Noll
136 * Provide sha1 as well as shs1.
138 * Version 4.0: 13 Aug 2006 Landon Curt Noll
139 * Port to ANSI C.
140 * Fixed all known compile warnings.
141 * Allow access to the internal hash transform function.
142 * The shs1Transform() function performs the byte swapping now.
143 * Eliminated use of SHS1_TRANSFORM macro.
144 * Improved the way -v prints version. Now -v prints the RCS version,
145 * not version listed in the above comment.
148 #include <stdio.h>
149 #include <stdlib.h>
150 #include <string.h>
151 #include <sys/types.h>
152 #include <time.h>
153 #include <sys/time.h>
154 #include <sys/resource.h>
155 #include <unistd.h>
156 #include "shs1.h"
158 /* size of test in megabytes */
159 #define TEST_MEG 16
161 /* number of chunks to process */
162 #define TEST_CHUNKS (TEST_MEG*1024*1024/SHS1_READSIZE)
164 /* SHS1 test suite strings */
165 #define ENTRY(str) {(BYTE *)str, NULL, sizeof(str)-1}
166 struct shs1_test {
167 BYTE *ro_data; /* read only string data or NULL to test */
168 BYTE *data; /* data or NULL to test */
169 int len; /* length of data */
170 } shs1_test_data[] = {
171 ENTRY(""),
172 ENTRY("a"),
173 ENTRY("abc"),
174 ENTRY("message digest"),
175 ENTRY("abcdefghijklmnopqrstuvwxyz"),
176 ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
177 ENTRY("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),
178 ENTRY("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
180 #define MAX_SHS1_TEST_DATA ((int)(sizeof(shs1_test_data)/sizeof(shs1_test_data[0])))
182 /* shs1 test filenames */
183 char *shs1_test_file[] = {
184 "file1",
185 "file2",
187 #define MAX_SHS1_TEST_FILE ((int)(sizeof(shs1_test_file)/sizeof(shs1_test_file[0])))
189 /* where the test files are located by default */
190 #if !defined(TLIB)
191 #define TLIB "."
192 #endif
194 /* Prototypes of the static functions */
195 static void shs1Output(char*, int, int, int, SHS1_INFO*);
196 static int shs1PreFileRead(char*, BYTE**);
197 static void shs1TestSuite(void);
198 static void shs1Help(void);
200 /* global variables */
201 int c_flag = 0; /* 1 => print C style digest with leading 0x */
202 int i_flag = 0; /* 1 => process inode & filename */
203 int q_flag = 0; /* 1 => print the digest only */
204 int debug = 0; /* 1 => add debug */
205 char *program = "<program name unknown>"; /* our name */
209 * shs1Output - output the digest
211 * given:
212 * str print string after digest, NULL => none
213 * quot 1 => surround str with a double quotes
214 * hexhdr 1 => print 0x before the hex value
215 * trail 1 => print a trailing ".0"
216 * dig current digest
218 static void
219 shs1Output(char *str, int quot, int hexhdr, int trail, SHS1_INFO *dig)
222 * finalize the digest
224 shs1Final(dig);
225 #if defined(DEBUG)
226 if (debug) {
227 fprintf(stderr, "DEBUG: octet count: %lld\n", dig->octets);
228 fprintf(stderr, "DEBUG: octet count: 0x%016llx\n", dig->octets);
229 fprintf(stderr, "DEBUG: bit count: %lld\n", dig->octets<<3);
230 fprintf(stderr, "DEBUG: bit count: 0x%016llx\n", dig->octets<<3);
232 #endif
235 * print the digest
237 shs1Print(hexhdr, trail, dig);
238 if (str && !q_flag) {
239 if (quot) {
240 printf(" \"%s\"\n", str);
241 } else {
242 printf(" %s\n", str);
244 } else {
245 putchar('\n');
247 fflush(stdout);
252 * shs1Print - print a digest in hex
254 * given:
255 * hexhdr 1 => print 0x before the hex value
256 * trail 1 => print a trailing ".0"
257 * shs1Info SHA-1 hash state
259 * Prints message digest buffer in shs1Info as 40 hexadecimal digits. Order is
260 * from low-order byte to high-order byte of digest. Each byte is printed
261 * with high-order hexadecimal digit first.
263 * If hexhdr, then print a leading "0x". If trail, then print a trailing ".0".
265 void
266 shs1Print(int hexhdr, int trail, SHS1_INFO *shs1Info)
268 if (hexhdr) {
269 fputs("0x", stdout);
271 printf("%08x%08x%08x%08x%08x",
272 shs1Info->digest[0], shs1Info->digest[1], shs1Info->digest[2],
273 shs1Info->digest[3], shs1Info->digest[4]);
274 if (trail) {
275 fputs(".0", stdout);
281 * shs1TimeTrial - measure the speed of SHS1
283 * Measures user time required to digest TEST_MEG megabytes of characters.
285 * This function will time blocking and under xor feedback mode if they
286 * are set.
288 static void
289 shs1TimeTrial(void)
291 ULONG data[SHS1_READWORDS]; /* test buffer */
292 SHS1_INFO shs1Info; /* hash state */
293 struct rusage start; /* test start time */
294 struct rusage stop; /* test end time */
295 double usrsec; /* duration of test in user seconds */
296 unsigned int i;
299 * initialize test data
301 for (i = 0; i < SHS1_READSIZE; i++) {
302 ((BYTE *)data)[i] = (BYTE)(i & 0xFF);
306 * announce test
308 if (!q_flag) {
309 printf("shs1 time trial for %d megs of test data ...", TEST_MEG);
310 fflush(stdout);
314 * digest data in SHS1_READSIZE byte chunks
316 getrusage(RUSAGE_SELF, &start);
317 shs1Init(&shs1Info);
318 for (i=0; i < TEST_CHUNKS; ++i) {
319 shs1fullUpdate(&shs1Info, (BYTE *)data, SHS1_READSIZE);
321 shs1Final(&shs1Info);
322 getrusage(RUSAGE_SELF, &stop);
325 * announce the test results
327 usrsec = (stop.ru_utime.tv_sec - start.ru_utime.tv_sec) +
328 (double)(stop.ru_utime.tv_usec - start.ru_utime.tv_usec)/1000000.0;
329 if (!q_flag) {
330 putchar('\n');
332 shs1Print(0, 0, &shs1Info);
333 if (q_flag) {
334 putchar('\n');
335 } else {
336 printf(" is digest of test data\n");
337 printf("user seconds to process test data: %.2f\n", usrsec);
338 printf("characters processed per user second: %d\n",
339 (int)((double)TEST_MEG*1024.0*1024.0/usrsec));
345 * shs1TestSuite - run a standard suite of test data
347 static void
348 shs1TestSuite(void)
350 struct shs1_test *t; /* current shs1 test */
351 struct stat buf; /* stat of a test file */
352 SHS1_INFO digest; /* test digest */
353 char **f; /* current file being tested */
354 int i;
357 * copy our test strings into writable data
359 for (i=0, t=shs1_test_data; i < MAX_SHS1_TEST_DATA; ++i, ++t) {
360 if (t->ro_data != NULL) {
361 t->data = (BYTE *)malloc(t->len + 1);
362 if (t->data == NULL) {
363 fprintf(stderr, "%s: malloc #4 failed\n", program);
364 exit(4);
366 strcpy((char *)t->data, (char *)t->ro_data);
371 * print test header
373 puts("shs1 test suite results:");
376 * find all of the test files
378 for (i=0, f=shs1_test_file; i < MAX_SHS1_TEST_FILE; ++i, ++f) {
379 if (stat(*f, &buf) < 0) {
380 /* no file1 in this directory, cd to the test suite directory */
381 if (chdir(TLIB) < 0) {
382 fflush(stdout);
383 fprintf(stderr,
384 "%s: cannot find %s or %s/%s\n", program, *f, TLIB, *f);
385 return;
391 * try all combinations of test strings as prefixes and data
393 for (i=0, t=shs1_test_data; i < MAX_SHS1_TEST_DATA; ++i, ++t) {
394 shs1Init(&digest);
395 shs1Update(&digest, t->data, t->len);
396 shs1Output((char *)t->ro_data, 1, c_flag, i_flag, &digest);
400 * try the files with all test strings as prefixes
402 for (i=0, f=shs1_test_file; i < MAX_SHS1_TEST_FILE; ++i, ++f) {
403 shs1Init(&digest);
404 shs1File(NULL, 0, *f, 0, &digest);
405 shs1Output(*f, 0, c_flag, i_flag, &digest);
407 exit(0);
412 * shs1PreFileRead - read and process a prepend file
414 * given:
415 * pre_file form pre_str from file pre_file
416 * buf pointer to pre_str pointer
418 * Returns the length of pre_str, and modifies pre_str to
419 * point at the malloced prepend data.
421 static int
422 shs1PreFileRead(char *pre_file, BYTE **buf)
424 struct stat statbuf; /* stat for pre_file */
425 int pre_len; /* length of pre_file to be used */
426 int bytes; /* bytes read from pre_file */
427 FILE *pre; /* pre_file descriptor */
429 /* obtain the length that we will use */
430 if (stat(pre_file, &statbuf) < 0) {
431 fprintf(stderr, "%s: unpable to find prepend file %s\n",
432 program, pre_file);
433 exit(5);
435 pre_len = statbuf.st_size;
436 if (pre_len > SHS1_MAX_PRE_FILE) {
437 /* don't use beyond SHS1_MAX_PRE_FILE in size */
438 pre_len = SHS1_MAX_PRE_FILE;
441 /* malloc our pre string */
442 *buf = (BYTE *)malloc(pre_len+1);
443 if (*buf == NULL) {
444 fprintf(stderr, "%s: malloc #3 failed\n", program);
445 exit(6);
448 /* open our pre_file */
449 pre = fopen(pre_file, "rb");
450 if (pre == NULL) {
451 fprintf(stderr, "%s: unable to open prepend file %s\n",
452 program, pre_file);
453 exit(7);
456 /* read our pre_file data */
457 bytes = fread((char *)(*buf), 1, pre_len, pre);
458 if (bytes != pre_len) {
459 fprintf(stderr,
460 "%s: unable to read %d bytes from prepend file %s\n",
461 program, pre_len, pre_file);
462 exit(8);
465 /* return our length */
466 return (pre_len);
471 * shs1Help - print shs1 help message and exit
473 static void
474 shs1Help(void)
476 fprintf(stderr,
477 "%s [-cCd%shimqtx][-p prefix][-P pfile][-s str] [file ...]\n",
478 program,
479 #if defined(DEBUG)
481 #else
483 #endif
485 fprintf(stderr,
486 " -c print C style digests with a leading 0x\n");
487 fprintf(stderr,
488 " -C do not space seperate multi digests\n");
489 fprintf(stderr,
490 " -d same as -m 2\n");
491 #if defined(DEBUG)
492 fprintf(stderr,
493 " -D debug mode\n");
494 #endif
495 fprintf(stderr,
496 " -h prints this message\n");
497 fprintf(stderr,
498 " -i process inode and filename as well as file data\n");
499 fprintf(stderr,
500 " -m num process num digests on every num-th byte\n");
501 fprintf(stderr,
502 " -p prefix prepend str to data before digesting\n");
503 fprintf(stderr,
504 " -P pfile prepend the file 'str' to data before digesting\n");
505 fprintf(stderr,
506 " -q print only the digest\n");
507 fprintf(stderr,
508 " -r reverse feedback mode\n");
509 fprintf(stderr,
510 " -s str prints digest and contents of string\n");
511 fprintf(stderr,
512 " -t prints time statistics for %dM chars\n", TEST_MEG);
513 fprintf(stderr,
514 " -v print version\n");
515 fprintf(stderr,
516 " -x execute an extended standard suite of test data\n");
517 fprintf(stderr,
518 " file print digest and name of file\n");
519 fprintf(stderr,
520 " (no args) print digest of stdin\n");
521 exit(0);
526 * main - shs1 main control function
529 main(int argc, char *argv[])
531 SHS1_INFO digest; /* our current digest */
532 BYTE *pre_str = NULL; /* pre-process this data first */
533 char *pre_file = NULL; /* pre-process this file first */
534 char *data_str = NULL; /* data is this string, not a file */
535 UINT pre_str_len; /* length of pre_str or pre_file */
536 UINT data_str_len; /* length of data_str */
537 int C_flag = 0; /* 1 => don't space seperate multi digests */
538 int d_flag = 0; /* 1 => dual digest mode */
539 int m_flag = 0; /* 1 => multi digest mode */
540 int t_flag = 0; /* 1 => -t was given */
541 int x_flag = 0; /* 1 => -x was given */
542 int multi = 0; /* number of digests to do in parallel */
543 extern char *optarg; /* argument to option */
544 extern int optind; /* option index */
545 int c;
548 * parse args
550 program = argv[0];
551 while ((c = getopt(argc, argv, "cCdDihm:p:P:qs:tvx")) != -1) {
552 switch (c) {
553 case 'c':
554 c_flag = 1;
555 break;
556 case 'C':
557 C_flag = 1;
558 break;
559 case 'd':
560 d_flag = 1;
561 multi = 2;
562 break;
563 case 'D':
564 #if defined(DEBUG)
565 debug = 1;
566 #else
567 fprintf(stderr, "%s: not compiled with -DDEBUG\n", program);
568 exit(9);
569 /*NOTREACHED*/
570 #endif
571 break;
572 case 'h':
573 shs1Help();
574 /*NOTREACHED*/
575 break;
576 case 'i':
577 i_flag = 1;
578 break;
579 case 'm':
580 m_flag = 1;
581 multi = atoi(optarg);
582 break;
583 case 'p':
584 pre_str = (BYTE *)optarg;
585 break;
586 case 'q':
587 q_flag = 1;
588 break;
589 case 'P':
590 pre_file = optarg;
591 break;
592 case 's':
593 data_str = optarg;
594 break;
595 case 't':
596 t_flag = 1;
597 break;
598 case 'v':
599 printf("%s: version %s\n", program, SHS1_VERSION);
600 exit(0);
601 case 'x':
602 x_flag = 1;
603 break;
604 default:
605 shs1Help();
606 break;
609 /* arg checking */
610 if (data_str && optind != argc) {
611 fprintf(stderr, "%s: -s is not compatible with digesting files\n",
612 program);
613 exit(10);
615 if (i_flag && optind == argc) {
616 fprintf(stderr, "%s: -i works only on filenames\n", program);
617 exit(11);
619 if (d_flag && m_flag) {
620 fprintf(stderr, "%s: -d imples -m 2, use one or the other\n", program);
621 exit(12);
623 if ((d_flag || m_flag) && multi < 2) {
624 fprintf(stderr, "%s: multi count must be > 1\n", program);
625 exit(13);
627 if (C_flag && !d_flag && !m_flag) {
628 fprintf(stderr, "%s: -C requires -d or -m num\n", program);
629 exit(14);
633 * process -x if needed
635 if (x_flag) {
636 if (d_flag) {
637 multiTest();
638 } else {
639 shs1TestSuite();
641 exit(0);
645 * process -t if needed
647 if (t_flag) {
648 shs1TimeTrial();
649 exit(0);
653 * process -P or -p if needed
655 if (pre_str && pre_file) {
656 fprintf(stderr, "%s: -p and -P conflict\n", program);
657 exit(15);
659 if (pre_file) {
660 pre_str_len = shs1PreFileRead(pre_file, &pre_str);
661 } else if (pre_str) {
662 pre_str_len = strlen((char *)pre_str);
663 } else {
664 pre_str_len = 0;
666 if (pre_str_len > SHS1_MAX_PRE_FILE) {
667 fprintf(stderr, "%s: prefix may not be longer than %d bytes\n",
668 program, SHS1_MAX_PRE_FILE);
669 exit(15);
673 * if -d of -m num, perform multi digest processing instead
675 if (d_flag || m_flag) {
676 multiMain(argc, argv, pre_str, pre_str_len, data_str, C_flag,
677 (UINT)multi);
680 * if no -d and no -m num, process string, stdin or files
682 } else {
685 * case: digest a string
687 if (data_str != NULL) {
688 data_str_len = strlen(data_str);
689 shs1Init(&digest);
690 shs1Update(&digest, pre_str, pre_str_len);
691 shs1Update(&digest, (BYTE *)data_str, data_str_len);
692 shs1Output(data_str, 1, c_flag, i_flag, &digest);
695 * case: digest stdin
697 } else if (optind == argc) {
698 shs1Init(&digest);
699 shs1Stream(pre_str, pre_str_len, stdin, &digest);
700 shs1Output(NULL, 0, c_flag, i_flag, &digest);
703 * case: digest files
705 } else {
706 for (; optind < argc; optind++) {
707 shs1Init(&digest);
708 shs1File(pre_str, pre_str_len, argv[optind], i_flag, &digest);
709 shs1Output(argv[optind], 0, c_flag, i_flag, &digest);
714 /* all done */
715 /* exit(0); */
716 return 0;