modified: makefile
[GalaxyCodeBases.git] / c_cpp / etc / md5_sha / md5dual.c
blobb2b9bd986c1c022c1d1068e2b2f25b7bf0249f5c
1 /*
2 * md5dual - md5 dual digest code
4 * @(#) $Revision: 13.1 $
5 * @(#) $Id: md5dual.c,v 13.1 2006/08/14 03:16:33 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/md5dual.c,v $
8 * Split our data into even and odd byte index streams, digest them both
9 * and output the digests, space separated on a line with a 0x prefix.
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 md5drvr.c for version and modification history.
33 char *MD5dual_what="%Z%"; /* #(@) if checked in */
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include "md5.h"
41 /* static declarations */
42 static void dualData(BYTE*, UINT, BYTE*, UINT, MD5_CTX*, MD5_CTX*);
43 static void dualStream(BYTE*, UINT, FILE*, MD5_CTX*, MD5_CTX*);
44 static void dualFile(BYTE*, UINT, char*, MD5_CTX*, MD5_CTX*);
45 static void dualOutput(char*, int, MD5_CTX*, MD5_CTX*);
47 /* dual test suite strings */
48 #define ENTRY(str) {(BYTE *)str, NULL, sizeof(str)-1}
49 struct dual_test {
50 BYTE *ro_data; /* read only string data or NULL to test */
51 BYTE *data; /* data or NULL to test */
52 int len; /* length of data */
53 } dual_test_data[] = {
54 {NULL, NULL, 0},
55 ENTRY(""),
56 ENTRY("a"),
57 ENTRY("aa"),
58 ENTRY("aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"),
59 ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
60 ENTRY("chongo <Ich bin, du bist, aber ein Yit ist nicht!!! :-)> /\\../\\"),
61 ENTRY("123456789 123456789 123456789 123456789 123456789 123456789 1234"),
62 ENTRY("a123456789 123456789 123456789 123456789 123456789 123456789 1234")
64 #define MAX_DUAL_TEST_DATA (sizeof(dual_test_data)/sizeof(dual_test_data[0]))
66 /* dual test filenames */
67 char *dual_test_file[] = {
68 "file1",
69 "file2",
70 "md5.data",
71 "/dev/null"
73 #define MAX_DUAL_TEST_FILE (sizeof(dual_test_file)/sizeof(dual_test_file[0]))
75 /* where the test files are located by default */
76 #if !defined(TLIB)
77 #define TLIB "."
78 #endif
82 * dualData - divide data into alternating bytes and digest both halves
84 * given:
85 * pre_str string prefix or NULL
86 * pre_len length of pre_str
87 * inString string to digest
88 * in_len length of inString
89 * even even byte digest
90 * odd odd byte digest
92 static void
93 dualData(BYTE *pre_str, UINT pre_len, BYTE *inString,
94 UINT in_len, MD5_CTX *even, MD5_CTX *odd)
96 int len; /* total length of pre_str and inString */
97 BYTE *even_buf; /* even byte array */
98 BYTE *odd_buf; /* odd byte array */
99 int indx; /* byte stream index */
100 BYTE *p;
101 unsigned int i;
104 * determine lengths
106 len = (pre_str == NULL) ? 0 : pre_len;
107 len += (inString == NULL) ? 0 : in_len;
108 /* no strings, quick return */
109 if (len == 0) {
110 return;
112 /* only 1 byte, process now and return */
113 if (len == 1) {
114 if (pre_str) {
115 MD5Update(even, (BYTE *)pre_str, 1);
116 MD5COUNT(even, 1);
117 } else {
118 MD5Update(odd, (BYTE *)inString, 1);
119 MD5COUNT(odd, 1);
121 return;
125 * malloc both string halves
127 odd_buf = (BYTE *)malloc(len/2);
128 if (odd_buf == NULL) {
129 fprintf(stderr, "%s: bad malloc #1\n", program);
130 exit(51);
132 even_buf = (BYTE *)malloc((len+1)/2);
133 if (even_buf == NULL) {
134 fprintf(stderr, "%s: bad malloc #2\n", program);
135 exit(52);
139 * divide the pre-string
141 indx = 0;
142 if (pre_str != NULL) {
143 for (p=pre_str, i=0; i < pre_len; ++indx, ++i, ++p) {
144 if (indx & 0x1) {
145 odd_buf[indx>>1] = *p;
146 } else {
147 even_buf[indx>>1] = *p;
153 * divide the string
155 if (inString != NULL) {
156 for (p=inString, i=0; i < in_len; ++indx, ++i, ++p) {
157 if (indx & 0x1) {
158 odd_buf[indx>>1] = *p;
159 } else {
160 even_buf[indx>>1] = *p;
166 * update both halves
168 MD5Update(even, even_buf, (len+1)/2);
169 MD5COUNT(even, (len+1)/2);
170 MD5Update(odd, odd_buf, len/2);
171 MD5COUNT(odd, len/2);
174 * cleanup
176 free(even_buf);
177 free(odd_buf);
182 * dualStream - divide a Stream into alternating bytes and digest both halves
184 * given:
185 * pre_str data prefix or NULL
186 * pre_len length of pre_str
187 * stream the stream to process
188 * even even byte digest
189 * odd odd byte digest
191 static void
192 dualStream(BYTE *pre_str, UINT pre_len, FILE *stream,
193 MD5_CTX *even, MD5_CTX *odd)
195 BYTE data[2*MD5_READSIZE]; /* our read buffer */
196 BYTE even_buf[MD5_READSIZE]; /* even half */
197 BYTE odd_buf[MD5_READSIZE]; /* off half */
198 int bytes; /* bytes last read */
199 int epartial; /* 1 => even partial chunk */
200 int opartial; /* 1 => odd partial chunk */
201 int elen; /* length of even_buf */
202 int olen; /* length of odd_buf */
203 BYTE *p;
204 int i;
207 * pre-process prefix if needed
209 if (pre_str != NULL) {
210 dualData(pre_str, pre_len, NULL, 0, even, odd);
214 * determine if either half has a partial chunk
216 if (even->datalen > 0) {
217 epartial = 1;
218 } else {
219 epartial = 0;
221 if (odd->datalen > 0) {
222 opartial = 1;
223 } else {
224 opartial = 0;
228 * process the contents of the file
230 while ((bytes = fread((char *)data, 1, MD5_READSIZE*2, stream)) > 0) {
233 * split bytes into two halves
235 for (i=0, olen=0, p=(BYTE *)data; i < bytes-1; i+=2, ++olen, p+=2) {
236 even_buf[olen] = *p;
237 odd_buf[olen] = *(p+1);
239 if (bytes & 0x1) {
240 even_buf[olen] = data[bytes-1];
241 elen = olen+1;
242 } else {
243 elen = olen;
247 * digest even bytes
249 if (epartial) {
250 if (even->datalen == 0 && (elen&(MD5_CHUNKSIZE-1)) == 0) {
251 MD5fullUpdate(even, even_buf, elen);
252 epartial = 0;
253 } else {
254 MD5Update(even, even_buf, elen);
256 } else if ((elen&(MD5_CHUNKSIZE-1)) == 0) {
257 MD5fullUpdate(even, even_buf, elen);
258 } else {
259 MD5Update(even, even_buf, elen);
260 epartial = 1;
262 MD5COUNT(even, elen);
265 * digest odd bytes
267 if (opartial) {
268 if (odd->datalen == 0 && (olen&(MD5_CHUNKSIZE-1)) == 0) {
269 MD5fullUpdate(odd, odd_buf, olen);
270 opartial = 0;
271 } else {
272 MD5Update(odd, odd_buf, olen);
274 } else if ((olen&(MD5_CHUNKSIZE-1)) == 0) {
275 MD5fullUpdate(odd, odd_buf, olen);
276 } else {
277 MD5Update(odd, odd_buf, olen);
278 opartial = 1;
280 MD5COUNT(odd, olen);
286 * dualFile - divide a file into alternating bytes and digest both halves
288 static void
289 dualFile(pre_str, pre_len, filename, even, odd)
290 BYTE *pre_str; /* string prefix or NULL */
291 UINT pre_len; /* length of pre_str */
292 char *filename; /* the filename to process */
293 MD5_CTX *even; /* even byte digest */
294 MD5_CTX *odd; /* odd byte digest */
296 FILE *inFile; /* the open file stream */
297 struct stat buf; /* stat or lstat of file */
298 struct md5_stat hashbuf; /* stat data to digest */
299 struct md5_stat hashlbuf; /* lstat data to digest */
302 * open the file
304 inFile = fopen(filename, "rb");
305 if (inFile == NULL) {
306 fprintf(stderr, "%s: cannot open %s: ", program, filename);
307 perror("");
308 return;
312 * pre-process prefix if needed
314 if (pre_str == NULL) {
315 if (i_flag) {
316 dualData(NULL, 0, (BYTE *)filename, strlen(filename), even, odd);
318 } else {
319 if (i_flag) {
320 dualData(pre_str, pre_len, (BYTE *)filename, strlen(filename),
321 even, odd);
322 } else {
323 dualData(pre_str, pre_len, NULL, 0, even, odd);
328 * digest file stat and lstat
330 if (i_flag) {
331 if (fstat(fileno(inFile), &buf) < 0) {
332 printf("%s can't be stated.\n", filename);
333 return;
335 hashbuf.stat_dev = buf.st_dev;
336 hashbuf.stat_ino = buf.st_ino;
337 hashbuf.stat_mode = buf.st_mode;
338 hashbuf.stat_nlink = buf.st_nlink;
339 hashbuf.stat_uid = buf.st_uid;
340 hashbuf.stat_gid = buf.st_gid;
341 hashbuf.stat_size = buf.st_size;
342 hashbuf.stat_mtime = buf.st_mtime;
343 hashbuf.stat_ctime = buf.st_ctime;
344 if (lstat(filename, &buf) < 0) {
345 printf("%s can't be lstated.\n", filename);
346 return;
348 hashlbuf.stat_dev = buf.st_dev;
349 hashlbuf.stat_ino = buf.st_ino;
350 hashlbuf.stat_mode = buf.st_mode;
351 hashlbuf.stat_nlink = buf.st_nlink;
352 hashlbuf.stat_uid = buf.st_uid;
353 hashlbuf.stat_gid = buf.st_gid;
354 hashlbuf.stat_size = buf.st_size;
355 hashlbuf.stat_mtime = buf.st_mtime;
356 hashlbuf.stat_ctime = buf.st_ctime;
357 dualData((BYTE *)&hashbuf, sizeof(hashbuf), (BYTE *)&hashlbuf,
358 sizeof(hashlbuf), even, odd);
361 * pad both halves with zeros to process file data faster
363 if (even->datalen > 0) {
364 MD5Update(even, (BYTE *)md5_zero, MD5_CHUNKSIZE - even->datalen);
365 MD5COUNT(even, MD5_CHUNKSIZE - even->datalen);
367 if (odd->datalen > 0) {
368 MD5Update(odd, (BYTE *)md5_zero, MD5_CHUNKSIZE - odd->datalen);
369 MD5COUNT(odd, MD5_CHUNKSIZE - odd->datalen);
374 * process the data stream
376 dualStream(NULL, 0, inFile, even, odd);
377 fclose(inFile);
382 * dualOutput - output the dual digests
384 * given:
385 * str print string after digest, NULL => none
386 * quot 1 => surround str with a double quotes
387 * even even byte digest
388 * odd odd byte digest
390 static void
391 dualOutput(char *str, int quot, MD5_CTX *even, MD5_CTX *odd)
394 * finalize both sets
396 MD5Final(even);
397 MD5Final(odd);
400 * print the 320 bit hex value
402 MD5Print(even);
403 putchar(' ');
404 MD5Print(odd);
405 if (str && !q_flag) {
406 if (quot) {
407 printf(" \"%s\"\n", str);
408 } else {
409 printf(" %s\n", str);
411 } else {
412 putchar('\n');
418 * dualTest - MD5 dual test suite
420 void
421 dualTest(void)
423 struct dual_test *t; /* current dual test */
424 struct dual_test *p; /* current dual pre-string test */
425 struct stat buf; /* stat of a test file */
426 MD5_CTX even_dig; /* even byte digest */
427 MD5_CTX odd_dig; /* odd byte digest */
428 char **f; /* current file being tested */
429 unsigned int i;
430 unsigned int j;
433 * copy our test strings into writable data
435 for (i=0, t=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++t) {
436 if (t->ro_data != NULL) {
437 t->data = (BYTE *)malloc(t->len + 1);
438 if (t->data == NULL) {
439 fprintf(stderr, "%s: malloc #5 failed\n", program);
440 exit(53);
442 strcpy((char *)t->data, (char *)t->ro_data);
447 * find all of the test files
449 for (i=0, f=dual_test_file; i < MAX_DUAL_TEST_FILE; ++i, ++f) {
450 if (stat(*f, &buf) < 0) {
451 /* no file1 in this directory, cd to the test suite directory */
452 if (chdir(TLIB) < 0) {
453 fflush(stdout);
454 fprintf(stderr,
455 "%s: cannot find %s or %s/%s\n", program, *f, TLIB, *f);
456 return;
462 * try all combinations of test strings as prefixes and data
464 for (i=0, t=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++t) {
465 for (j=0, p=dual_test_data; j < MAX_DUAL_TEST_DATA; ++j, ++p) {
466 printf("pre:%d data:%d\n", i, j);
467 MD5Init(&even_dig);
468 MD5Init(&odd_dig);
469 dualData(p->data, p->len, t->data, t->len, &even_dig, &odd_dig);
470 dualOutput(NULL, 0, &even_dig, &odd_dig);
475 * try the files with all test strings as prefixes
477 for (i=0, p=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++p) {
478 for (j=0, f=dual_test_file; j < MAX_DUAL_TEST_FILE; ++j, ++f) {
479 printf("pre:%d file:%s\n", i, *f);
480 MD5Init(&even_dig);
481 MD5Init(&odd_dig);
482 dualFile(p->data, p->len, *f, &even_dig, &odd_dig);
483 dualOutput(NULL, 0, &even_dig, &odd_dig);
486 exit(0);
491 * dualMain - main driver of MD5 dual routines
493 * given:
494 * argc arg count left after getopt
495 * argv args left after getopt
496 * pre_str pre-process this data first
497 * pre_len length of pre_str
498 * data_str data is this string, not a file
500 void
501 dualMain(argc, argv, pre_str, pre_len, data_str)
502 int argc; /* arg count left after getopt */
503 char **argv; /* args left after getopt */
504 BYTE *pre_str; /* pre-process this data first */
505 UINT pre_len; /* length of pre_str */
506 char *data_str; /* data is this string, not a file */
508 extern int optind; /* option index */
509 MD5_CTX even_dig; /* even byte digest */
510 MD5_CTX odd_dig; /* odd byte digest */
513 * case: initialize both halves
515 MD5Init(&even_dig);
516 MD5Init(&odd_dig);
519 * digest a string
521 if (data_str != NULL) {
522 dualData(pre_str, pre_len, (BYTE *)data_str, strlen(data_str),
523 &even_dig, &odd_dig);
524 dualOutput(data_str, 1, &even_dig, &odd_dig);
527 * case: digest stdin
529 } else if (optind == argc) {
530 dualStream(pre_str, pre_len, stdin, &even_dig, &odd_dig);
531 dualOutput(NULL, 0, &even_dig, &odd_dig);
534 * case: digest files
536 } else {
537 if (i_flag) {
538 dot_zero = 1;
540 for (; optind < argc; optind++) {
541 dualFile(pre_str, pre_len, argv[optind], &even_dig, &odd_dig);
542 dualOutput(argv[optind], 0, &even_dig, &odd_dig);