2 * shsdrvr - old shs driver code
4 * @(#) $Revision: 13.4 $
5 * @(#) $Id: shsdrvr.c,v 13.4 2010/10/12 21:09:35 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/shsdrvr.c,v $
8 **************************************************************************
9 * This version implements the old Secure Hash Algorithm specified by *
10 * (FIPS Pub 180). This version is kept for backward compatibility with *
11 * shs version 2.10.1. See the shs utility for the new standard. *
12 **************************************************************************
14 * This file was written by Landon Curt Noll.
16 * This code has been placed in the public domain. Please do not
17 * copyright this code.
19 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
20 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
21 * CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
22 * NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
23 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
25 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 * chongo (was here) /\oo/\
29 * http://www.isthe.com/chongo/index.html
31 * Share and enjoy! :-)
35 * NOTE: The version information below refers to all shs code, not
36 * just this file. In particular, this file was created by
39 * Version 1.1: 02 Sep 1992? original authors
40 * This code is based on code by Peter C. Gutmann. Much thanks goes
41 * to Peter C. Gutman (pgut1@cs.aukuni.ac.nz) , Shawn A. Clifford
42 * (sac@eng.ufl.edu), Pat Myrto (pat@rwing.uucp) and others who wrote
43 * and/or worked on the original code.
45 * Version 2.1: 31 Dec 1993 Landon Curt Noll
46 * Reformatted, performance improvements and bug fixes
48 * Version 2.2: 02 Jan 1994 Landon Curt Noll
50 * better error messages
52 * added -c 0 (concatenation)
53 * reordered -i stat buffer pre-pending
55 * Version 2.3: 03 Jan 1994 Landon Curt Noll
56 * added -c 1 (side by side)
57 * added -c 2 (even force to be odd)
58 * added -c x (shs dual test suite)
59 * changed -c help to be -c h
60 * changed -c operand to type[,opt[,...]]
61 * prefix & string ABI now can take arbitrary binary data
63 * fixed even/odd byte split bug
66 * added UNROLL_LOOPS to control shs.c loop unrolling
67 * major performance improvements
69 * Version 2.4: 05 Jan 1994 Landon Curt Noll
70 * renamed calc mode to dual mode
72 * added -d (dual digests, space separated)
73 * rewrote most of the file, string and stream logic using shsdual code
75 * Version 2.5: 08 Jan 1994 Landon Curt Noll
76 * added (new) -c (print 0x in front of digests)
77 * removed st_blksize and st_blocks from -i preprocessing data
78 * only print .0 suffix if -i and digesting a file
79 * non-zero edit codes are now unique
80 * changed the dual test suite (shorter, added non alpha numeric chars)
81 * -i requires filenames
82 * fixed @(#) what string code
83 * boolean logic simplication by Rich Schroeppel (rcs@cs.arizona.edu)
84 * on the fly in a circular buffer by Colin Plumb (colin@nyx10.cs.du.edu)
86 * Version 2.6: 11 Jan 1994 Landon Curt Noll
87 * Merged the shs and md5 Makefiles to build both in the same directory
88 * alignment and byte order performance improvements
89 * eliminate wateful memory copies
90 * shs transform contains no function calls
93 * Version 2.7: 13 Jan 1994 Landon Curt Noll
95 * chunk is now 64 bytes, block is determined by blocking factor
96 * magic 64 and 64 related values defined in terms of #defines
97 * added blocking code (-b block_len)
98 * added xor feedback code (-f)
99 * added xor feedback and block options to performance test
100 * performance improvements
102 * Version 2.8: 16 Jan 1994 Landon Curt Noll
104 * performance improvements
105 * removed blocking and feedback code
106 * count bytes in driver, convert to 64 bit count in final transform
108 * handle read errors and EOF better
109 * prefix strings not multiple of 64 bytes in length do not slow down hash
110 * renumbered exit codes
111 * fixed dual digest split bug
112 * byte sex swapping is now controlled thru the SHS_TRANSFORM macro
113 * shsTransform() is now called via the SHS_TRANSFORM macro
115 * Version 2.9: 12 Feb 1994 Landon Curt Noll
116 * prep for beta release
117 * removed all feedback code
119 * Version 2.10: 25 Mar 1994 Landon Curt Noll
120 * must_align catchs signal to detect misaligned access
122 * Version 3.1: 09 Mar 1995 Landon Curt Noll
123 * Bumped version from 2.10 to 3.1.
125 * Moved stream and file routines into shsio.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 sha as well as shs.
138 * Version 4.1: 13 Aug 2006 Landon Curt Noll
140 * Fixed all known compile warnings.
141 * Allow access to the internal hash transform function.
142 * The shsTransform() function performs the byte swapping now.
143 * Eliminated use of SHS_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/SHS_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 } shs_test_data
[] = {
174 ENTRY("message digest"),
175 ENTRY("abcdefghijklmnopqrstuvwxyz"),
176 ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
177 ENTRY("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),
178 ENTRY("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
180 #define MAX_SHS_TEST_DATA ((int)(sizeof(shs_test_data)/sizeof(shs_test_data[0])))
182 /* shs test filenames */
183 char *shs_test_file
[] = {
187 #define MAX_SHS_TEST_FILE ((int)(sizeof(shs_test_file)/sizeof(shs_test_file[0])))
189 /* where the test files are located by default */
194 /* Prototypes of the static functions */
195 static void shsOutput(char*, int, int, int, SHS_INFO
*);
196 static int shsPreFileRead(char*, BYTE
**);
197 static void shsTestSuite(void);
198 static void shsHelp(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 * shsOutput - 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 shsOutput(char *str
, int quot
, int hexhdr
, int trail
, SHS_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 shsPrint(hexhdr
, trail
, dig
);
238 if (str
&& !q_flag
) {
240 printf(" \"%s\"\n", str
);
242 printf(" %s\n", str
);
252 * shsPrint - print a digest in hex
254 * Prints message digest buffer in shsInfo as 40 hexadecimal digits. Order is
255 * from low-order byte to high-order byte of digest. Each byte is printed
256 * with high-order hexadecimal digit first.
258 * If hexhdr, then print a leading "0x". If trail, then print a trailing ".0".
261 * hexhdr 1 => print 0x before the hex value
262 * trail 1 => print a trailing ".0"
266 shsPrint(int hexhdr
, int trail
, SHS_INFO
*shsInfo
)
271 printf("%08x%08x%08x%08x%08x",
272 shsInfo
->digest
[0], shsInfo
->digest
[1], shsInfo
->digest
[2],
273 shsInfo
->digest
[3], shsInfo
->digest
[4]);
281 * shsTimeTrial - 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
[SHS_READWORDS
]; /* test buffer */
292 SHS_INFO shsInfo
; /* 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
< SHS_READSIZE
; i
++) {
302 ((BYTE
*)data
)[i
] = (BYTE
)(i
& 0xFF);
309 printf("shs time trial for %d megs of test data ...", TEST_MEG
);
314 * digest data in SHS_READSIZE byte chunks
316 getrusage(RUSAGE_SELF
, &start
);
318 for (i
=0; i
< TEST_CHUNKS
; ++i
) {
319 shsfullUpdate(&shsInfo
, (BYTE
*)data
, SHS_READSIZE
);
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 shsPrint(0, 0, &shsInfo
);
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 * shsTestSuite - run a standard suite of test data
350 struct shs_test
*t
; /* current shs test */
351 struct stat buf
; /* stat of a test file */
352 SHS_INFO digest
; /* test digest */
353 char **f
; /* current file being tested */
357 * copy our test strings into writable data
359 for (i
=0, t
=shs_test_data
; i
< MAX_SHS_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("old shs test suite results:");
376 * find all of the test files
378 for (i
=0, f
=shs_test_file
; i
< MAX_SHS_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
=shs_test_data
; i
< MAX_SHS_TEST_DATA
; ++i
, ++t
) {
395 shsUpdate(&digest
, t
->data
, t
->len
);
396 shsOutput((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
=shs_test_file
; i
< MAX_SHS_TEST_FILE
; ++i
, ++f
) {
404 shsFile(NULL
, 0, *f
, 0, &digest
);
405 shsOutput(*f
, 0, c_flag
, i_flag
, &digest
);
412 * shsPreFileRead - 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 shsPreFileRead(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
> SHS_MAX_PRE_FILE
) {
437 /* don't use beyond SHS_MAX_PRE_FILE in size */
438 pre_len
= SHS_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 * shsHelp - print shs 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 - shs main control function
529 main(int argc
, char *argv
[])
531 SHS_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
, SHS_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
= shsPreFileRead(pre_file
, &pre_str
);
661 } else if (pre_str
) {
662 pre_str_len
= strlen((char *)pre_str
);
666 if (pre_str_len
> SHS_MAX_PRE_FILE
) {
667 fprintf(stderr
, "%s: prefix may not be longer than %d bytes\n",
668 program
, SHS_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 shsUpdate(&digest
, pre_str
, pre_str_len
);
691 shsUpdate(&digest
, (BYTE
*)data_str
, data_str_len
);
692 shsOutput(data_str
, 1, c_flag
, i_flag
, &digest
);
697 } else if (optind
== argc
) {
699 shsStream(pre_str
, pre_str_len
, stdin
, &digest
);
700 shsOutput(NULL
, 0, c_flag
, i_flag
, &digest
);
706 for (; optind
< argc
; optind
++) {
708 shsFile(pre_str
, pre_str_len
, argv
[optind
], i_flag
, &digest
);
709 shsOutput(argv
[optind
], 0, c_flag
, i_flag
, &digest
);