ea36586e3bf7882a16391e912f39a2f0933450bc
[mono.git] / mono / utils / mono-sha1.c
1 /*
2 SHA-1 in C
3 By Steve Reid <sreid@sea-to-sky.net>
4 100% Public Domain
5
6 -----------------
7 Modified 7/98 
8 By James H. Brown <jbrown@burgoyne.com>
9 Still 100% Public Domain
10
11 Corrected a problem which generated improper hash values on 16 bit machines
12 Routine mono_sha1_update changed from
13         void mono_sha1_update(MonoSHA1Context* context, unsigned char* data, unsigned int
14 len)
15 to
16         void mono_sha1_update(MonoSHA1Context* context, unsigned char* data, unsigned
17 long len)
18
19 The 'len' parameter was declared an int which works fine on 32 bit machines.
20 However, on 16 bit machines an int is too small for the shifts being done
21 against
22 it.  This caused the hash function to generate incorrect values if len was
23 greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of mono_sha1_update().
24
25 Since the file IO in main() reads 16K at a time, any file 8K or larger would
26 be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
27 "a"s).
28
29 I also changed the declaration of variables i & j in mono_sha1_update to 
30 unsigned long from unsigned int for the same reason.
31
32 These changes should make no difference to any 32 bit implementations since
33 an
34 int and a long are the same size in those environments.
35
36 --
37 I also corrected a few compiler warnings generated by Borland C.
38 1. Added #include <process.h> for exit() prototype
39 2. Removed unused variable 'j' in mono_sha1_final
40 3. Changed exit(0) to return(0) at end of main.
41
42 ALL changes I made can be located by searching for comments containing 'JHB'
43 -----------------
44 Modified 8/98
45 By Steve Reid <sreid@sea-to-sky.net>
46 Still 100% public domain
47
48 1- Removed #include <process.h> and used return() instead of exit()
49 2- Fixed overwriting of finalcount in mono_sha1_final() (discovered by Chris Hall)
50 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
51
52 -----------------
53 Modified 4/01
54 By Saul Kravitz <Saul.Kravitz@celera.com>
55 Still 100% PD
56 Modified to run on Compaq Alpha hardware.  
57
58
59 */
60
61 /*
62 Test Vectors (from FIPS PUB 180-1)
63 "abc"
64   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
65 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
66   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
67 A million repetitions of "a"
68   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
69 */
70
71 #define SHA1HANDSOFF
72
73 #include <stdio.h>
74 #include <string.h>
75 #include "mono-digest.h"
76
77
78 typedef          long int int32;
79 typedef unsigned long int uint32;
80
81 /* #include <process.h> */      /* prototype for exit() - JHB */
82 /* Using return() instead of exit() - SWR */
83
84 static void SHA1Transform(guint32 state[5], const guchar buffer[64]);
85
86 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
87
88 /* blk0() and blk() perform the initial expand. */
89 /* I got the idea of expanding during the round function from SSLeay */
90 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
91 #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
92     |(rol(block->l[i],8)&0x00FF00FF))
93 #else
94 #define blk0(i) block->l[i]
95 #endif
96 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
97     ^block->l[(i+2)&15]^block->l[i&15],1))
98
99 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
100 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
101 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
102 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
103 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
104 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
105
106
107 #ifdef VERBOSE  /* SAK */
108 static void SHAPrintContext(MonoSHA1Context *context, char *msg){
109   printf("%s (%d,%d) %x %x %x %x %x\n",
110          msg,
111          context->count[0], context->count[1], 
112          context->state[0],
113          context->state[1],
114          context->state[2],
115          context->state[3],
116          context->state[4]);
117 }
118 #endif
119
120 /* Hash a single 512-bit block. This is the core of the algorithm. */
121
122 static void SHA1Transform(guint32 state[5], const guchar buffer[64])
123 {
124 uint32 a, b, c, d, e;
125 typedef union {
126     unsigned char c[64];
127     uint32 l[16];
128 } CHAR64LONG16;
129 CHAR64LONG16* block;
130 #ifdef SHA1HANDSOFF
131 static unsigned char workspace[64];
132     block = (CHAR64LONG16*)workspace;
133     memcpy(block, buffer, 64);
134 #else
135     block = (CHAR64LONG16*)buffer;
136 #endif
137     /* Copy context->state[] to working vars */
138     a = state[0];
139     b = state[1];
140     c = state[2];
141     d = state[3];
142     e = state[4];
143     /* 4 rounds of 20 operations each. Loop unrolled. */
144     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);
145     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);
146     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);
147     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);
148     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);
149     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);
150     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);
151     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);
152     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);
153     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);
154     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);
155     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);
156     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);
157     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);
158     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);
159     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);
160     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);
161     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);
162     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);
163     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);
164     /* Add the working vars back into context.state[] */
165     state[0] += a;
166     state[1] += b;
167     state[2] += c;
168     state[3] += d;
169     state[4] += e;
170     /* Wipe variables */
171     a = b = c = d = e = 0;
172 }
173
174
175 /* mono_sha1_init - Initialize new context */
176
177 void mono_sha1_init(MonoSHA1Context* context)
178 {
179     /* SHA1 initialization constants */
180     context->state[0] = 0x67452301;
181     context->state[1] = 0xEFCDAB89;
182     context->state[2] = 0x98BADCFE;
183     context->state[3] = 0x10325476;
184     context->state[4] = 0xC3D2E1F0;
185     context->count[0] = context->count[1] = 0;
186 }
187
188
189 /* Run your data through this. */
190
191 void mono_sha1_update(MonoSHA1Context* context, const guchar* data, guint32 len)        /*
192 JHB */
193 {
194 uint32 i, j;    /* JHB */
195
196 #ifdef VERBOSE
197     SHAPrintContext(context, "before");
198 #endif
199     j = (context->count[0] >> 3) & 63;
200     if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
201     context->count[1] += (len >> 29);
202     if ((j + len) > 63) {
203         memcpy(&context->buffer[j], data, (i = 64-j));
204         SHA1Transform(context->state, context->buffer);
205         for ( ; i + 63 < len; i += 64) {
206             SHA1Transform(context->state, &data[i]);
207         }
208         j = 0;
209     }
210     else i = 0;
211     memcpy(&context->buffer[j], &data[i], len - i);
212 #ifdef VERBOSE
213     SHAPrintContext(context, "after ");
214 #endif
215 }
216
217
218 /* Add padding and return the message digest. */
219
220 void mono_sha1_final( MonoSHA1Context* context, unsigned char digest[20])
221 {
222 uint32 i;       /* JHB */
223 unsigned char finalcount[8];
224
225     for (i = 0; i < 8; i++) {
226         finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
227          >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
228     }
229     mono_sha1_update(context, (unsigned char *)"\200", 1);
230     while ((context->count[0] & 504) != 448) {
231         mono_sha1_update(context, (unsigned char *)"\0", 1);
232     }
233     mono_sha1_update(context, finalcount, 8);  /* Should cause a SHA1Transform()
234 */
235     for (i = 0; i < 20; i++) {
236         digest[i] = (unsigned char)
237          ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
238     }
239     /* Wipe variables */
240     i = 0;      /* JHB */
241     memset(context->buffer, 0, 64);
242     memset(context->state, 0, 20);
243     memset(context->count, 0, 8);
244     memset(finalcount, 0, 8);   /* SWR */
245 #ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
246     SHA1Transform(context->state, context->buffer);
247 #endif
248 }
249  
250 void
251 mono_sha1_get_digest (const gchar *buffer, gint buffer_size, guchar digest [20])
252 {       
253         MonoSHA1Context ctx;
254
255         mono_sha1_init (&ctx);
256         mono_sha1_update (&ctx, buffer, buffer_size);
257         mono_sha1_final (&ctx, digest);
258         
259 }
260
261 void
262 mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20])
263 {       
264         MonoSHA1Context ctx;
265         guchar tmp_buf[1024];
266         gint nb_bytes_read;
267         FILE *fp;
268
269         mono_sha1_init (&ctx);
270         fp = fopen(filename, "r");
271         if (!fp) {
272                 return;
273         }
274         
275         while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0)
276                 mono_sha1_update (&ctx, tmp_buf, nb_bytes_read);
277         
278         if (ferror(fp)) {
279                 fclose(fp);
280                 return;
281         } else {
282                 fclose(fp);
283         }
284
285         mono_sha1_final (&ctx, digest);
286 }
287
288 /*
289  * mono_digest_get_public_token:
290  *
291  * Get the public token from public key data.
292  * @token must point to at least 8 bytes of storage.
293  */
294 void 
295 mono_digest_get_public_token (guchar* token, const guchar *pubkey, guint32 len)
296 {
297         guchar digest [20];
298         int i;
299
300         g_return_if_fail (token != NULL);
301         mono_sha1_get_digest (pubkey, len, digest);
302         for (i = 0; i < 8; ++i)
303                 token [i] = digest [19 - i];
304 }
305