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! :-)
29 * NOTE: The version information below refers to all shs1 code, not
30 * just this file. In particular, this file was created by
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
44 * better error messages
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
57 * fixed even/odd byte split bug
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
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
87 * Version 2.7: 13 Jan 1994 Landon Curt Noll
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
98 * performance improvements
99 * removed blocking and feedback code
100 * count bytes in driver, convert to 64 bit count in final transform
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
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
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.
151 #include <sys/types.h>
153 #include <sys/time.h>
154 #include <sys/resource.h>
158 /* size of test in megabytes */
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}
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
[] = {
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
[] = {
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 */
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
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"
219 shs1Output(char *str
, int quot
, int hexhdr
, int trail
, SHS1_INFO
*dig
)
222 * finalize the digest
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);
237 shs1Print(hexhdr
, trail
, dig
);
238 if (str
&& !q_flag
) {
240 printf(" \"%s\"\n", str
);
242 printf(" %s\n", str
);
252 * shs1Print - print a digest in hex
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".
266 shs1Print(int hexhdr
, int trail
, SHS1_INFO
*shs1Info
)
271 printf("%08x%08x%08x%08x%08x",
272 shs1Info
->digest
[0], shs1Info
->digest
[1], shs1Info
->digest
[2],
273 shs1Info
->digest
[3], shs1Info
->digest
[4]);
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
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 */
299 * initialize test data
301 for (i
= 0; i
< SHS1_READSIZE
; i
++) {
302 ((BYTE
*)data
)[i
] = (BYTE
)(i
& 0xFF);
309 printf("shs1 time trial for %d megs of test data ...", TEST_MEG
);
314 * digest data in SHS1_READSIZE byte chunks
316 getrusage(RUSAGE_SELF
, &start
);
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;
332 shs1Print(0, 0, &shs1Info
);
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
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 */
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
);
366 strcpy((char *)t
->data
, (char *)t
->ro_data
);
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) {
384 "%s: cannot find %s or %s/%s\n", program
, *f
, TLIB
, *f
);
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
) {
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
) {
404 shs1File(NULL
, 0, *f
, 0, &digest
);
405 shs1Output(*f
, 0, c_flag
, i_flag
, &digest
);
412 * shs1PreFileRead - read and process a prepend file
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.
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",
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);
444 fprintf(stderr
, "%s: malloc #3 failed\n", program
);
448 /* open our pre_file */
449 pre
= fopen(pre_file
, "rb");
451 fprintf(stderr
, "%s: unable to open prepend file %s\n",
456 /* read our pre_file data */
457 bytes
= fread((char *)(*buf
), 1, pre_len
, pre
);
458 if (bytes
!= pre_len
) {
460 "%s: unable to read %d bytes from prepend file %s\n",
461 program
, pre_len
, pre_file
);
465 /* return our length */
471 * shs1Help - print shs1 help message and exit
477 "%s [-cCd%shimqtx][-p prefix][-P pfile][-s str] [file ...]\n",
486 " -c print C style digests with a leading 0x\n");
488 " -C do not space seperate multi digests\n");
490 " -d same as -m 2\n");
496 " -h prints this message\n");
498 " -i process inode and filename as well as file data\n");
500 " -m num process num digests on every num-th byte\n");
502 " -p prefix prepend str to data before digesting\n");
504 " -P pfile prepend the file 'str' to data before digesting\n");
506 " -q print only the digest\n");
508 " -r reverse feedback mode\n");
510 " -s str prints digest and contents of string\n");
512 " -t prints time statistics for %dM chars\n", TEST_MEG
);
514 " -v print version\n");
516 " -x execute an extended standard suite of test data\n");
518 " file print digest and name of file\n");
520 " (no args) print digest of stdin\n");
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 */
551 while ((c
= getopt(argc
, argv
, "cCdDihm:p:P:qs:tvx")) != -1) {
567 fprintf(stderr
, "%s: not compiled with -DDEBUG\n", program
);
581 multi
= atoi(optarg
);
584 pre_str
= (BYTE
*)optarg
;
599 printf("%s: version %s\n", program
, SHS1_VERSION
);
610 if (data_str
&& optind
!= argc
) {
611 fprintf(stderr
, "%s: -s is not compatible with digesting files\n",
615 if (i_flag
&& optind
== argc
) {
616 fprintf(stderr
, "%s: -i works only on filenames\n", program
);
619 if (d_flag
&& m_flag
) {
620 fprintf(stderr
, "%s: -d imples -m 2, use one or the other\n", program
);
623 if ((d_flag
|| m_flag
) && multi
< 2) {
624 fprintf(stderr
, "%s: multi count must be > 1\n", program
);
627 if (C_flag
&& !d_flag
&& !m_flag
) {
628 fprintf(stderr
, "%s: -C requires -d or -m num\n", program
);
633 * process -x if needed
645 * process -t if needed
653 * process -P or -p if needed
655 if (pre_str
&& pre_file
) {
656 fprintf(stderr
, "%s: -p and -P conflict\n", program
);
660 pre_str_len
= shs1PreFileRead(pre_file
, &pre_str
);
661 } else if (pre_str
) {
662 pre_str_len
= strlen((char *)pre_str
);
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
);
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
,
680 * if no -d and no -m num, process string, stdin or files
685 * case: digest a string
687 if (data_str
!= NULL
) {
688 data_str_len
= strlen(data_str
);
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
);
697 } else if (optind
== argc
) {
699 shs1Stream(pre_str
, pre_str_len
, stdin
, &digest
);
700 shs1Output(NULL
, 0, c_flag
, i_flag
, &digest
);
706 for (; optind
< argc
; optind
++) {
708 shs1File(pre_str
, pre_str_len
, argv
[optind
], i_flag
, &digest
);
709 shs1Output(argv
[optind
], 0, c_flag
, i_flag
, &digest
);