2 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
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:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
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.
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.
26 * In addition, the following conditions apply:
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)."
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/)."
38 * 3. Redistributions in source or binary form must retain an intact copy
39 * of this copyright notice and list of conditions.
42 #include "t_defines.h"
46 #endif /* HAVE_UNISTD_H */
49 #include <sys/types.h>
59 static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE];
60 static unsigned long randcnt = 0;
61 static unsigned int outpos = 0;
65 * t_envhash - Generate a 160-bit SHA hash of the environment
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 $_.
75 extern char ** environ;
86 for(ptr = environ; *ptr; ++ptr) {
87 strncpy(ebuf, *ptr, 255);
89 SHA1Update(&ctxt, ebuf, strlen(ebuf));
91 SHA1Final(out, &ctxt);
95 * t_fshash - Generate a 160-bit SHA hash from the file system
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.
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.
110 * The entire buffer is run once through SHA to obtain the final result.
123 if(stat(".", &st) >= 0) {
124 SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
127 strcpy(dotpath, "..");
128 for(i = 0; i < 40; ++i) {
129 if(stat(dotpath, &st) < 0)
131 if(st.st_ino == pinode && st.st_dev == pdev)
133 SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
136 strcat(dotpath, "/..");
140 if(fstat(0, &st) >= 0)
141 SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
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));
148 SHA1Final(out, &ctxt);
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:
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
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.
172 static char initialized = 0;
180 unsigned char envh[SHA_DIGESTSIZE];
181 unsigned char fsh[SHA_DIGESTSIZE];
182 unsigned char devrand[20];
186 unsigned long raw_truerand();
204 i = open("/dev/urandom", O_RDONLY);
206 r += read(i, preseed.devrand, sizeof(preseed.devrand));
210 /* Resort to truerand only if desperate for some Real entropy */
212 preseed.trand1 = raw_truerand();
217 gettimeofday(&t, NULL);
221 preseed.sec = t.time;
222 preseed.usec = t.millitm;
224 preseed.sec = t.tv_sec;
225 preseed.usec = t.tv_usec;
227 preseed.pid = getpid();
228 preseed.ppid = getppid();
229 t_envhash(preseed.envh);
230 t_fshash(preseed.fsh);
233 preseed.trand2 = raw_truerand();
236 SHA1Update(&ctxt, (unsigned char *) &preseed, sizeof(preseed));
237 SHA1Final(randpool, &ctxt);
239 memset((unsigned char *) &preseed, 0, sizeof(preseed));
240 memset((unsigned char *) &ctxt, 0, sizeof(ctxt));
243 #define NUM_RANDOMS 12
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:
250 * S[i+1] = SHA-1(i || S[i])
253 * where the A[i] are the output blocks starting with i=0.
254 * Each cycle generates 20 bytes of new output.
258 unsigned char * data;
264 if(size <= 0) /* t_random(NULL, 0) forces seed initialization */
267 while(size > outpos) {
269 memcpy(data, randout + (sizeof(randout) - outpos), outpos);
276 SHA1Update(&randctxt, randpool, sizeof(randpool));
277 SHA1Final(randout, &randctxt);
279 SHA1Update(&randctxt, (unsigned char *) &randcnt, sizeof(randcnt));
280 SHA1Update(&randctxt, randpool, sizeof(randpool));
281 SHA1Final(randpool, &randctxt);
283 outpos = sizeof(randout);
287 memcpy(data, randout + (sizeof(randout) - outpos), size);
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.
298 _TYPE( unsigned char * )
299 t_sessionkey(key, sk, sklen)
305 unsigned char * hbuf;
306 unsigned char hout[SHA_DIGESTSIZE];
309 while(sklen > 0 && *sk == 0) { /* Skip leading 0's */
315 if((hbuf = malloc(klen * sizeof(char))) == 0)
318 for(i = 0; i < klen; ++i)
319 hbuf[i] = sk[sklen - 2 * i - 1];
321 SHA1Update(&ctxt, hbuf, klen);
322 SHA1Final(hout, &ctxt);
323 for(i = 0; i < sizeof(hout); ++i)
324 key[2 * i] = hout[i];
326 for(i = 0; i < klen; ++i)
327 hbuf[i] = sk[sklen - 2 * i - 2];
329 SHA1Update(&ctxt, hbuf, klen);
330 SHA1Final(hout, &ctxt);
331 for(i = 0; i < sizeof(hout); ++i)
332 key[2 * i + 1] = hout[i];
334 memset(hout, 0, sizeof(hout));
335 memset(hbuf, 0, klen);