1/* rndlinux.c - raw random number for OSes with /dev/random 2 * Copyright (C) 1998, 2001, 2002, 2003, 2007, 3 * 2009 Free Software Foundation, Inc. 4 * 5 * This file is part of Libgcrypt. 6 * 7 * Libgcrypt is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * Libgcrypt is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 22#include <config.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <errno.h> 26#include <sys/time.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#ifdef HAVE_GETTIMEOFDAY 30# include <sys/times.h> 31#endif 32#include <string.h> 33#include <unistd.h> 34#include <fcntl.h> 35#include "types.h" 36#include "g10lib.h" 37#include "rand-internal.h" 38 39static int open_device ( const char *name ); 40 41 42static int 43set_cloexec_flag (int fd) 44{ 45 int oldflags; 46 47 oldflags= fcntl (fd, F_GETFD, 0); 48 if (oldflags < 0) 49 return oldflags; 50 oldflags |= FD_CLOEXEC; 51 return fcntl (fd, F_SETFD, oldflags); 52} 53 54 55 56/* 57 * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). 58 */ 59static int 60open_device ( const char *name ) 61{ 62 int fd; 63 64 fd = open ( name, O_RDONLY ); 65 if ( fd == -1 ) 66 log_fatal ("can't open %s: %s\n", name, strerror(errno) ); 67 68 if (set_cloexec_flag (fd)) 69 log_error ("error setting FD_CLOEXEC on fd %d: %s\n", 70 fd, strerror (errno)); 71 72 /* We used to do the following check, however it turned out that this 73 is not portable since more OSes provide a random device which is 74 sometimes implemented as another device type. 75 76 struct stat sb; 77 78 if( fstat( fd, &sb ) ) 79 log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); 80 if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) 81 log_fatal("invalid random device!\n" ); 82 */ 83 return fd; 84} 85 86 87int 88_gcry_rndlinux_gather_random (void (*add)(const void*, size_t, 89 enum random_origins), 90 enum random_origins origin, 91 size_t length, int level ) 92{ 93 static int fd_urandom = -1; 94 static int fd_random = -1; 95 int fd; 96 int n; 97 byte buffer[768]; 98 size_t n_hw; 99 size_t want = length; 100 size_t last_so_far = 0; 101 int any_need_entropy = 0; 102 int delay; 103 104 /* First read from a hardware source. However let it account only 105 for up to 50% of the requested bytes. */ 106 n_hw = _gcry_rndhw_poll_slow (add, origin); 107 if (n_hw > length/2) 108 n_hw = length/2; 109 if (length > 1) 110 length -= n_hw; 111 112 /* Open the requested device. */ 113 if (level >= 2) 114 { 115 if( fd_random == -1 ) 116 fd_random = open_device ( NAME_OF_DEV_RANDOM ); 117 fd = fd_random; 118 } 119 else 120 { 121 if( fd_urandom == -1 ) 122 fd_urandom = open_device ( NAME_OF_DEV_URANDOM ); 123 fd = fd_urandom; 124 } 125 126 /* Enter the read loop. */ 127 delay = 0; /* Start with 0 seconds so that we do no block on the 128 first iteration and in turn call the progress function 129 before blocking. To give the OS a better chance to 130 return with something we will actually use 100ms. */ 131 while (length) 132 { 133 fd_set rfds; 134 struct timeval tv; 135 int rc; 136 137 FD_ZERO(&rfds); 138 FD_SET(fd, &rfds); 139 tv.tv_sec = delay; 140 tv.tv_usec = delay? 0 : 100000; 141 if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) 142 { 143 if (!any_need_entropy || last_so_far != (want - length) ) 144 { 145 last_so_far = want - length; 146 _gcry_random_progress ("need_entropy", 'X', 147 (int)last_so_far, (int)want); 148 any_need_entropy = 1; 149 } 150 delay = 3; /* Use 3 seconds henceforth. */ 151 continue; 152 } 153 else if( rc == -1 ) 154 { 155 log_error ("select() error: %s\n", strerror(errno)); 156 if (!delay) 157 delay = 1; /* Use 1 second if we encounter an error before 158 we have ever blocked. */ 159 continue; 160 } 161 162 do 163 { 164 int nbytes = length < sizeof(buffer)? length : sizeof(buffer); 165 n = read(fd, buffer, nbytes ); 166 if( n >= 0 && n > nbytes ) 167 { 168 log_error("bogus read from random device (n=%d)\n", n ); 169 n = nbytes; 170 } 171 } 172 while( n == -1 && errno == EINTR ); 173 if ( n == -1 ) 174 log_fatal("read error on random device: %s\n", strerror(errno)); 175 (*add)( buffer, n, origin ); 176 length -= n; 177 } 178 memset(buffer, 0, sizeof(buffer) ); 179 180 if (any_need_entropy) 181 _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want); 182 183 return 0; /* success */ 184} 185