merging with main branch
[charm.git] / src / conv-ccs / ccs-auth.c
1 /*******************************************************
2 Hashing and authentication routines for CCS.
3
4 Orion Sky Lawlor, olawlor@acm.org, 7/21/2001
5 */
6
7 #include <string.h>
8 #include <stdio.h>
9 #include "sockRoutines.h"
10 #include "conv-ccs.h"
11 #include "ccs-auth.h"
12
13 /* Parse this secret key as a hex string*/
14 int CCS_AUTH_makeSecretKey(const char *str,CcsSec_secretKey *key)
15 {
16   int i;
17   memset(key->data,0,sizeof(CcsSec_secretKey));
18   for (i=0;i<sizeof(key->data);i++) {
19     int cur=0;
20     char tmp[3];
21     tmp[0]=str[2*i+0];
22     tmp[1]=str[2*i+1];
23     if (tmp[1]==0 || tmp[1]==' ' || tmp[1]=='\n') tmp[1]='0'; /*zero-pad*/
24     tmp[2]=0;
25     if (1!=sscanf(tmp,"%x",&cur)) break;
26     key->data[i]=(unsigned char)cur;
27   }
28   if (i==0) return 0;
29   else return 1;
30 }
31
32
33 /*************************************************************
34 Perform one round of the SHA-1 message hash.  Input is a set of
35 16 32-bit native words (512 bits); output is 5 32-bit native
36 words (160 bits). Because it uses native arithmetic, the 
37 implementation works equally well with 32 and 64-bit big-
38 and little-endian systems. However, when the input or output
39 is interpreted as bytes, they should be considered big-endian.
40 The speed is about 400,000 transformed blocks per second on a 
41 1 GHz machine.
42
43 Implemented and placed in the public domain by Steve Reid
44 Collected by Wei Dai (http://www.eskimo.com/~weidai/cryptlib.html)
45
46 Adapted for Charm++ by Orion Sky Lawlor, olawlor@acm.org, 7/20/2001
47 */
48 /*Contains at least the low 32 bits of a big-endian integer.*/
49 typedef unsigned int word32;
50 typedef unsigned char byte8;
51
52 static void SHA1_init(word32 *state)
53 {
54         state[0] = 0x67452301u;
55         state[1] = 0xEFCDAB89u;
56         state[2] = 0x98BADCFEu;
57         state[3] = 0x10325476u;
58         state[4] = 0xC3D2E1F0u;
59 }
60
61 static word32 rotlFixed(word32 x, word32 y)
62 {
63 #if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
64         return y ? _lrotl(x, y) : x;
65 #elif defined(__MWERKS__) && TARGET_CPU_PPC
66         return y ? __rlwinm(x,y,0,31) : x;
67 #else /*Default C version*/
68         return ((0xFFffFFffu)&(x<<y)) | (((0xFFffFFffu)&x)>>(32-y));
69 #endif
70 }
71
72 #define blk0(i) (W[i] = data[i])
73 #define blk1(i) (W[i&15] = rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1))
74
75 #define f1(x,y,z) (z^(x&(y^z)))
76 #define f2(x,y,z) (x^y^z)
77 #define f3(x,y,z) ((x&y)|(z&(x|y)))
78 #define f4(x,y,z) (x^y^z)
79
80 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
81 #define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999u+rotlFixed(v,5);w=rotlFixed(w,30);
82 #define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999u+rotlFixed(v,5);w=rotlFixed(w,30);
83 #define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1u+rotlFixed(v,5);w=rotlFixed(w,30);
84 #define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDCu+rotlFixed(v,5);w=rotlFixed(w,30);
85 #define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6u+rotlFixed(v,5);w=rotlFixed(w,30);
86
87 static void SHA1_transform(word32 *state, const word32 *data)
88 {
89     word32 W[16];
90     /* Copy context->state[] to working vars */
91     word32 a = state[0];
92     word32 b = state[1];
93     word32 c = state[2];
94     word32 d = state[3];
95     word32 e = state[4];
96     /* 4 rounds of 20 operations each. Loop unrolled. */
97     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);
98     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);
99     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);
100     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);
101     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);
102     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);
103     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);
104     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);
105     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);
106     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);
107     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);
108     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);
109     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);
110     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);
111     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);
112     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);
113     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);
114     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);
115     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);
116     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);
117     /* Add the working vars back into context.state[] */
118     state[0] += a;
119     state[1] += b;
120     state[2] += c;
121     state[3] += d;
122     state[4] += e;
123 }
124
125 /********************************************************
126 Compute the signed SHA-1 hash of this 52-byte input.
127 The 52 bytes comes about because a SHA block is 64 bytes,
128 minus an 8-byte length block and 4-byte end-of-message
129 code.  It is permissible for in to equal out.
130
131 The resulting hash code is 20 bytes long.
132 */
133 static void SHA1_hash(const byte8 *in,SHA1_hash_t *out)
134 {
135         int i;
136 #define SHA1_data_len 16 /*Length of input data (words)*/
137 #define SHA1_hash_len 5 /*Length of output hash code (words)*/
138         word32 message[SHA1_data_len];
139         word32 hash[SHA1_hash_len];
140         
141         /*Assemble the message from the user data by
142           interpreting the bytes as big-endian words.*/
143         for (i=0;i<SHA1_data_len-3;i++)
144                 message[i]=(in[i*4+0]<<24)+(in[i*4+1]<<16)+
145                            (in[i*4+2]<< 8)+(in[i*4+3]<< 0);
146         /*Paste on the end-of-message and length fields*/
147         message[13]=0x80000000u;/*End-of-message: one followed by zeros*/
148         message[14]=0x00000000u;/*High word of message length (all zero)*/
149         message[15]=512-64-32;/*Low word: message length, in bits*/
150         
151         /*Do the hash*/
152         SHA1_init(hash);
153         SHA1_transform(hash,message);
154         
155         /*Convert the result from words back to bytes*/
156         for (i=0;i<SHA1_hash_len;i++) {
157                 out->data[i*4+0]=0xffu & (hash[i]>>24);
158                 out->data[i*4+1]=0xffu & (hash[i]>>16);
159                 out->data[i*4+2]=0xffu & (hash[i]>> 8);
160                 out->data[i*4+3]=0xffu & (hash[i]>> 0);
161         }
162 }
163
164 #if SHA1_TEST_DRIVER
165 /* Tiny test driver routine-- should print out:
166 F9693B3AE7791C4ACE70CE31E4C2213F21CE900A
167 */
168 int main(int argc,char *argv[])
169 {
170         int i;
171         SHA1_hash_t h;
172         byte8 message[52]; memset(message,0,52);
173         message[0]=0x01;
174         SHA1_hash(message, &h);
175         for (i=0;i<sizeof(h);i++) printf("%02X",h.data[i]);
176         printf("\n");
177 }
178 #endif
179
180 /*Compare two hashed values-- return 1 if they differ; 0 else
181  */
182 static int SHA1_differ(const SHA1_hash_t *a,const SHA1_hash_t *b)
183 {
184   return 0!=memcmp(a->data,b->data,sizeof(SHA1_hash_t));
185 }
186
187 /********************************************************
188 Authentication routines: create a hash code; compare
189 hash codes.
190 */
191
192 /*Create a hash code of this secret key, varying "salt" value,
193 and (optional, may be NULL) request header.
194 */
195 void CCS_AUTH_hash(const CcsSec_secretKey *key,unsigned int salt,
196                    const CcsMessageHeader *hdrOrNull,SHA1_hash_t *out)
197 {
198   /*Fill the message buffer*/
199         byte8 mess[64];
200         byte8 *messCur=mess;
201
202         memset(mess,0,64);
203         memcpy(messCur,key,sizeof(CcsSec_secretKey));
204         messCur+=sizeof(CcsSec_secretKey);
205         
206         *(ChMessageInt_t *)messCur=ChMessageInt_new(salt);
207         messCur+=sizeof(ChMessageInt_t);
208         
209         if (hdrOrNull!=NULL) {
210           const int headerBytes=16; /*Only copy start of header.*/
211           memcpy(messCur,hdrOrNull,headerBytes);
212         }
213         
214         SHA1_hash(mess,out);
215 }
216            
217 /*Create a hash code as above, and compare it to the given code.*/
218 int  CCS_AUTH_differ(const CcsSec_secretKey *key,unsigned int salt,
219                    const CcsMessageHeader *hdrOrNull,SHA1_hash_t *given)
220 {
221         SHA1_hash_t cur;
222         CCS_AUTH_hash(key,salt,hdrOrNull,&cur);
223         return SHA1_differ(&cur,given);
224 }
225
226 /********************************************************
227 Randomness routines: return a good 32-bit random number.
228 */
229 #include <stdlib.h>
230
231 #if defined(_WIN32) && ! defined(__CYGWIN__)
232 #include <sys/timeb.h>
233 #else /*UNIX machine*/
234 #include <sys/time.h>
235 #include <fcntl.h>
236 #endif
237
238 void CCS_RAND_new(CCS_RAND_state *s)
239 {
240   int i,randFD;
241   static int newCount=0;
242   byte8 tmp[sizeof(s->state)];
243
244   /* State buffer starts out uninitialized. */
245   /* XOR in a linear counter */
246   s->state[32] ^= newCount++;
247
248 /*Fill the state buffer with random noise*/
249
250 #if defined(_WIN32) && ! defined(__CYGWIN__)
251   _ftime((struct _timeb *)tmp);
252   for (i=0;i<sizeof(s->state);i++)
253     s->state[i]^=tmp[i];
254 #else /*UNIX machine*/
255   /* XOR the current time of day into the state buffer*/
256   gettimeofday((struct timeval *)tmp,NULL);
257   for (i=0;i<sizeof(s->state);i++)
258     s->state[i]^=tmp[i];
259
260   /* XOR bytes from /dev/urandom into the state buffer*/
261   randFD=open("/dev/urandom",O_RDONLY);
262   if (randFD!=-1) {
263     if (sizeof(s->state)==read(randFD,tmp,sizeof(s->state)))
264       for (i=0;i<sizeof(s->state);i++)
265         s->state[i]^=tmp[i];
266     close(randFD);
267   }
268 #endif
269 }
270
271 word32 CCS_RAND_next(CCS_RAND_state *s) {
272   SHA1_hash_t ret;
273   /*Stir the state*/
274   (*(int *)(s->state))++;
275   SHA1_hash(s->state,&ret);
276   return *(word32 *)(&ret);
277 }
278
279
280
281
282
283
284
285
286
287
288
289