Sicherung
[libgcrypt.git] / cipher / rand-unix.c
1 /* rand-unix.c  -  raw random number generator for unix like OSes
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #ifdef  HAVE_GETHRTIME
31   #include <sys/times.h>
32 #endif
33 #ifndef HAVE_GETTIMEOFTIME
34   #include <sys/times.h>
35 #endif
36 #ifdef HAVE_GETRUSAGE
37   #include <sys/resource.h>
38 #endif
39 #include <string.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include "util.h"
43 #include "rmd.h"
44 #include "ttyio.h"
45 #include "i18n.h"
46 #include "rand-internal.h"
47 #ifdef USE_RAND_UNIX  /* This file is only for real systems */
48
49
50 void
51 random_poll()
52 {
53     char buf[POOLSIZE/5];
54     read_random_source( buf, POOLSIZE/5, 1 ); /* read /dev/urandom */
55     add_randomness( buf, POOLSIZE/5, 2);
56     memset( buf, 0, POOLSIZE/5);
57 }
58
59
60 void
61 fast_random_poll()
62 {
63   #if HAVE_GETHRTIME
64     {   hrtime_t tv;
65         tv = gethrtime();
66         add_randomness( &tv, sizeof(tv), 1 );
67     }
68   #elif HAVE_GETTIMEOFTIME
69     {   struct timeval tv;
70         if( gettimeofday( &tv, NULL ) )
71             BUG();
72         add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
73         add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
74     }
75   #else /* use times */
76     {   struct tms buf;
77         times( &buf );
78         add_randomness( &buf, sizeof buf, 1 );
79     }
80   #endif
81   #ifdef HAVE_GETRUSAGE
82     {   struct rusage buf;
83         if( getrusage( RUSAGE_SELF, &buf ) )
84             BUG();
85         add_randomness( &buf, sizeof buf, 1 );
86         memset( &buf, 0, sizeof buf );
87     }
88   #endif
89 }
90
91
92 #ifdef HAVE_DEV_RANDOM  /* we have the /dev/random device */
93
94 /****************
95  * Used to open the Linux /dev/random device
96  */
97 static int
98 open_device( const char *name, int minor )
99 {
100     int fd;
101     struct stat sb;
102
103     fd = open( name, O_RDONLY );
104     if( fd == -1 )
105         log_fatal("can't open %s: %s\n", name, strerror(errno) );
106     if( fstat( fd, &sb ) )
107         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
108   #if defined(__sparc__) && defined(__linux__)
109     #warning something is wrong with UltraPenguin /dev/random
110   #else
111     if( !S_ISCHR(sb.st_mode) )
112         log_fatal("invalid random device!\n" );
113   #endif
114     return fd;
115 }
116
117
118 void
119 read_random_source( byte *buffer, size_t length, int level )
120 {
121     static int fd_urandom = -1;
122     static int fd_random = -1;
123     int fd;
124     int n;
125     int warn=0;
126
127     if( level >= 2 ) {
128         if( fd_random == -1 )
129             fd_random = open_device( "/dev/random", 8 );
130         fd = fd_random;
131     }
132     else if( level == 1 ) {
133         if( fd_urandom == -1 )
134             fd_urandom = open_device( "/dev/urandom", 9 );
135         fd = fd_urandom;
136     }
137     else {
138         /* This is level 0, which only yields simple random bytes.
139          * We do not use /dev/urandom as this would remove entropy
140          * from the kernel entropy pool */
141        /* FIXME !!!! */
142
143         if( fd_urandom == -1 )
144             fd_urandom = open_device( "/dev/urandom", 9 );
145         fd = fd_urandom;
146     }
147
148
149     do {
150         fd_set rfds;
151         struct timeval tv;
152         int rc;
153
154         FD_ZERO(&rfds);
155         FD_SET(fd, &rfds);
156         tv.tv_sec = 3;
157         tv.tv_usec = 0;
158         if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) {
159             if( !warn )
160                 tty_printf( _(
161 "\n"
162 "Not enough random bytes available.  Please do some other work to give\n"
163 "the OS a chance to collect more entropy! (Need %d more bytes)\n"), length );
164             warn = 1;
165             continue;
166         }
167         else if( rc == -1 ) {
168             tty_printf("select() error: %s\n", strerror(errno));
169             continue;
170         }
171
172         assert( length < 500 );
173         do {
174             n = read(fd, buffer, length );
175             if( n >= 0 && n > length ) {
176                 log_error("bogus read from random device (n=%d)\n", n );
177                 n = length;
178             }
179         } while( n == -1 && errno == EINTR );
180         if( n == -1 )
181             log_fatal("read error on random device: %s\n", strerror(errno) );
182         assert( n <= length );
183         buffer += n;
184         length -= n;
185     } while( length );
186 }
187
188 #else /* not HAVE_DEV_RANDOM */
189
190
191 /****************
192  * The real random data collector for Unix.
193  * this function runs in a loop, waiting for commands from ctrl_fd
194  * and normally starts a collection process, which outputs random
195  * bytes to out_fd.
196  *
197  * Commands understand from ctrl_fd are single character:
198  *  'Q' = Quit the loop
199  *  'S' = Start a new collection process
200  */
201 static void
202 collector( FILE *ctrlfp, FILE *outfp )
203 {
204
205
206
207 }
208
209 #endif /* no HAVE_DEV_RANDOM */
210 #endif /* USE_RAND_UNIX */