add chaos_calmer branch
[15.05/openwrt.git] / package / network / services / ead / src / tinysrp / t_misc.c
1 /*
2  * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
18  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
21  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
22  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
23  * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
24  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25  *
26  * In addition, the following conditions apply:
27  *
28  * 1. Any software that incorporates the SRP authentication technology
29  *    must display the following acknowlegment:
30  *    "This product uses the 'Secure Remote Password' cryptographic
31  *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
32  *
33  * 2. Any software that incorporates all or part of the SRP distribution
34  *    itself must also display the following acknowledgment:
35  *    "This product includes software developed by Tom Wu and Eugene
36  *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
37  *
38  * 3. Redistributions in source or binary form must retain an intact copy
39  *    of this copyright notice and list of conditions.
40  */
41
42 #include "t_defines.h"
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif /* HAVE_UNISTD_H */
47
48 #include <stdio.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52
53 #include "t_sha.h"
54
55 #ifndef NULL
56 #define NULL 0
57 #endif
58
59 static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE];
60 static unsigned long randcnt = 0;
61 static unsigned int outpos = 0;
62 SHA1_CTX randctxt;
63
64 /*
65  * t_envhash - Generate a 160-bit SHA hash of the environment
66  *
67  * This routine performs an SHA hash of all the "name=value" pairs
68  * in the environment concatenated together and dumps them in the
69  * output.  While it is true that anyone on the system can see
70  * your environment, someone not on the system will have a very
71  * difficult time guessing it, especially since some systems play
72  * tricks with variable ordering and sometimes define quirky
73  * environment variables like $WINDOWID or $_.
74  */
75 extern char ** environ;
76
77 static void
78 t_envhash(out)
79      unsigned char * out;
80 {
81   char ** ptr;
82   char ebuf[256];
83   SHA1_CTX ctxt;
84
85   SHA1Init(&ctxt);
86   for(ptr = environ; *ptr; ++ptr) {
87     strncpy(ebuf, *ptr, 255);
88     ebuf[255] = '\0';
89     SHA1Update(&ctxt, ebuf, strlen(ebuf));
90   }
91   SHA1Final(out, &ctxt);
92 }
93
94 /*
95  * t_fshash - Generate a 160-bit SHA hash from the file system
96  *
97  * This routine climbs up the directory tree from the current
98  * directory, running stat() on each directory until it hits the
99  * root directory.  This information is sensitive to the last
100  * access/modification times of all the directories above you,
101  * so someone who lists one of those directories injects some
102  * entropy into the system.  Obviously, this hash is very sensitive
103  * to your current directory when the program is run.
104  *
105  * For good measure, it also performs an fstat on the standard input,
106  * usually your tty, throws that into the buffer, creates a file in
107  * /tmp (the inode is unpredictable on a busy system), and runs stat()
108  * on that before deleting it.
109  *
110  * The entire buffer is run once through SHA to obtain the final result.
111  */
112 static void
113 t_fshash(out)
114      unsigned char * out;
115 {
116   char dotpath[128];
117   struct stat st;
118   SHA1_CTX ctxt;
119   int i, pinode;
120   dev_t pdev;
121
122   SHA1Init(&ctxt);
123   if(stat(".", &st) >= 0) {
124     SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
125     pinode = st.st_ino;
126     pdev = st.st_dev;
127     strcpy(dotpath, "..");
128     for(i = 0; i < 40; ++i) {
129       if(stat(dotpath, &st) < 0)
130         break;
131       if(st.st_ino == pinode && st.st_dev == pdev)
132         break;
133       SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
134       pinode = st.st_ino;
135       pdev = st.st_dev;
136       strcat(dotpath, "/..");
137     }
138   }
139
140   if(fstat(0, &st) >= 0)
141     SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
142
143   sprintf(dotpath, "/tmp/rnd.%d", getpid());
144   if(creat(dotpath, 0600) >= 0 && stat(dotpath, &st) >= 0)
145     SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
146   unlink(dotpath);
147
148   SHA1Final(out, &ctxt);
149 }
150
151 /*
152  * Generate a high-entropy seed for the strong random number generator.
153  * This uses a wide variety of quickly gathered and somewhat unpredictable
154  * system information.  The 'preseed' structure is assembled from:
155  *
156  *   The system time in seconds
157  *   The system time in microseconds
158  *   The current process ID
159  *   The parent process ID
160  *   A hash of the user's environment
161  *   A hash gathered from the file system
162  *   Input from a random device, if available
163  *   Timings of system interrupts
164  *
165  * The entire structure (60 bytes on most systems) is fed to SHA to produce
166  * a 160-bit seed for the strong random number generator.  It is believed
167  * that in the worst case (on a quiet system with no random device versus
168  * an attacker who has access to the system already), the seed contains at
169  * least about 80 bits of entropy.  Versus an attacker who does not have
170  * access to the system, the entropy should be slightly over 128 bits.
171  */
172 static char initialized = 0;
173
174 static struct {
175   unsigned int trand1;
176   time_t sec;
177   time_t usec;
178   short pid;
179   short ppid;
180   unsigned char envh[SHA_DIGESTSIZE];
181   unsigned char fsh[SHA_DIGESTSIZE];
182   unsigned char devrand[20];
183   unsigned int trand2;
184 } preseed;
185
186 unsigned long raw_truerand();
187
188 void
189 t_initrand()
190 {
191   SHA1_CTX ctxt;
192 #ifdef USE_FTIME
193   struct timeb t;
194 #else
195   struct timeval t;
196 #endif
197   int i, r=0;
198
199   if(initialized)
200     return;
201
202   initialized = 1;
203
204   i = open("/dev/urandom", O_RDONLY);
205   if(i > 0) {
206     r += read(i, preseed.devrand, sizeof(preseed.devrand));
207     close(i);
208   }
209
210   /* Resort to truerand only if desperate for some Real entropy */
211   if(r == 0)
212     preseed.trand1 = raw_truerand();
213
214 #ifdef USE_FTIME
215   ftime(&t);
216 #else
217   gettimeofday(&t, NULL);
218 #endif
219
220 #ifdef USE_FTIME
221   preseed.sec = t.time;
222   preseed.usec = t.millitm;
223 #else
224   preseed.sec = t.tv_sec;
225   preseed.usec = t.tv_usec;
226 #endif
227   preseed.pid = getpid();
228   preseed.ppid = getppid();
229   t_envhash(preseed.envh);
230   t_fshash(preseed.fsh);
231
232   if(r == 0)
233     preseed.trand2 = raw_truerand();
234
235   SHA1Init(&ctxt);
236   SHA1Update(&ctxt, (unsigned char *) &preseed, sizeof(preseed));
237   SHA1Final(randpool, &ctxt);
238   outpos = 0;
239   memset((unsigned char *) &preseed, 0, sizeof(preseed));
240   memset((unsigned char *) &ctxt, 0, sizeof(ctxt));
241 }
242
243 #define NUM_RANDOMS 12
244
245 /*
246  * The strong random number generator.  This uses a 160-bit seed
247  * and uses SHA-1 in a feedback configuration to generate successive
248  * outputs.  If S[0] is set to the initial seed, then:
249  *
250  *         S[i+1] = SHA-1(i || S[i])
251  *         A[i] = SHA-1(S[i])
252  *
253  * where the A[i] are the output blocks starting with i=0.
254  * Each cycle generates 20 bytes of new output.
255  */
256 _TYPE( void )
257 t_random(data, size)
258      unsigned char * data;
259      unsigned size;
260 {
261   if(!initialized)
262     t_initrand();
263
264   if(size <= 0)         /* t_random(NULL, 0) forces seed initialization */
265     return;
266
267   while(size > outpos) {
268     if(outpos > 0) {
269       memcpy(data, randout + (sizeof(randout) - outpos), outpos);
270       data += outpos;
271       size -= outpos;
272     }
273
274     /* Recycle */
275     SHA1Init(&randctxt);
276     SHA1Update(&randctxt, randpool, sizeof(randpool));
277     SHA1Final(randout, &randctxt);
278     SHA1Init(&randctxt);
279     SHA1Update(&randctxt, (unsigned char *) &randcnt, sizeof(randcnt));
280     SHA1Update(&randctxt, randpool, sizeof(randpool));
281     SHA1Final(randpool, &randctxt);
282     ++randcnt;
283     outpos = sizeof(randout);
284   }
285
286   if(size > 0) {
287     memcpy(data, randout + (sizeof(randout) - outpos), size);
288     outpos -= size;
289   }
290 }
291
292 /*
293  * The interleaved session-key hash.  This separates the even and the odd
294  * bytes of the input (ignoring the first byte if the input length is odd),
295  * hashes them separately, and re-interleaves the two outputs to form a
296  * single 320-bit value.
297  */
298 _TYPE( unsigned char * )
299 t_sessionkey(key, sk, sklen)
300      unsigned char * key;
301      unsigned char * sk;
302      unsigned sklen;
303 {
304   unsigned i, klen;
305   unsigned char * hbuf;
306   unsigned char hout[SHA_DIGESTSIZE];
307   SHA1_CTX ctxt;
308
309   while(sklen > 0 && *sk == 0) {        /* Skip leading 0's */
310     --sklen;
311     ++sk;
312   }
313
314   klen = sklen / 2;
315   if((hbuf = malloc(klen * sizeof(char))) == 0)
316     return 0;
317
318   for(i = 0; i < klen; ++i)
319     hbuf[i] = sk[sklen - 2 * i - 1];
320   SHA1Init(&ctxt);
321   SHA1Update(&ctxt, hbuf, klen);
322   SHA1Final(hout, &ctxt);
323   for(i = 0; i < sizeof(hout); ++i)
324     key[2 * i] = hout[i];
325
326   for(i = 0; i < klen; ++i)
327     hbuf[i] = sk[sklen - 2 * i - 2];
328   SHA1Init(&ctxt);
329   SHA1Update(&ctxt, hbuf, klen);
330   SHA1Final(hout, &ctxt);
331   for(i = 0; i < sizeof(hout); ++i)
332     key[2 * i + 1] = hout[i];
333
334   memset(hout, 0, sizeof(hout));
335   memset(hbuf, 0, klen);
336   free(hbuf);
337   return key;
338 }