can create v4 signatures
[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(void);
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 {
133         /* fixme: we should use a simpler one for level 0,
134          * because reading from /dev/urandom removes entropy
135          * and the next read on /dev/random may have to wait */
136         if( fd_urandom == -1 )
137             fd_urandom = open_device( "/dev/urandom", 9 );
138         fd = fd_urandom;
139     }
140
141
142     do {
143         fd_set rfds;
144         struct timeval tv;
145         int rc;
146
147         FD_ZERO(&rfds);
148         FD_SET(fd, &rfds);
149         tv.tv_sec = 3;
150         tv.tv_usec = 0;
151         if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) {
152             if( !warn )
153                 tty_printf( _(
154 "\n"
155 "Not enough random bytes available.  Please do some other work to give\n"
156 "the OS a chance to collect more entropy! (Need %d more bytes)\n"), length );
157             warn = 1;
158             continue;
159         }
160         else if( rc == -1 ) {
161             tty_printf("select() error: %s\n", strerror(errno));
162             continue;
163         }
164
165         assert( length < 500 );
166         do {
167             n = read(fd, buffer, length );
168             if( n >= 0 && n > length ) {
169                 log_error("bogus read from random device (n=%d)\n", n );
170                 n = length;
171             }
172         } while( n == -1 && errno == EINTR );
173         if( n == -1 )
174             log_fatal("read error on random device: %s\n", strerror(errno) );
175         assert( n <= length );
176         buffer += n;
177         length -= n;
178     } while( length );
179 }
180
181 #else /* not HAVE_DEV_RANDOM */
182
183
184 /****************
185  * The real random data collector for Unix.
186  * this function runs in a loop, waiting for commands from ctrl_fd
187  * and normally starts a collection process, which outputs random
188  * bytes to out_fd.
189  *
190  * Commands understand from ctrl_fd are single character:
191  *  'Q' = Quit the loop
192  *  'S' = Start a new collection process
193  */
194 static void
195 collector( FILE *ctrlfp, FILE *outfp )
196 {
197
198
199
200 }
201
202 #endif /* no HAVE_DEV_RANDOM */
203 #endif /* USE_RAND_UNIX */