chiark / gitweb /
changelog: start 0.6.8
[secnet.git] / sha1.c
1 /*
2 SHA-1 in C
3 By Steve Reid <sreid@sea-to-sky.net>
4 100% Public Domain
5 [I interpet this as a blanket permision -iwj.]
6
7 Note: parts of this file have been removed or modified to work in secnet.
8 Instead of using this file in new projects, I suggest you use the
9 unmodified version. SDE.
10
11 -----------------
12 Modified 7/98 
13 By James H. Brown <jbrown@burgoyne.com>
14 Still 100% Public Domain
15
16 Corrected a problem which generated improper hash values on 16 bit machines
17 Routine SHA1Update changed from
18         void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
19 len)
20 to
21         void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
22 long len)
23
24 The 'len' parameter was declared an int which works fine on 32 bit machines.
25 However, on 16 bit machines an int is too small for the shifts being done
26 against
27 it.  This caused the hash function to generate incorrect values if len was
28 greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
29
30 Since the file IO in main() reads 16K at a time, any file 8K or larger would
31 be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
32 "a"s).
33
34 I also changed the declaration of variables i & j in SHA1Update to 
35 unsigned long from unsigned int for the same reason.
36
37 These changes should make no difference to any 32 bit implementations since
38 an
39 int and a long are the same size in those environments.
40
41 --
42 I also corrected a few compiler warnings generated by Borland C.
43 1. Added #include <process.h> for exit() prototype
44 2. Removed unused variable 'j' in SHA1Final
45 3. Changed exit(0) to return(0) at end of main.
46
47 ALL changes I made can be located by searching for comments containing 'JHB'
48 -----------------
49 Modified 8/98
50 By Steve Reid <sreid@sea-to-sky.net>
51 Still 100% public domain
52
53 1- Removed #include <process.h> and used return() instead of exit()
54 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
55 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
56
57 -----------------
58 Modified 4/01
59 By Saul Kravitz <Saul.Kravitz@celera.com>
60 Still 100% PD
61 Modified to run on Compaq Alpha hardware.  
62
63 -----------------
64 (Further modifications as part of secnet.  See git history for full details.
65  - Ian Jackson et al)
66 */
67
68 /*
69 Test Vectors (from FIPS PUB 180-1)
70 "abc"
71   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
72 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
73   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
74 A million repetitions of "a"
75   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
76 */
77
78 /* #define SHA1HANDSOFF  */
79
80 #include "secnet.h"
81 #include "util.h"
82 #include <stdio.h>
83 #include <string.h>
84
85 #define SHA1HANDSOFF
86
87 #if 0
88 #ifndef  i386   /* For ALPHA  (SAK) */
89 #define LITTLE_ENDIAN 
90 typedef          long int int64;
91 typedef unsigned long int uint64;
92 typedef          int int32;
93 typedef unsigned int uint32;
94 #else  /*i386*/
95 #define LITTLE_ENDIAN 
96 typedef          long long int int64;
97 typedef unsigned long long int uint64;
98 typedef          long int int32;
99 typedef unsigned long int uint32;
100 #endif /*i386*/
101 #endif /* 0 */
102
103 /* Get types and defines from the secnet configuration */
104 /* typedef int64_t int64; */
105 typedef uint64_t uint64;
106 /* typedef int32_t int32; */
107 typedef uint32_t uint32;
108
109 /* #include <process.h> */      /* prototype for exit() - JHB */
110 /* Using return() instead of exit() - SWR */
111
112 typedef struct {
113     uint32 state[5];
114     uint32 count[2];
115     unsigned char buffer[64];
116 } SHA1_CTX;
117
118 void SHA1Transform(uint32 state[5], unsigned char const buffer[64]);
119 void SHA1Init(SHA1_CTX* context);
120 void SHA1Update(SHA1_CTX* context, unsigned char const * data, uint32 len);
121 /* JHB */
122 void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
123
124 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
125
126 /* blk0() and blk() perform the initial expand. */
127 /* I got the idea of expanding during the round function from SSLeay */
128 #ifndef WORDS_BIGENDIAN
129 #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
130     |(rol(block->l[i],8)&0x00FF00FF))
131 #else
132 #define blk0(i) block->l[i]
133 #endif
134 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
135     ^block->l[(i+2)&15]^block->l[i&15],1))
136
137 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
138 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
139 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
140 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
141 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
142 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
143
144
145 #ifdef VERBOSE  /* SAK */
146 void SHAPrintContext(SHA1_CTX *context, char *msg){
147   printf("%s (%d,%d) %x %x %x %x %x\n",
148          msg,
149          context->count[0], context->count[1], 
150          context->state[0],
151          context->state[1],
152          context->state[2],
153          context->state[3],
154          context->state[4]);
155 }
156 #endif
157
158 /* Hash a single 512-bit block. This is the core of the algorithm. */
159
160 void SHA1Transform(uint32 state[5], unsigned char const buffer[64])
161 {
162 uint32 a, b, c, d, e;
163 typedef union {
164     unsigned char c[64];
165     uint32 l[16];
166 } CHAR64LONG16;
167 CHAR64LONG16* block;
168 #ifdef SHA1HANDSOFF
169 static unsigned char workspace[64];
170     block = (CHAR64LONG16*)workspace;
171     memcpy(block, buffer, 64);
172 #else
173     block = (CHAR64LONG16*)buffer;
174 #endif
175     /* Copy context->state[] to working vars */
176     a = state[0];
177     b = state[1];
178     c = state[2];
179     d = state[3];
180     e = state[4];
181     /* 4 rounds of 20 operations each. Loop unrolled. */
182     R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
183     R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
184     R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
185     R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
186     R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
187     R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
188     R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
189     R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
190     R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
191     R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
192     R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
193     R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
194     R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
195     R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
196     R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
197     R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
198     R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
199     R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
200     R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
201     R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
202     /* Add the working vars back into context.state[] */
203     state[0] += a;
204     state[1] += b;
205     state[2] += c;
206     state[3] += d;
207     state[4] += e;
208     /* Wipe variables */
209     a = b = c = d = e = 0;
210 }
211
212
213 /* SHA1Init - Initialize new context */
214
215 void SHA1Init(SHA1_CTX* context)
216 {
217     /* SHA1 initialization constants */
218     context->state[0] = 0x67452301;
219     context->state[1] = 0xEFCDAB89;
220     context->state[2] = 0x98BADCFE;
221     context->state[3] = 0x10325476;
222     context->state[4] = 0xC3D2E1F0;
223     context->count[0] = context->count[1] = 0;
224 }
225
226
227 /* Run your data through this. */
228
229 void SHA1Update(SHA1_CTX* context, unsigned char const* data, uint32 len)       /*
230 JHB */
231 {
232 uint32 i, j;    /* JHB */
233
234 #ifdef VERBOSE
235     SHAPrintContext(context, "before");
236 #endif
237     j = (context->count[0] >> 3) & 63;
238     if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
239     context->count[1] += (len >> 29);
240     if ((j + len) > 63) {
241         memcpy(&context->buffer[j], data, (i = 64-j));
242         SHA1Transform(context->state, context->buffer);
243         for ( ; i + 63 < len; i += 64) {
244             SHA1Transform(context->state, &data[i]);
245         }
246         j = 0;
247     }
248     else i = 0;
249     memcpy(&context->buffer[j], &data[i], len - i);
250 #ifdef VERBOSE
251     SHAPrintContext(context, "after ");
252 #endif
253 }
254
255
256 /* Add padding and return the message digest. */
257
258 void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
259 {
260 uint32 i;       /* JHB */
261 unsigned char finalcount[8];
262
263     for (i = 0; i < 8; i++) {
264         finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
265          >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
266     }
267     SHA1Update(context, (unsigned char *)"\200", 1);
268     while ((context->count[0] & 504) != 448) {
269         SHA1Update(context, (unsigned char *)"\0", 1);
270     }
271     SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform()
272 */
273     for (i = 0; i < 20; i++) {
274         digest[i] = (unsigned char)
275          ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
276     }
277     /* Wipe variables */
278     i = 0;      /* JHB */
279     memset(context->buffer, 0, 64);
280     memset(context->state, 0, 20);
281     memset(context->count, 0, 8);
282     memset(finalcount, 0, 8);   /* SWR */
283 #ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
284     SHA1Transform(context->state, context->buffer);
285 #endif
286 }
287   
288 /*************************************************************/
289
290 /* Everything below here is the interface to secnet */
291 static void sha1_init(void *sst)
292 {
293     SHA1_CTX *ctx=sst;
294
295     SHA1Init(ctx);
296 }
297
298 static void sha1_update(void *sst, const void *buf, int32_t len)
299 {
300     SHA1_CTX *ctx=sst;
301
302     SHA1Update(ctx,buf,len);
303 }
304
305 static void sha1_final(void *sst, uint8_t *digest)
306 {
307     SHA1_CTX *ctx=sst;
308
309     SHA1Final(digest,ctx);
310 }
311
312 struct sha1 {
313     closure_t cl;
314     struct hash_if ops;
315 };
316
317 static struct sha1 st[1];
318 struct hash_if *const sha1_hash_if = &st->ops;
319
320 void sha1_module(dict_t *dict)
321 {
322     cstring_t testinput="abcdbcdecdefdefgefghfghigh"
323         "ijhijkijkljklmklmnlmnomnopnopq";
324     uint8_t expected[20]=
325     { 0x84,0x98,0x3e,0x44,
326       0x1c,0x3b,0xd2,0x6e,
327       0xba,0xae,0x4a,0xa1,
328       0xf9,0x51,0x29,0xe5,
329       0xe5,0x46,0x70,0xf1};
330     uint8_t digest[20];
331     int i;
332
333     st->cl.description="sha1";
334     st->cl.type=CL_HASH;
335     st->cl.apply=NULL;
336     st->cl.interface=&st->ops;
337     st->ops.hlen=20;
338     st->ops.slen=sizeof(SHA1_CTX);
339     st->ops.init=sha1_init;
340     st->ops.update=sha1_update;
341     st->ops.final=sha1_final;
342
343     dict_add(dict,"sha1",new_closure(&st->cl));
344
345     hash_hash(&st->ops,testinput,strlen(testinput),digest);
346     for (i=0; i<20; i++) {
347         if (digest[i]!=expected[i]) {
348             fatal("sha1 module failed self-test");
349         }
350     }
351 }