2 * shsdual - old shs dual digest code
4 * @(#) $Revision: 13.2 $
5 * @(#) $Id: shsdual.c,v 13.2 2006/08/14 10:09:23 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/shsdual.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 * Split our data into multiple byte index streams, digest them all
15 * and output the digests on a line.
17 * This file was written by Landon Curt Noll.
19 * This code has been placed in the public domain. Please do not
20 * copyright this code.
22 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
24 * CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
25 * NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
26 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
27 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
28 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 * chongo (was here) /\oo/\
32 * http://www.isthe.com/chongo/index.html
34 * Share and enjoy! :-)
36 * See shsdrvr.c for version and modification history.
39 char *shsdual_what
="@(#)"; /* #(@) if checked in */
47 /* static declarations */
48 static void multiData(BYTE
*, UINT
, BYTE
*, UINT
, UINT
, SHS_INFO
*);
49 static void multiStream(BYTE
*, UINT
, FILE*, UINT
, SHS_INFO
*);
50 static void multiFile(BYTE
*, UINT
, char*, UINT
, SHS_INFO
*);
51 static void multiOutput(char*, int, int, UINT
, SHS_INFO
*);
53 /* dual test suite strings */
54 #define ENTRY(str) {(BYTE *)str, sizeof(str)-1}
56 BYTE
*data
; /* data or NULL to test */
57 int len
; /* length of data */
58 } dual_test_data
[] = {
63 ENTRY("aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"),
64 ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
65 ENTRY("chongo <Ich bin, du bist, aber ein Yit ist nicht!!! :-)> /\\../\\"),
66 ENTRY("123456789 123456789 123456789 123456789 123456789 123456789 1234"),
67 ENTRY("a123456789 123456789 123456789 123456789 123456789 123456789 1234")
69 #define MAX_DUAL_TEST_DATA (sizeof(dual_test_data)/sizeof(dual_test_data[0]))
71 /* dual test filenames */
72 char *dual_test_file
[] = {
78 #define MAX_DUAL_TEST_FILE (sizeof(dual_test_file)/sizeof(dual_test_file[0]))
80 /* where the test files are located by default */
87 * multiData - divide data into multiple sections
90 * pre_str string prefix or NULL
91 * pre_len length of pre_str
92 * inString string to digest
93 * in_len length of inString
94 * cnt number of digests
95 * digs array of digests, cnt elements long
98 multiData(BYTE
*pre_str
, UINT pre_len
, BYTE
*inString
, UINT in_len
,
99 UINT cnt
, SHS_INFO
*digs
)
101 BYTE
**bufs
; /* byte arrays for digests */
102 UINT
*buflen
; /* bytes stored in bufs[i] */
103 int len
; /* total length of pre_str and inString */
104 UINT indx
; /* byte stream index */
105 BYTE
**n
; /* n[i] is next byte to use in bufs[i] */
112 len
= (pre_str
== NULL
) ? 0 : pre_len
;
113 len
+= (inString
== NULL
) ? 0 : in_len
;
114 /* no strings, quick return */
115 if (len
== 0 || cnt
<= 0) {
120 * malloc string arrays
122 bufs
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
124 fprintf(stderr
, "%s: bad malloc #1\n", program
);
127 buflen
= (UINT
*)malloc(sizeof(UINT
)*cnt
);
128 if (buflen
== NULL
) {
129 fprintf(stderr
, "%s: bad malloc #2\n", program
);
132 n
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
134 fprintf(stderr
, "%s: bad malloc #3\n", program
);
137 for (i
=0; i
< cnt
; ++i
) {
138 bufs
[i
] = (BYTE
*)malloc(1+(len
/cnt
));
139 if (bufs
[i
] == NULL
) {
140 fprintf(stderr
, "%s: bad malloc #4\n", program
);
148 * divide the pre-string
151 if (pre_str
!= NULL
) {
152 for (p
=pre_str
, i
=0; i
< pre_len
; ++i
, ++p
, indx
++) {
153 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
161 if (inString
!= NULL
) {
162 for (p
=inString
, i
=0; i
< in_len
; ++indx
, ++i
, ++p
) {
163 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
171 for (i
=0; i
< cnt
; ++i
) {
172 shsUpdate(digs
+i
, bufs
[i
], buflen
[i
]);
180 for (i
=0; i
< cnt
; ++i
) {
188 * multiStream - divide a Stream into multiple sections
191 * pre_str data prefix or NULL
192 * pre_len length of pre_str
193 * stream the stream to process
194 * cnt number of digests
195 * digs array of digests, cnt elements long
198 multiStream(BYTE
*pre_str
, UINT pre_len
, FILE *stream
, UINT cnt
, SHS_INFO
*digs
)
200 BYTE data
[SHS_READSIZE
]; /* our read buffer */
201 int bytes
; /* bytes last read */
202 BYTE
**bufs
; /* byte arrays for digests */
203 UINT
*buflen
; /* bytes stored in bufs[i] */
204 UINT indx
; /* byte stream index */
205 BYTE
*pbeyond
; /* beyond end of used data or pre_str */
206 BYTE
**n
; /* n[i] is next byte to use in bufs[i] */
211 * no sets, quick return
218 * malloc string arrays
220 bufs
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
222 fprintf(stderr
, "%s: bad malloc #5\n", program
);
225 buflen
= (UINT
*)malloc(sizeof(UINT
)*cnt
);
226 if (buflen
== NULL
) {
227 fprintf(stderr
, "%s: bad malloc #6\n", program
);
230 n
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
232 fprintf(stderr
, "%s: bad malloc #7\n", program
);
235 for (i
=0; i
< cnt
; ++i
) {
236 bufs
[i
] = (BYTE
*)malloc(SHS_BLOCKSIZE
);
237 if (bufs
[i
] == NULL
) {
238 fprintf(stderr
, "%s: bad malloc #8\n", program
);
246 * divide the pre-string
249 if (pre_str
!= NULL
&& pre_len
> 0) {
250 for (p
=pre_str
, pbeyond
=pre_str
+pre_len
; p
< pbeyond
; ++p
, ++indx
) {
251 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
252 if (++buflen
[indx
] >= SHS_BLOCKSIZE
) {
253 shsUpdate(digs
+indx
, bufs
[indx
], SHS_BLOCKSIZE
);
255 n
[indx
] = bufs
[indx
];
261 * process the contents of the file
263 while ((bytes
= fread((char *)data
, 1, SHS_READSIZE
, stream
)) > 0) {
266 * load the bytes into the bufs
268 for (p
=data
, pbeyond
=data
+bytes
; p
< pbeyond
; ++p
, ++indx
) {
269 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
270 if (++buflen
[indx
] >= SHS_BLOCKSIZE
) {
271 shsUpdate(digs
+indx
, bufs
[indx
], SHS_BLOCKSIZE
);
273 n
[indx
] = bufs
[indx
];
279 * process any partial buffers
281 for (i
=0; i
< cnt
; ++i
) {
283 shsUpdate(digs
+i
, bufs
[i
], buflen
[i
]);
292 for (i
=0; i
< cnt
; ++i
) {
300 * multiFile - divide a file into alternating bytes and digest both halves
303 * pre_str string prefix or NULL
304 * pre_len length of pre_str
305 * filename the filename to process
306 * cnt number of digests
307 * digs array of digests, cnt elements long
310 multiFile(BYTE
*pre_str
, UINT pre_len
, char *filename
, UINT cnt
, SHS_INFO
*digs
)
312 FILE *inFile
; /* the open file stream */
313 struct stat buf
; /* stat or lstat of file */
314 struct shs_stat hashbuf
; /* stat data to digest */
315 struct shs_stat hashlbuf
; /* lstat data to digest */
328 inFile
= fopen(filename
, "rb");
329 if (inFile
== NULL
) {
330 fprintf(stderr
, "%s: cannot open %s: ", program
, filename
);
336 * pre-process prefix if needed
338 if (pre_str
== NULL
|| pre_len
<= 0) {
340 multiData(NULL
, 0, (BYTE
*)filename
, strlen(filename
), cnt
, digs
);
344 multiData(pre_str
, pre_len
, (BYTE
*)filename
, strlen(filename
),
347 multiData(pre_str
, pre_len
, NULL
, 0, cnt
, digs
);
352 * digest file stat and lstat
355 if (fstat(fileno(inFile
), &buf
) < 0) {
356 printf("%s can't be stated.\n", filename
);
359 hashbuf
.stat_dev
= buf
.st_dev
;
360 hashbuf
.stat_ino
= buf
.st_ino
;
361 hashbuf
.stat_mode
= buf
.st_mode
;
362 hashbuf
.stat_nlink
= buf
.st_nlink
;
363 hashbuf
.stat_uid
= buf
.st_uid
;
364 hashbuf
.stat_gid
= buf
.st_gid
;
365 hashbuf
.stat_size
= buf
.st_size
;
366 hashbuf
.stat_mtime
= buf
.st_mtime
;
367 hashbuf
.stat_ctime
= buf
.st_ctime
;
368 if (lstat(filename
, &buf
) < 0) {
369 printf("%s can't be lstated.\n", filename
);
372 hashlbuf
.stat_dev
= buf
.st_dev
;
373 hashlbuf
.stat_ino
= buf
.st_ino
;
374 hashlbuf
.stat_mode
= buf
.st_mode
;
375 hashlbuf
.stat_nlink
= buf
.st_nlink
;
376 hashlbuf
.stat_uid
= buf
.st_uid
;
377 hashlbuf
.stat_gid
= buf
.st_gid
;
378 hashlbuf
.stat_size
= buf
.st_size
;
379 hashlbuf
.stat_mtime
= buf
.st_mtime
;
380 hashlbuf
.stat_ctime
= buf
.st_ctime
;
381 multiData((BYTE
*)&hashbuf
, sizeof(hashbuf
), (BYTE
*)&hashlbuf
,
382 sizeof(hashlbuf
), cnt
, digs
);
385 * pad sections with zeros to process file data faster
387 for (i
=0; i
< cnt
; ++i
) {
388 if (digs
[i
].datalen
> 0) {
389 shsUpdate(digs
+i
, (BYTE
*)shs_zero
,
390 SHS_CHUNKSIZE
- digs
[i
].datalen
);
396 * process the data stream
398 multiStream(NULL
, 0, inFile
, cnt
, digs
);
404 * multiOutput - output the multiple digests
407 * str print string after digest, NULL => none
408 * quot 1 => surround str with a double quotes
409 * nospace 1 => don't space seperate multi digests
410 * cnt number of digests
411 * digs array of digests, cnt elements long
414 multiOutput(str
, quot
, nospace
, cnt
, digs
)
415 char *str
; /* print string after digest, NULL => none */
416 int quot
; /* 1 => surround str with a double quotes */
417 int nospace
; /* 1 => don't space seperate multi digests */
418 UINT cnt
; /* number of digests */
419 SHS_INFO
*digs
; /* array of digests, cnt elements long */
433 for (i
=0; i
< cnt
; ++i
) {
440 shsPrint(c_flag
, 0, digs
);
441 for (i
=1; i
< cnt
-1; ++i
) {
444 shsPrint(c_flag
, 0, digs
+i
);
446 shsPrint(0, 0, digs
+i
);
452 shsPrint(c_flag
, i_flag
, digs
+cnt
-1);
454 shsPrint(0, i_flag
, digs
+cnt
-1);
457 if (str
&& !q_flag
) {
459 printf(" \"%s\"\n", str
);
461 printf(" %s\n", str
);
470 * multiTest - shs dual test suite
475 struct dual_test
*t
; /* current dual test */
476 struct dual_test
*p
; /* current dual pre-string test */
477 struct stat buf
; /* stat of a test file */
478 SHS_INFO digs
[2]; /* even byte digest */
479 char **f
; /* current file being tested */
484 * find all of the test files
486 for (i
=0, f
=dual_test_file
; i
< MAX_DUAL_TEST_FILE
; ++i
, ++f
) {
487 if (stat(*f
, &buf
) < 0) {
488 /* no file1 in this directory, cd to the test suite directory */
489 if (chdir(TLIB
) < 0) {
492 "%s: cannot find %s or %s/%s\n", program
, *f
, TLIB
, *f
);
499 * try all combinations of test strings as prefixes and data
501 for (i
=0, t
=dual_test_data
; i
< MAX_DUAL_TEST_DATA
; ++i
, ++t
) {
502 for (j
=1, p
=dual_test_data
+1; j
< MAX_DUAL_TEST_DATA
; ++j
, ++p
) {
503 printf("pre:%u data:%u\n", i
, j
);
506 multiData(p
->data
, p
->len
, t
->data
, t
->len
, 2, digs
);
507 multiOutput(NULL
, 0, 0, 2, digs
);
512 * try the files with all test strings as prefixes
514 for (i
=0, p
=dual_test_data
; i
< MAX_DUAL_TEST_DATA
; ++i
, ++p
) {
515 for (j
=0, f
=dual_test_file
; j
< MAX_DUAL_TEST_FILE
; ++j
, ++f
) {
516 printf("pre:%d file:%s\n", i
, *f
);
519 multiFile(p
->data
, p
->len
, *f
, 2, digs
);
520 multiOutput(NULL
, 0, 0, 2, digs
);
528 * multiMain - main driver of shs dual routines
531 * c arg count left after getopt
532 * argv args left after getopt
533 * pre_str pre-process this data first
534 * pre_len length of pre_str
535 * data_str data is this string, not a file
536 * nospace 1 => don't space seperate multi digests
537 * cnt number of digests to perform
540 multiMain(int argc
, char **argv
, BYTE
*pre_str
, UINT pre_len
,
541 char *data_str
, int nospace
, UINT cnt
)
543 extern int optind
; /* option index */
544 SHS_INFO
*digs
; /* multiple digest */
555 * initialize multiple digests
557 digs
= (SHS_INFO
*)malloc(sizeof(SHS_INFO
)*cnt
);
559 fprintf(stderr
, "%s: bad malloc #1\n", program
);
562 for (i
=0; i
< cnt
; ++i
) {
569 if (data_str
!= NULL
) {
570 multiData(pre_str
, pre_len
, (BYTE
*)data_str
, strlen(data_str
),
572 multiOutput(data_str
, 1, nospace
, cnt
, digs
);
577 } else if (optind
== argc
) {
578 multiStream(pre_str
, pre_len
, stdin
, cnt
, digs
);
579 multiOutput(NULL
, 0, nospace
, cnt
, digs
);
585 for (; optind
< argc
; optind
++) {
586 multiFile(pre_str
, pre_len
, argv
[optind
], cnt
, digs
);
587 multiOutput(argv
[optind
], 0, nospace
, cnt
, digs
);