2 * Dropbear - a SSH2 server
4 * Copyright (c) 2002,2003 Matt Johnston
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
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
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;
59 #ifdef DROPBEAR_PRNGD_SOCKET
60 struct sockaddr_un egdsock
;
64 #ifdef DROPBEAR_RANDOM_DEV
65 readfd
= open(DROPBEAR_RANDOM_DEV
, O_RDONLY
);
67 dropbear_exit("couldn't open random device");
71 #ifdef DROPBEAR_PRNGD_SOCKET
72 readfd
= connect_unix(DROPBEAR_PRNGD_SOCKET
);
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");
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");
91 /* read the actual random data */
97 struct timeval timeout
;
100 timeout
.tv_sec
= 2; /* two seconds should be enough */
104 FD_SET(readfd
, &read_fds
);
105 ret
= select(readfd
+ 1, &read_fds
, NULL
, NULL
, &timeout
);
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.");
112 readlen
= read(readfd
, &buf
[readpos
], buflen
- readpos
);
114 if (readlen
< 0 && errno
== EINTR
) {
117 dropbear_exit("error reading random source");
120 } while (readpos
< buflen
);
125 /* initialise the prng from /dev/(u)random or prngd */
128 unsigned char readbuf
[INIT_SEED_SIZE
];
132 /* initialise so that things won't warn about
133 * hashing an undefined buffer */
135 m_burn(hashpool
, sizeof(hashpool
));
138 /* get the seed data */
139 readrand(readbuf
, sizeof(readbuf
));
141 /* hash in the new seed data */
143 sha1_process(&hs
, (void*)hashpool
, sizeof(hashpool
));
144 sha1_process(&hs
, (void*)readbuf
, sizeof(readbuf
));
145 sha1_done(&hs
, hashpool
);
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() {
161 dropbear_exit("seedrandom not done");
165 gettimeofday(&tv
, NULL
);
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
) {
178 unsigned char hash
[SHA1_HASH_SIZE
];
179 unsigned int copylen
;
182 dropbear_exit("seedrandom not done");
187 sha1_process(&hs
, (void*)hashpool
, sizeof(hashpool
));
188 sha1_process(&hs
, (void*)&counter
, sizeof(counter
));
189 sha1_done(&hs
, hash
);
192 if (counter
> MAX_COUNTER
) {
196 copylen
= MIN(len
, SHA1_HASH_SIZE
);
197 memcpy(buf
, hash
, 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
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
);
218 if ((size_bits
% 8) != 0) {
222 randbuf
= (unsigned char*)m_malloc(len
);
224 genrandom(randbuf
, len
);
225 /* Mask out the unrequired bits - mp_read_unsigned_bin expects
227 randbuf
[0] &= masks
[size_bits
% 8];
229 bytes_to_mp(rand
, randbuf
, len
);
231 /* keep regenerating until we get one satisfying
233 } while (mp_cmp(rand
, max
) != MP_LT
);
234 m_burn(randbuf
, len
);