2 * shs1dual - multi digest code that works with NIST Secure Hash Standard-1
4 * @(#) $Revision: 13.2 $
5 * @(#) $Id: shs1dual.c,v 13.2 2006/08/14 10:09:23 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/shs1dual.c,v $
8 * Split our data into multiple byte index streams, digest them all
9 * and output the digests on a line.
11 * This file was written by Landon Curt Noll.
13 * This code has been placed in the public domain. Please do not
14 * copyright this code.
16 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
17 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
18 * CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
19 * NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
21 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
22 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 * chongo (was here) /\oo/\
26 * http://www.isthe.com/chongo/index.html
28 * Share and enjoy! :-)
30 * See shs1drvr.c for version and modification history.
33 char *shs1dual_what
="@(#)"; /* #(@) if checked in */
41 /* static declarations */
42 static void multiData(BYTE
*, UINT
, BYTE
*, UINT
, UINT
, SHS1_INFO
*);
43 static void multiStream(BYTE
*, UINT
, FILE*, UINT
, SHS1_INFO
*);
44 static void multiFile(BYTE
*, UINT
, char*, UINT
, SHS1_INFO
*);
45 static void multiOutput(char*, int, int, UINT
, SHS1_INFO
*);
47 /* dual test suite strings */
48 #define ENTRY(str) {(BYTE *)str, sizeof(str)-1}
50 BYTE
*data
; /* data or NULL to test */
51 int len
; /* length of data */
52 } dual_test_data
[] = {
57 ENTRY("aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"),
58 ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
59 ENTRY("chongo <Ich bin, du bist, aber ein Yit ist nicht!!! :-)> /\\../\\"),
60 ENTRY("123456789 123456789 123456789 123456789 123456789 123456789 1234"),
61 ENTRY("a123456789 123456789 123456789 123456789 123456789 123456789 1234")
63 #define MAX_DUAL_TEST_DATA (sizeof(dual_test_data)/sizeof(dual_test_data[0]))
65 /* dual test filenames */
66 char *dual_test_file
[] = {
72 #define MAX_DUAL_TEST_FILE (sizeof(dual_test_file)/sizeof(dual_test_file[0]))
74 /* where the test files are located by default */
81 * multiData - divide data into multiple sections
84 * pre_str string prefix or NULL
85 * pre_len length of pre_str
86 * inString string to digest
87 * in_len length of inString
88 * cnt number of digests
89 * digs array of digests, cnt elements long
92 multiData(BYTE
*pre_str
, UINT pre_len
, BYTE
*inString
,
93 UINT in_len
, UINT cnt
, SHS1_INFO
*digs
)
95 BYTE
**bufs
; /* byte arrays for digests */
96 UINT
*buflen
; /* bytes stored in bufs[i] */
97 int len
; /* total length of pre_str and inString */
98 UINT indx
; /* byte stream index */
99 BYTE
**n
; /* n[i] is next byte to use in bufs[i] */
106 len
= (pre_str
== NULL
) ? 0 : pre_len
;
107 len
+= (inString
== NULL
) ? 0 : in_len
;
108 /* no strings, quick return */
109 if (len
== 0 || cnt
<= 0) {
114 * malloc string arrays
116 bufs
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
118 fprintf(stderr
, "%s: bad malloc #1\n", program
);
121 buflen
= (UINT
*)malloc(sizeof(UINT
)*cnt
);
122 if (buflen
== NULL
) {
123 fprintf(stderr
, "%s: bad malloc #2\n", program
);
126 n
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
128 fprintf(stderr
, "%s: bad malloc #3\n", program
);
131 for (i
=0; i
< cnt
; ++i
) {
132 bufs
[i
] = (BYTE
*)malloc(1+(len
/cnt
));
133 if (bufs
[i
] == NULL
) {
134 fprintf(stderr
, "%s: bad malloc #4\n", program
);
142 * divide the pre-string
145 if (pre_str
!= NULL
) {
146 for (p
=pre_str
, i
=0; i
< pre_len
; ++i
, ++p
, indx
++) {
147 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
155 if (inString
!= NULL
) {
156 for (p
=inString
, i
=0; i
< in_len
; ++indx
, ++i
, ++p
) {
157 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
165 for (i
=0; i
< cnt
; ++i
) {
166 shs1Update(digs
+i
, bufs
[i
], buflen
[i
]);
174 for (i
=0; i
< cnt
; ++i
) {
182 * multiStream - divide a Stream into multiple sections
185 * pre_str data prefix or NULL
186 * pre_len length of pre_str
187 * stream the stream to process
188 * cnt number of digests
189 * digs array of digests, cnt elements long
192 multiStream(BYTE
*pre_str
, UINT pre_len
, FILE *stream
,
193 UINT cnt
, SHS1_INFO
*digs
)
195 BYTE data
[SHS1_READSIZE
]; /* our read buffer */
196 int bytes
; /* bytes last read */
197 BYTE
**bufs
; /* byte arrays for digests */
198 UINT
*buflen
; /* bytes stored in bufs[i] */
199 UINT indx
; /* byte stream index */
200 BYTE
*pbeyond
; /* beyond end of used data or pre_str */
201 BYTE
**n
; /* n[i] is next byte to use in bufs[i] */
206 * no sets, quick return
213 * malloc string arrays
215 bufs
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
217 fprintf(stderr
, "%s: bad malloc #5\n", program
);
220 buflen
= (UINT
*)malloc(sizeof(UINT
)*cnt
);
221 if (buflen
== NULL
) {
222 fprintf(stderr
, "%s: bad malloc #6\n", program
);
225 n
= (BYTE
**)malloc(sizeof(BYTE
*)*cnt
);
227 fprintf(stderr
, "%s: bad malloc #7\n", program
);
230 for (i
=0; i
< cnt
; ++i
) {
231 bufs
[i
] = (BYTE
*)malloc(SHS1_BLOCKSIZE
);
232 if (bufs
[i
] == NULL
) {
233 fprintf(stderr
, "%s: bad malloc #8\n", program
);
241 * divide the pre-string
244 if (pre_str
!= NULL
&& pre_len
> 0) {
245 for (p
=pre_str
, pbeyond
=pre_str
+pre_len
; p
< pbeyond
; ++p
, ++indx
) {
246 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
247 if (++buflen
[indx
] >= SHS1_BLOCKSIZE
) {
248 shs1Update(digs
+indx
, bufs
[indx
], SHS1_BLOCKSIZE
);
250 n
[indx
] = bufs
[indx
];
256 * process the contents of the file
258 while ((bytes
= fread((char *)data
, 1, SHS1_READSIZE
, stream
)) > 0) {
261 * load the bytes into the bufs
263 for (p
=data
, pbeyond
=data
+bytes
; p
< pbeyond
; ++p
, ++indx
) {
264 *(n
[(indx
= ((indx
>= cnt
) ? 0 : indx
))]++) = *p
;
265 if (++buflen
[indx
] >= SHS1_BLOCKSIZE
) {
266 shs1Update(digs
+indx
, bufs
[indx
], SHS1_BLOCKSIZE
);
268 n
[indx
] = bufs
[indx
];
274 * process any partial buffers
276 for (i
=0; i
< cnt
; ++i
) {
278 shs1Update(digs
+i
, bufs
[i
], buflen
[i
]);
287 for (i
=0; i
< cnt
; ++i
) {
295 * multiFile - divide a file into alternating bytes and digest both halves
298 * pre_str string prefix or NULL
299 * pre_len length of pre_str
300 * filename the filename to process
301 * cnt number of digests
302 * digs array of digests, cnt elements long
305 multiFile(BYTE
*pre_str
, UINT pre_len
, char *filename
,
306 UINT cnt
, SHS1_INFO
*digs
)
308 FILE *inFile
; /* the open file stream */
309 struct stat buf
; /* stat or lstat of file */
310 struct shs1_stat hashbuf
; /* stat data to digest */
311 struct shs1_stat hashlbuf
; /* lstat data to digest */
324 inFile
= fopen(filename
, "rb");
325 if (inFile
== NULL
) {
326 fprintf(stderr
, "%s: cannot open %s: ", program
, filename
);
332 * pre-process prefix if needed
334 if (pre_str
== NULL
|| pre_len
<= 0) {
336 multiData(NULL
, 0, (BYTE
*)filename
, strlen(filename
), cnt
, digs
);
340 multiData(pre_str
, pre_len
, (BYTE
*)filename
, strlen(filename
),
343 multiData(pre_str
, pre_len
, NULL
, 0, cnt
, digs
);
348 * digest file stat and lstat
351 if (fstat(fileno(inFile
), &buf
) < 0) {
352 printf("%s can't be stated.\n", filename
);
355 hashbuf
.stat_dev
= buf
.st_dev
;
356 hashbuf
.stat_ino
= buf
.st_ino
;
357 hashbuf
.stat_mode
= buf
.st_mode
;
358 hashbuf
.stat_nlink
= buf
.st_nlink
;
359 hashbuf
.stat_uid
= buf
.st_uid
;
360 hashbuf
.stat_gid
= buf
.st_gid
;
361 hashbuf
.stat_size
= buf
.st_size
;
362 hashbuf
.stat_mtime
= buf
.st_mtime
;
363 hashbuf
.stat_ctime
= buf
.st_ctime
;
364 if (lstat(filename
, &buf
) < 0) {
365 printf("%s can't be lstated.\n", filename
);
368 hashlbuf
.stat_dev
= buf
.st_dev
;
369 hashlbuf
.stat_ino
= buf
.st_ino
;
370 hashlbuf
.stat_mode
= buf
.st_mode
;
371 hashlbuf
.stat_nlink
= buf
.st_nlink
;
372 hashlbuf
.stat_uid
= buf
.st_uid
;
373 hashlbuf
.stat_gid
= buf
.st_gid
;
374 hashlbuf
.stat_size
= buf
.st_size
;
375 hashlbuf
.stat_mtime
= buf
.st_mtime
;
376 hashlbuf
.stat_ctime
= buf
.st_ctime
;
377 multiData((BYTE
*)&hashbuf
, sizeof(hashbuf
), (BYTE
*)&hashlbuf
,
378 sizeof(hashlbuf
), cnt
, digs
);
381 * pad sections with zeros to process file data faster
383 for (i
=0; i
< cnt
; ++i
) {
384 if (digs
[i
].datalen
> 0) {
385 shs1Update(digs
+i
, (BYTE
*)shs1_zero
,
386 SHS1_CHUNKSIZE
- digs
[i
].datalen
);
392 * process the data stream
394 multiStream(NULL
, 0, inFile
, cnt
, digs
);
400 * multiOutput - output the multiple digests
403 * str print string after digest, NULL => none
404 * quot 1 => surround str with a double quotes
405 * nospace 1 => don't space seperate multi digests
406 * cnt number of digests
407 * digs array of digests, cnt elements long
410 multiOutput(char *str
, int quot
, int nospace
, UINT cnt
, SHS1_INFO
*digs
)
424 for (i
=0; i
< cnt
; ++i
) {
431 shs1Print(c_flag
, 0, digs
);
432 for (i
=1; i
< cnt
-1; ++i
) {
435 shs1Print(c_flag
, 0, digs
+i
);
437 shs1Print(0, 0, digs
+i
);
443 shs1Print(c_flag
, i_flag
, digs
+cnt
-1);
445 shs1Print(0, i_flag
, digs
+cnt
-1);
448 if (str
&& !q_flag
) {
450 printf(" \"%s\"\n", str
);
452 printf(" %s\n", str
);
461 * multiTest - shs1 dual test suite
466 struct dual_test
*t
; /* current dual test */
467 struct dual_test
*p
; /* current dual pre-string test */
468 struct stat buf
; /* stat of a test file */
469 SHS1_INFO digs
[2]; /* even byte digest */
470 char **f
; /* current file being tested */
475 * find all of the test files
477 for (i
=0, f
=dual_test_file
; i
< MAX_DUAL_TEST_FILE
; ++i
, ++f
) {
478 if (stat(*f
, &buf
) < 0) {
479 /* no file1 in this directory, cd to the test suite directory */
480 if (chdir(TLIB
) < 0) {
483 "%s: cannot find %s or %s/%s\n", program
, *f
, TLIB
, *f
);
490 * try all combinations of test strings as prefixes and data
492 for (i
=0, t
=dual_test_data
; i
< MAX_DUAL_TEST_DATA
; ++i
, ++t
) {
493 for (j
=1, p
=dual_test_data
+1; j
< MAX_DUAL_TEST_DATA
; ++j
, ++p
) {
494 printf("pre:%u data:%u\n", i
, j
);
497 multiData(p
->data
, p
->len
, t
->data
, t
->len
, 2, digs
);
498 multiOutput(NULL
, 0, 0, 2, digs
);
503 * try the files with all test strings as prefixes
505 for (i
=0, p
=dual_test_data
; i
< MAX_DUAL_TEST_DATA
; ++i
, ++p
) {
506 for (j
=0, f
=dual_test_file
; j
< MAX_DUAL_TEST_FILE
; ++j
, ++f
) {
507 printf("pre:%d file:%s\n", i
, *f
);
510 multiFile(p
->data
, p
->len
, *f
, 2, digs
);
511 multiOutput(NULL
, 0, 0, 2, digs
);
519 * multiMain - main driver of shs1 dual routines
522 * argc arg count left after getopt
523 * argv args left after getopt
524 * pre_str pre-process this data first
525 * pre_len length of pre_str
526 * data_str data is this string, not a file
527 * nospace 1 => don't space seperate multi digests
528 * cnt number of digests to perform
531 multiMain(int argc
, char **argv
, BYTE
*pre_str
, UINT pre_len
,
532 char *data_str
, int nospace
, UINT cnt
)
534 extern int optind
; /* option index */
535 SHS1_INFO
*digs
; /* multiple digest */
546 * initialize multiple digests
548 digs
= (SHS1_INFO
*)malloc(sizeof(SHS1_INFO
)*cnt
);
550 fprintf(stderr
, "%s: bad malloc #1\n", program
);
553 for (i
=0; i
< cnt
; ++i
) {
560 if (data_str
!= NULL
) {
561 multiData(pre_str
, pre_len
, (BYTE
*)data_str
, strlen(data_str
),
563 multiOutput(data_str
, 1, nospace
, cnt
, digs
);
568 } else if (optind
== argc
) {
569 multiStream(pre_str
, pre_len
, stdin
, cnt
, digs
);
570 multiOutput(NULL
, 0, nospace
, cnt
, digs
);
576 for (; optind
< argc
; optind
++) {
577 multiFile(pre_str
, pre_len
, argv
[optind
], cnt
, digs
);
578 multiOutput(argv
[optind
], 0, nospace
, cnt
, digs
);