OSDN Git Service

Add support for IPv6 (not tested).
[ffftp/ffftp.git] / sha.c
1 /* Implementation of NIST's Secure Hash Algorithm (FIPS 180)\r
2  * Lightly bummed for execution efficiency.\r
3  *\r
4  * Jim Gillogly 3 May 1993\r
5  *\r
6  * 27 Aug 93: imported SHA_LITTLE_ENDIAN mods from Peter Gutmann's implementation\r
7  * 5 Jul 94: Modified for NSA fix\r
8  *\r
9  * Compile: cc -O -o sha sha.c\r
10  *\r
11  * To remove the test wrapper and use just the nist_hash() routine,\r
12  *      compile with -DONT_WRAP\r
13  *\r
14  * To reverse byte order for little-endian machines, use -DSHA_LITTLE_ENDIAN\r
15  *\r
16  * To get the original SHA definition before the 1994 fix, use -DVERSION_0\r
17  *\r
18  * Usage: sha [-vt] [filename ...]\r
19  *\r
20  *      -v switch: output the filename as well\r
21  *      -t switch: suppress spaces between 32-bit blocks\r
22  *\r
23  *      If no input files are specified, process standard input.\r
24  *\r
25  * Output: 40-hex-digit digest of each file specified (160 bits)\r
26  *\r
27  * Synopsis of the function calls:\r
28  *\r
29  *   sha_file(char *filename, uint32 *buffer)\r
30  *      Filename is a file to be opened and processed.\r
31  *      buffer is a user-supplied array of 5 or more longs.\r
32  *      The 5-word buffer is filled with 160 bits of non-terminated hash.\r
33  *      Returns 0 if successful, non-zero if bad file.\r
34  *\r
35  *   void sha_stream(FILE *stream, uint32 *buffer)\r
36  *      Input is from already-opened stream, not file.\r
37  *\r
38  *   void sha_memory(char *mem, int32 length, uint32 *buffer)\r
39  *      Input is a memory block "length" bytes long.\r
40  *\r
41  * Caveat:\r
42  *      Not tested for case that requires the high word of the length,\r
43  *      which would be files larger than 1/2 gig or so.\r
44  *\r
45  * Limitation:\r
46  *      sha_memory (the memory block function) will deal with blocks no longer\r
47  *      than 4 gigabytes; for longer samples, the stream version will\r
48  *      probably be most convenient (e.g. perl moby_data.pl | sha).\r
49  *\r
50  * Bugs:\r
51  *      The standard is defined for bit strings; I assume bytes.\r
52  *\r
53  * Copyright 1993, Dr. James J. Gillogly\r
54  * This code may be freely used in any application.\r
55  */\r
56 \r
57 /* #define VERSION_0 */  /* Define this to get the original SHA definition */\r
58 \r
59 #include <stdio.h>\r
60 #include <memory.h>\r
61 #include "sha.h"\r
62 \r
63 #ifdef MSDOS\r
64 # define SHA_LITTLE_ENDIAN\r
65 #endif\r
66 \r
67 #define VERBOSE\r
68 \r
69 #define TRUE  1\r
70 #define FALSE 0\r
71 \r
72 #define SUCCESS 0\r
73 #define FAILURE -1\r
74 \r
75 int sha_file();                         /* External entries */\r
76 void sha_stream(), sha_memory();\r
77 \r
78 static void nist_guts();\r
79 \r
80 #ifdef SHA_TEST_WRAP        /* make a test program */\r
81 \r
82 #define HASH_SIZE 5     /* Produces 160-bit digest of the message */\r
83 \r
84 main(argc, argv)\r
85 int argc;\r
86 char **argv;\r
87 {\r
88     uint32 hbuf[HASH_SIZE];\r
89     char *s;\r
90     int file_args = FALSE;  /* If no files, take it from stdin */\r
91     int verbose = FALSE;\r
92     int terse = FALSE;\r
93 \r
94 #ifdef MEMTEST\r
95     sha_memory("abc", 3l, hbuf);         /* NIST test value from appendix A */\r
96     if (verbose) printf("Memory:");\r
97     if (terse) printf("%08lx%08lx%08lx%08lx%08lx\n",\r
98         hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
99     else printf("%08lx %08lx %08lx %08lx %08lx\n",\r
100         hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
101 #endif\r
102 \r
103     for (++argv; --argc; ++argv)           /* March down the arg list */\r
104     {\r
105         if (**argv == '-')                 /* Process one or more flags */\r
106             for (s = &(*argv)[1]; *s; s++) /* Obfuscated C contest entry */\r
107                 switch(*s)\r
108                 {\r
109                     case 'v': case 'V':\r
110                         verbose = TRUE;\r
111                         break;\r
112                     case 't': case 'T':\r
113                         terse = TRUE;\r
114                         break;\r
115                     default:\r
116                         fprintf(stderr, "Unrecognized flag: %c\n", *s);\r
117                         return FALSE;\r
118                 }\r
119         else                            /* Process a file */\r
120         {\r
121             if (verbose) printf("%s:", *argv);\r
122             file_args = TRUE;           /* Whether or not we could read it */\r
123 \r
124             if (sha_file(*argv, hbuf) == FAILURE)\r
125                 printf("Can't open file %s.\n", *argv);\r
126             else\r
127                 if (terse) printf("%08lx%08lx%08lx%08lx%08lx\n",\r
128                     hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
129                 else printf("%08lx %08lx %08lx %08lx %08lx\n",\r
130                     hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
131         }\r
132     }\r
133     if (! file_args)    /* No file specified */\r
134     {\r
135         if (verbose) printf("%s:", *argv);\r
136         sha_stream(stdin, hbuf);\r
137 \r
138         if (terse) printf("%08lx%08lx%08lx%08lx%08lx\n",\r
139             hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
140         else printf("%08lx %08lx %08lx %08lx %08lx\n",\r
141             hbuf[0], hbuf[1], hbuf[2], hbuf[3], hbuf[4]);\r
142     }\r
143     return TRUE;\r
144 }\r
145 \r
146 #endif ONT_WRAP\r
147 \r
148 #ifdef SHA_LITTLE_ENDIAN    /* Imported from Peter Gutmann's implementation */\r
149 \r
150 /* When run on a little-endian CPU we need to perform byte reversal on an\r
151    array of longwords.  It is possible to make the code endianness-\r
152    independant by fiddling around with data at the byte level, but this\r
153    makes for very slow code, so we rely on the user to sort out endianness\r
154    at compile time */\r
155 \r
156 static void byteReverse( uint32 *buffer, int byteCount )\r
157     {\r
158     uint32 value;\r
159     int count;\r
160 \r
161     byteCount /= sizeof( uint32 );\r
162     for( count = 0; count < byteCount; count++ )\r
163         {\r
164         value = ( buffer[ count ] << 16 ) | ( buffer[ count ] >> 16 );\r
165         buffer[ count ] = ( ( value & 0xFF00FF00L ) >> 8 ) | ( ( value & 0x00FF00FFL ) << 8 );\r
166         }\r
167     }\r
168 #endif /* SHA_LITTLE_ENDIAN */\r
169 \r
170 \r
171 \r
172 union longbyte\r
173 {\r
174     uint32 W[80];        /* Process 16 32-bit words at a time */\r
175     char B[320];                /* But read them as bytes for counting */\r
176 };\r
177 \r
178 sha_file(filename, buffer)      /* Hash a file */\r
179 char *filename;\r
180 uint32 *buffer;\r
181 {\r
182     FILE *infile;\r
183 \r
184     if ((infile = fopen(filename, "rb")) == NULL)\r
185     {\r
186         int i;\r
187 \r
188         for (i = 0; i < 5; i++)\r
189             buffer[i] = 0xdeadbeef;\r
190         return FAILURE;\r
191     }\r
192     (void) sha_stream(infile, buffer);\r
193     fclose(infile);\r
194     return SUCCESS;\r
195 }\r
196 \r
197 void sha_memory(mem, length, buffer)    /* Hash a memory block */\r
198 char *mem;\r
199 uint32 length;\r
200 uint32 *buffer;\r
201 {\r
202     nist_guts(FALSE, (FILE *) NULL, mem, length, buffer);\r
203 }\r
204 \r
205 void sha_stream(stream, buffer)\r
206 FILE *stream;\r
207 uint32 *buffer;\r
208 {\r
209     nist_guts(TRUE, stream, (char *) NULL, 0l, buffer);\r
210 }\r
211 \r
212 #define f0(x,y,z) (z ^ (x & (y ^ z)))           /* Magic functions */\r
213 #define f1(x,y,z) (x ^ y ^ z)\r
214 #define f2(x,y,z) ((x & y) | (z & (x | y)))\r
215 #define f3(x,y,z) (x ^ y ^ z)\r
216 \r
217 #define K0 0x5a827999                           /* Magic constants */\r
218 #define K1 0x6ed9eba1\r
219 #define K2 0x8f1bbcdc\r
220 #define K3 0xca62c1d6\r
221 \r
222 #define S(n, X) ((X << n) | (X >> (32 - n)))    /* Barrel roll */\r
223 \r
224 #define r0(f, K) \\r
225     temp = S(5, A) + f(B, C, D) + E + *p0++ + K; \\r
226     E = D;  \\r
227     D = C;  \\r
228     C = S(30, B); \\r
229     B = A;  \\r
230     A = temp\r
231 \r
232 #ifdef VERSION_0\r
233 #define r1(f, K) \\r
234     temp = S(5, A) + f(B, C, D) + E + \\r
235            (*p0++ = *p1++ ^ *p2++ ^ *p3++ ^ *p4++) + K; \\r
236     E = D;  \\r
237     D = C;  \\r
238     C = S(30, B); \\r
239     B = A;  \\r
240     A = temp\r
241 #else                   /* Version 1: Summer '94 update */\r
242 #define r1(f, K) \\r
243     temp = *p1++ ^ *p2++ ^ *p3++ ^ *p4++; \\r
244     temp = S(5, A) + f(B, C, D) + E + (*p0++ = S(1,temp)) + K; \\r
245     E = D;  \\r
246     D = C;  \\r
247     C = S(30, B); \\r
248     B = A;  \\r
249     A = temp\r
250 #endif\r
251 \r
252 static void nist_guts(file_flag, stream, mem, length, buf)\r
253 int file_flag;                  /* Input from memory, or from stream? */\r
254 FILE *stream;\r
255 char *mem;\r
256 uint32 length;\r
257 uint32 *buf;\r
258 {\r
259     int i, nread, nbits;\r
260     union longbyte d;\r
261     uint32 hi_length, lo_length;\r
262     int padded;\r
263     char *s;\r
264 \r
265     register uint32 *p0, *p1, *p2, *p3, *p4;\r
266     uint32 A, B, C, D, E, temp;\r
267 \r
268     uint32 h0, h1, h2, h3, h4;\r
269 \r
270     h0 = 0x67452301;                            /* Accumulators */\r
271     h1 = 0xefcdab89;\r
272     h2 = 0x98badcfe;\r
273     h3 = 0x10325476;\r
274     h4 = 0xc3d2e1f0;\r
275 \r
276     padded = FALSE;\r
277     s = mem;\r
278     for (hi_length = lo_length = 0; ;)  /* Process 16 longs at a time */\r
279     {\r
280         if (file_flag)\r
281         {\r
282                 nread = fread(d.B, 1, 64, stream);  /* Read as 64 bytes */\r
283         }\r
284         else\r
285         {\r
286                 if (length < 64) nread = length;\r
287                 else             nread = 64;\r
288                 length -= nread;\r
289                 memcpy(d.B, s, nread);\r
290                 s += nread;\r
291         }\r
292         if (nread < 64)   /* Partial block? */\r
293         {\r
294                 nbits = nread << 3;               /* Length: bits */\r
295                 if ((lo_length += nbits) < (unsigned int)nbits)\r
296                         hi_length++;              /* 64-bit integer */\r
297 \r
298                 if (nread < 64 && ! padded)  /* Append a single bit */\r
299                 {\r
300                         d.B[nread++] = (char)0x80; /* Using up next byte */\r
301                         padded = TRUE;       /* Single bit once */\r
302                 }\r
303                 for (i = nread; i < 64; i++) /* Pad with nulls */\r
304                         d.B[i] = 0;\r
305                 if (nread <= 56)   /* Room for length in this block */\r
306                 {\r
307                         d.W[14] = hi_length;\r
308                         d.W[15] = lo_length;\r
309 #ifdef SHA_LITTLE_ENDIAN\r
310               byteReverse(d.W, 56 );\r
311 #endif /* SHA_LITTLE_ENDIAN */\r
312                 }\r
313 #ifdef SHA_LITTLE_ENDIAN\r
314            else byteReverse(d.W, 64 );\r
315 #endif /* SHA_LITTLE_ENDIAN */\r
316         }\r
317         else    /* Full block -- get efficient */\r
318         {\r
319                 if ((lo_length += 512) < 512)\r
320                         hi_length++;    /* 64-bit integer */\r
321 #ifdef SHA_LITTLE_ENDIAN\r
322            byteReverse(d.W, 64 );\r
323 #endif /* SHA_LITTLE_ENDIAN */\r
324         }\r
325 \r
326         p0 = d.W;\r
327         A = h0; B = h1; C = h2; D = h3; E = h4;\r
328 \r
329         r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);\r
330         r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);\r
331         r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);\r
332         r0(f0,K0);\r
333 \r
334         p1 = &d.W[13]; p2 = &d.W[8]; p3 = &d.W[2]; p4 = &d.W[0];\r
335 \r
336                    r1(f0,K0); r1(f0,K0); r1(f0,K0); r1(f0,K0);\r
337         r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);\r
338         r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);\r
339         r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);\r
340         r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);\r
341         r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);\r
342         r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);\r
343         r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);\r
344         r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);\r
345         r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);\r
346         r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);\r
347         r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);\r
348         r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);\r
349 \r
350         h0 += A; h1 += B; h2 += C; h3 += D; h4 += E;\r
351 \r
352         if (nread <= 56) break; /* If it's greater, length in next block */\r
353     }\r
354     buf[0] = h0; buf[1] = h1; buf[2] = h2; buf[3] = h3; buf[4] = h4;\r
355 }\r