remove unused variable
[dropbear.git] / random.c
blobba8b2bd53b10f2bd107e66afbde9fff41937fe25
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
25 #include "includes.h"
26 #include "buffer.h"
27 #include "dbutil.h"
28 #include "bignum.h"
30 static int donerandinit = 0;
32 /* this is used to generate unique output from the same hashpool */
33 static uint32_t counter = 0;
34 /* the max value for the counter, so it won't integer overflow */
35 #define MAX_COUNTER 1<<30
37 static unsigned char hashpool[SHA1_HASH_SIZE];
39 #define INIT_SEED_SIZE 32 /* 256 bits */
41 static void readrand(unsigned char* buf, unsigned int buflen);
43 /* The basic setup is we read some data from /dev/(u)random or prngd and hash it
44 * into hashpool. To read data, we hash together current hashpool contents,
45 * and a counter. We feed more data in by hashing the current pool and new
46 * data into the pool.
48 * It is important to ensure that counter doesn't wrap around before we
49 * feed in new entropy.
53 static void readrand(unsigned char* buf, unsigned int buflen) {
55 static int already_blocked = 0;
56 int readfd;
57 unsigned int readpos;
58 int readlen;
59 #ifdef DROPBEAR_PRNGD_SOCKET
60 struct sockaddr_un egdsock;
61 char egdcmd[2];
62 #endif
64 #ifdef DROPBEAR_RANDOM_DEV
65 readfd = open(DROPBEAR_RANDOM_DEV, O_RDONLY);
66 if (readfd < 0) {
67 dropbear_exit("couldn't open random device");
69 #endif
71 #ifdef DROPBEAR_PRNGD_SOCKET
72 readfd = connect_unix(DROPBEAR_PRNGD_SOCKET);
74 if (readfd < 0) {
75 dropbear_exit("couldn't open random device");
77 /* todo - try various common locations */
78 if (connect(readfd, (struct sockaddr*)&egdsock,
79 sizeof(struct sockaddr_un)) < 0) {
80 dropbear_exit("couldn't open random device");
83 if (buflen > 255)
84 dropbear_exit("can't request more than 255 bytes from egd");
85 egdcmd[0] = 0x02; /* blocking read */
86 egdcmd[1] = (unsigned char)buflen;
87 if (write(readfd, egdcmd, 2) < 0)
88 dropbear_exit("can't send command to egd");
89 #endif
91 /* read the actual random data */
92 readpos = 0;
93 do {
94 if (!already_blocked)
96 int ret;
97 struct timeval timeout;
98 fd_set read_fds;
100 timeout.tv_sec = 2; /* two seconds should be enough */
101 timeout.tv_usec = 0;
103 FD_ZERO(&read_fds);
104 FD_SET(readfd, &read_fds);
105 ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
106 if (ret == 0)
108 dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source.");
109 already_blocked = 1;
112 readlen = read(readfd, &buf[readpos], buflen - readpos);
113 if (readlen <= 0) {
114 if (readlen < 0 && errno == EINTR) {
115 continue;
117 dropbear_exit("error reading random source");
119 readpos += readlen;
120 } while (readpos < buflen);
122 close (readfd);
125 /* initialise the prng from /dev/(u)random or prngd */
126 void seedrandom() {
128 unsigned char readbuf[INIT_SEED_SIZE];
130 hash_state hs;
132 /* initialise so that things won't warn about
133 * hashing an undefined buffer */
134 if (!donerandinit) {
135 m_burn(hashpool, sizeof(hashpool));
138 /* get the seed data */
139 readrand(readbuf, sizeof(readbuf));
141 /* hash in the new seed data */
142 sha1_init(&hs);
143 sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
144 sha1_process(&hs, (void*)readbuf, sizeof(readbuf));
145 sha1_done(&hs, hashpool);
147 counter = 0;
148 donerandinit = 1;
151 /* hash the current random pool with some unique identifiers
152 * for this process and point-in-time. this is used to separate
153 * the random pools for fork()ed processes. */
154 void reseedrandom() {
156 pid_t pid;
157 hash_state hs;
158 struct timeval tv;
160 if (!donerandinit) {
161 dropbear_exit("seedrandom not done");
164 pid = getpid();
165 gettimeofday(&tv, NULL);
167 sha1_init(&hs);
168 sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
169 sha1_process(&hs, (void*)&pid, sizeof(pid));
170 sha1_process(&hs, (void*)&tv, sizeof(tv));
171 sha1_done(&hs, hashpool);
174 /* return len bytes of pseudo-random data */
175 void genrandom(unsigned char* buf, unsigned int len) {
177 hash_state hs;
178 unsigned char hash[SHA1_HASH_SIZE];
179 unsigned int copylen;
181 if (!donerandinit) {
182 dropbear_exit("seedrandom not done");
185 while (len > 0) {
186 sha1_init(&hs);
187 sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
188 sha1_process(&hs, (void*)&counter, sizeof(counter));
189 sha1_done(&hs, hash);
191 counter++;
192 if (counter > MAX_COUNTER) {
193 seedrandom();
196 copylen = MIN(len, SHA1_HASH_SIZE);
197 memcpy(buf, hash, copylen);
198 len -= copylen;
199 buf += copylen;
201 m_burn(hash, sizeof(hash));
204 /* Generates a random mp_int.
205 * max is a *mp_int specifying an upper bound.
206 * rand must be an initialised *mp_int for the result.
207 * the result rand satisfies: 0 < rand < max
208 * */
209 void gen_random_mpint(mp_int *max, mp_int *rand) {
211 unsigned char *randbuf = NULL;
212 unsigned int len = 0;
213 const unsigned char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
215 const int size_bits = mp_count_bits(max);
217 len = size_bits / 8;
218 if ((size_bits % 8) != 0) {
219 len += 1;
222 randbuf = (unsigned char*)m_malloc(len);
223 do {
224 genrandom(randbuf, len);
225 /* Mask out the unrequired bits - mp_read_unsigned_bin expects
226 * MSB first.*/
227 randbuf[0] &= masks[size_bits % 8];
229 bytes_to_mp(rand, randbuf, len);
231 /* keep regenerating until we get one satisfying
232 * 0 < rand < max */
233 } while (mp_cmp(rand, max) != MP_LT);
234 m_burn(randbuf, len);
235 m_free(randbuf);