source: trunk/third/ssh/randoms.c @ 12646

Revision 12646, 13.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2
3random.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Sat Mar  4 14:55:57 1995 ylo
11
12Cryptographically strong random number generation.
13
14*/
15
16/*
17 * $Id: randoms.c,v 1.1.1.3 1999-03-08 17:43:11 danw Exp $
18 * $Log: not supported by cvs2svn $
19 * Revision 1.4  1998/05/23  20:23:13  kivinen
20 *      Changed uint32 to word32.
21 *
22 * Revision 1.3  1998/04/17  00:39:38  kivinen
23 *      Removed sys/resource.h including (it is already included in
24 *      the includes.h).
25 *
26 * Revision 1.2  1997/03/26 05:35:54  kivinen
27 *      Added HAVE_NO_TZ_IN_GETTIMEOFDAY support.
28 *
29 * Revision 1.1.1.1  1996/02/18 21:38:11  ylo
30 *      Imported ssh-1.2.13.
31 *
32 * Revision 1.6  1995/10/02  01:25:24  ylo
33 *      Added a cast to avoid compiler warning; also minor change in
34 *      noise collection.
35 *
36 * Revision 1.5  1995/09/21  17:12:23  ylo
37 *      Don't use the second argument of gettimeofday.
38 *
39 * Revision 1.4  1995/09/13  11:59:07  ylo
40 *      Large modifications to make this work on machines without 32
41 *      bit integer type (Cray).
42 *
43 * Revision 1.3  1995/08/29  22:22:50  ylo
44 *      Removed extra '&'.
45 *
46 * Revision 1.2  1995/07/13  01:29:20  ylo
47 *      Removed "Last modified" header.
48 *      Added cvs log.
49 *
50 * $Endlog$
51 */
52
53#include "includes.h"
54#include "randoms.h"
55#include "getput.h"
56#include "userfile.h"
57
58#ifdef HAVE_GETRUSAGE
59#ifdef HAVE_RUSAGE_H
60#include <sys/rusage.h>
61#endif /* HAVE_RUSAGE_H */
62#endif /* HAVE_GETRUSAGE */
63
64#ifdef HAVE_TIMES
65#include <sys/times.h>
66#endif /* HAVE_TIMES */
67
68/* Initializes the random number generator, loads any random information
69   from the given file, and acquires as much environmental noise as it
70   can to initialize the random number generator.  More noise can be
71   acquired later by calling random_add_noise + random_stir, or by
72   calling random_get_environmental_noise again later when the environmental
73   situation has changed.  All I/O will be done with the given uid using
74   userfile. */
75
76void random_initialize(RandomState *state, uid_t uid, const char *filename)
77{
78  char buf[8192];
79  int bytes;
80  UserFile uf;
81 
82  state->add_position = 0;
83  state->next_available_byte = sizeof(state->stir_key);
84  state->last_dev_random_usage = 0;
85
86  /* This isn't strictly necessary, but will keep programs like 3rd degree or
87     purify silent. */
88  memset(state->state, 0, sizeof(state->state));
89
90  /* Get noise from the file. */
91  random_add_noise(state, filename, strlen(filename)); /* Use the path. */
92  uf = userfile_open(uid, filename, O_RDONLY, 0);
93  if (uf != NULL)
94    {
95      state->state[0] += (int)uf;
96      bytes = userfile_read(uf, buf, sizeof(buf));
97      userfile_close(uf);
98      if (bytes > 0)
99        random_add_noise(state, buf, bytes);
100      memset(buf, 0, sizeof(buf));
101    }
102  else
103    {
104      /* Get all possible noise since we have no seed. */
105      random_acquire_environmental_noise(state, uid);
106      random_save(state, uid, filename);
107    }
108
109  /* Get easily available noise from the environment. */
110  random_acquire_light_environmental_noise(state);
111}
112
113void random_xor_noise(RandomState *state, unsigned int i, word32 value)
114{
115  value ^= GET_32BIT(state->state + 4 * i);
116  PUT_32BIT(state->state + 4 * i, value);
117}
118
119/* Acquires as much environmental noise as it can.  This is probably quite
120   sufficient on a unix machine, but might be grossly inadequate on a
121   single-user PC or a Macintosh.
122
123   We test the elapsed real time after each command, and abort if we have
124   consumed over 30 seconds.  */
125
126void random_acquire_environmental_noise(RandomState *state, uid_t uid)
127{
128  time_t start_time;
129
130  /* Record the start time. */
131  start_time = time(NULL);
132
133  /* Run these first so that other statistics accumulate from these.  We stop
134     collecting more noise when we have spent 30 seconds real time; on a large
135     system a single executed command is probably enough, whereas on small
136     systems we must use all possible noise sources. */
137  random_get_noise_from_command(state, uid, "ps laxww 2>/dev/null");
138  if (time(NULL) - start_time < 30)
139    random_get_noise_from_command(state, uid, "ps -al 2>/dev/null");
140  if (time(NULL) - start_time < 30)
141    random_get_noise_from_command(state, uid, "ls -alni /tmp/. 2>/dev/null");
142  if (time(NULL) - start_time < 30)
143    random_get_noise_from_command(state, uid, "w 2>/dev/null");
144  if (time(NULL) - start_time < 30)
145    random_get_noise_from_command(state, uid, "netstat -s 2>/dev/null");
146  if (time(NULL) - start_time < 30)
147    random_get_noise_from_command(state, uid, "netstat -an 2>/dev/null");
148  if (time(NULL) - start_time < 30)
149    random_get_noise_from_command(state, uid, "netstat -in 2>/dev/null");
150
151  /* Get other easily available noise. */
152  random_acquire_light_environmental_noise(state);
153}
154
155/* Acquires easily available environmental noise. */
156
157void random_acquire_light_environmental_noise(RandomState *state)
158{
159  int f;
160  char buf[32];
161  int len;
162
163  /* Stir first to make all bits depend on all other bits (some of
164     them not revealed to callers). */
165  random_stir(state);
166
167  /* About every five minutes, mix in some noise from /dev/random. */
168  if (time(NULL) - state->last_dev_random_usage > 5 * 60)
169    {
170      state->last_dev_random_usage = time(NULL);
171
172      /* If /dev/random is available, read some data from there in non-blocking
173         mode and mix it into the pool. */
174      f = open("/dev/random", O_RDONLY);
175      if (f >= 0)
176        {
177          /* Set the descriptor into non-blocking mode. */
178#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
179          fcntl(f, F_SETFL, O_NONBLOCK);
180#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
181          fcntl(f, F_SETFL, O_NDELAY);
182#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
183          len = read(f, buf, sizeof(buf));
184          close(f);
185          if (len > 0)
186            random_add_noise(state, buf, len);
187        }
188    }
189
190  /* Get miscellaneous noise from various system parameters and statistics. */
191  random_xor_noise(state,
192                   (unsigned int)(state->state[0] + 256*state->state[1]) %
193                     (RANDOM_STATE_BYTES / 4),
194                   (word32)time(NULL));
195
196#ifdef HAVE_GETTIMEOFDAY
197  {
198    struct timeval tv;
199#ifdef HAVE_NO_TZ_IN_GETTIMEOFDAY
200    gettimeofday(&tv);
201#else
202    gettimeofday(&tv, NULL);
203#endif
204    random_xor_noise(state, 0, (word32)tv.tv_usec);
205    random_xor_noise(state, 1, (word32)tv.tv_sec);
206#ifdef HAVE_CLOCK
207    random_xor_noise(state, 3, (word32)clock());
208#endif /* HAVE_CLOCK */
209 }
210#endif /* HAVE_GETTIMEOFDAY */
211#ifdef HAVE_TIMES
212  {
213    struct tms tm;
214    random_xor_noise(state, 2, (word32)times(&tm));
215    random_xor_noise(state, 4, (word32)(tm.tms_utime ^ (tm.tms_stime << 8) ^
216                                        (tm.tms_cutime << 16) ^
217                                        (tm.tms_cstime << 24)));
218  }
219#endif /* HAVE_TIMES */
220#ifdef HAVE_GETRUSAGE
221  {
222    struct rusage ru, cru;
223    getrusage(RUSAGE_SELF, &ru);
224    getrusage(RUSAGE_CHILDREN, &cru);
225    random_xor_noise(state, 0, (word32)(ru.ru_utime.tv_usec +
226                                        cru.ru_utime.tv_usec));
227    random_xor_noise(state, 2, (word32)(ru.ru_stime.tv_usec +
228                                        cru.ru_stime.tv_usec));
229    random_xor_noise(state, 5, (word32)(ru.ru_maxrss + cru.ru_maxrss));
230    random_xor_noise(state, 6, (word32)(ru.ru_ixrss + cru.ru_ixrss));
231    random_xor_noise(state, 7, (word32)(ru.ru_idrss + cru.ru_idrss));
232    random_xor_noise(state, 8, (word32)(ru.ru_minflt + cru.ru_minflt));
233    random_xor_noise(state, 9, (word32)(ru.ru_majflt + cru.ru_majflt));
234    random_xor_noise(state, 10, (word32)(ru.ru_nswap + cru.ru_nswap));
235    random_xor_noise(state, 11, (word32)(ru.ru_inblock + cru.ru_inblock));
236    random_xor_noise(state, 12, (word32)(ru.ru_oublock + cru.ru_oublock));
237    random_xor_noise(state, 13, (word32)((ru.ru_msgsnd ^ ru.ru_msgrcv ^
238                                          ru.ru_nsignals) +
239                                         (cru.ru_msgsnd ^ cru.ru_msgrcv ^
240                                          cru.ru_nsignals)));
241    random_xor_noise(state, 14, (word32)(ru.ru_nvcsw + cru.ru_nvcsw));
242    random_xor_noise(state, 15, (word32)(ru.ru_nivcsw + cru.ru_nivcsw));
243  }
244#endif /* HAVE_GETRUSAGE */
245  random_xor_noise(state, 11, (word32)getpid());
246  random_xor_noise(state, 12, (word32)getppid());
247  random_xor_noise(state, 10, (word32)getuid());
248  random_xor_noise(state, 10, (word32)(getgid() << 16));
249#ifdef _POSIX_CHILD_MAX
250  random_xor_noise(state, 13, (word32)(_POSIX_CHILD_MAX << 16));
251#endif /* _POSIX_CHILD_MAX */
252#ifdef CLK_TCK
253  random_xor_noise(state, 14, (word32)(CLK_TCK << 16));
254#endif /* CLK_TCK */
255
256  random_stir(state);
257}
258
259/* Executes the given command, and processes its output as noise.  The
260   command will be run via userfile with the given uid. */
261
262void random_get_noise_from_command(RandomState *state, uid_t uid,
263                                   const char *cmd)
264{
265  char line[1000];
266  UserFile uf;
267
268  uf = userfile_popen(uid, cmd, "r");
269  if (uf == NULL)
270    return;
271  while (userfile_gets(line, sizeof(line), uf))
272    random_add_noise(state, line, strlen(line));
273  userfile_pclose(uf);
274  memset(line, 0, sizeof(line));
275}
276
277/* Adds the contents of the buffer as noise. */
278
279void random_add_noise(RandomState *state, const void *buf, unsigned int bytes)
280{
281  unsigned int pos = state->add_position;
282  const char *input = buf;
283  while (bytes > 0)
284    {
285      if (pos >= RANDOM_STATE_BYTES)
286        {
287          pos = 0;
288          random_stir(state);
289        }
290      state->state[pos] ^= *input;
291      input++;
292      bytes--;
293      pos++;
294    }
295  state->add_position = pos;
296}
297
298/* Stirs the random pool to consume any newly acquired noise or to get more
299   random numbers.
300
301   This works by encrypting the data in the buffer in CFB mode with MD5 as
302   the cipher. */
303
304void random_stir(RandomState *state)
305{
306  word32 iv[4];
307  unsigned int i;
308
309  /* Start IV from last block of random pool. */
310  iv[0] = GET_32BIT(state->state);
311  iv[1] = GET_32BIT(state->state + 4);
312  iv[2] = GET_32BIT(state->state + 8);
313  iv[3] = GET_32BIT(state->state + 12);
314
315  /* First CFB pass. */
316  for (i = 0; i < RANDOM_STATE_BYTES; i += 16)
317    {
318      MD5Transform(iv, state->stir_key);
319      iv[0] ^= GET_32BIT(state->state + i);
320      PUT_32BIT(state->state + i, iv[0]);
321      iv[1] ^= GET_32BIT(state->state + i + 4);
322      PUT_32BIT(state->state + i + 4, iv[1]);
323      iv[2] ^= GET_32BIT(state->state + i + 8);
324      PUT_32BIT(state->state + i + 8, iv[2]);
325      iv[3] ^= GET_32BIT(state->state + i + 12);
326      PUT_32BIT(state->state + i + 12, iv[3]);
327    }
328
329  /* Get new key. */
330  memcpy(state->stir_key, state->state, sizeof(state->stir_key));
331
332  /* Second CFB pass. */
333  for (i = 0; i < RANDOM_STATE_BYTES; i += 16)
334    {
335      MD5Transform(iv, state->stir_key);
336      iv[0] ^= GET_32BIT(state->state + i);
337      PUT_32BIT(state->state + i, iv[0]);
338      iv[1] ^= GET_32BIT(state->state + i + 4);
339      PUT_32BIT(state->state + i + 4, iv[1]);
340      iv[2] ^= GET_32BIT(state->state + i + 8);
341      PUT_32BIT(state->state + i + 8, iv[2]);
342      iv[3] ^= GET_32BIT(state->state + i + 12);
343      PUT_32BIT(state->state + i + 12, iv[3]);
344    }
345 
346  memset(iv, 0, sizeof(iv));
347
348  state->add_position = 0;
349
350  /* Some data in the beginning is not returned to aboid giving an observer
351     complete knowledge of the contents of our random pool. */
352  state->next_available_byte = sizeof(state->stir_key);
353}
354
355/* Returns a random byte.  Stirs the random pool if necessary.  Acquires
356   new environmental noise approximately every five minutes. */
357
358unsigned int random_get_byte(RandomState *state)
359{
360  if (state->next_available_byte >= RANDOM_STATE_BYTES)
361    {
362      /* Get some easily available noise.  More importantly, this stirs
363         the pool. */
364      random_acquire_light_environmental_noise(state);
365    }
366  assert(state->next_available_byte < RANDOM_STATE_BYTES);
367  return state->state[state->next_available_byte++];
368}
369
370/* Saves random data in a disk file.  This is used to create a file that
371   can be used as a random seed on future runs.  Only half of the random
372   data in our pool is written to the file to avoid an observer being
373   able to deduce the contents of our random pool from the file.
374   I/O will be done using the give uid with userfile. */
375
376void random_save(RandomState *state, uid_t uid, const char *filename)
377{
378  char buf[RANDOM_STATE_BYTES / 2];  /* Save only half of its bits. */
379  int i;
380  UserFile uf;
381
382  /* Get some environmental noise to make it harder to predict previous
383     values from saved bits (besides, we have now probably consumed some
384     resources so the noise may be really useful).  This also stirs
385     the pool.  We also clear the last /dev/random usage time to take
386     noise from there if available. */
387  state->last_dev_random_usage = 0;
388  random_acquire_light_environmental_noise(state);
389
390  /* Get as many bytes as is half the size of the pool.  I am assuming
391     this will get enough randomness for it to be very useful, but will
392     not reveal enough to make it possible to determine previous or future
393     returns by the generator. */
394  for (i = 0; i < sizeof(buf); i++)
395    buf[i] = random_get_byte(state);
396
397  /* Again get a little noise and stir it to mix the unrevealed half with
398     those bits that have been saved to a file.  There should be enough
399     unrevealed bits (plus the new noise) to make it infeasible to try to
400     guess future values from the saved bits. */
401  random_acquire_light_environmental_noise(state);
402
403  /* Create and write the file.  Failure to create the file is silently
404     ignored. */
405  uf = userfile_open(uid, filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
406  if (uf != NULL)
407    {
408      /* Creation successful.  Write data to the file. */
409      userfile_write(uf, buf, sizeof(buf));
410      userfile_close(uf);
411    }
412  memset(buf, 0, sizeof(buf));
413}
414
415/* Clears the random number generator data structures. */
416
417void random_clear(RandomState *state)
418{
419  memset(state, 0, sizeof(*state));
420}
Note: See TracBrowser for help on using the repository browser.