Root/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
59static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE];
60static unsigned long randcnt = 0;
61static unsigned int outpos = 0;
62SHA1_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 */
75extern char ** environ;
76
77static void
78t_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 */
112static void
113t_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 */
172static char initialized = 0;
173
174static 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
186unsigned long raw_truerand();
187
188void
189t_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 )
257t_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 * )
299t_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}
339

Archive Download this file



interactive