summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/rand/md_rand.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/rand/md_rand.c')
-rw-r--r--src/lib/libcrypto/rand/md_rand.c312
1 files changed, 237 insertions, 75 deletions
diff --git a/src/lib/libcrypto/rand/md_rand.c b/src/lib/libcrypto/rand/md_rand.c
index c9a071bd22..6b158f0349 100644
--- a/src/lib/libcrypto/rand/md_rand.c
+++ b/src/lib/libcrypto/rand/md_rand.c
@@ -56,15 +56,23 @@
56 * [including the GNU Public Licence.] 56 * [including the GNU Public Licence.]
57 */ 57 */
58 58
59#define ENTROPY_NEEDED 16 /* require 128 bits = 16 bytes of randomness */
60
61#ifndef MD_RAND_DEBUG
62# ifndef NDEBUG
63# define NDEBUG
64# endif
65#endif
66
67#include <assert.h>
59#include <stdio.h> 68#include <stdio.h>
60#include <sys/types.h>
61#include <fcntl.h>
62#include <time.h> 69#include <time.h>
63#include <string.h> 70#include <string.h>
64 71
65#include "openssl/e_os.h" 72#include "openssl/e_os.h"
66 73
67#include <openssl/crypto.h> 74#include <openssl/crypto.h>
75#include <openssl/err.h>
68 76
69#if !defined(USE_MD5_RAND) && !defined(USE_SHA1_RAND) && !defined(USE_MDC2_RAND) && !defined(USE_MD2_RAND) 77#if !defined(USE_MD5_RAND) && !defined(USE_SHA1_RAND) && !defined(USE_MDC2_RAND) && !defined(USE_MD2_RAND)
70#if !defined(NO_SHA) && !defined(NO_SHA1) 78#if !defined(NO_SHA) && !defined(NO_SHA1)
@@ -130,17 +138,23 @@ static int state_num=0,state_index=0;
130static unsigned char state[STATE_SIZE+MD_DIGEST_LENGTH]; 138static unsigned char state[STATE_SIZE+MD_DIGEST_LENGTH];
131static unsigned char md[MD_DIGEST_LENGTH]; 139static unsigned char md[MD_DIGEST_LENGTH];
132static long md_count[2]={0,0}; 140static long md_count[2]={0,0};
141static double entropy=0;
142static int initialized=0;
133 143
134const char *RAND_version="RAND" OPENSSL_VERSION_PTEXT; 144const char *RAND_version="RAND" OPENSSL_VERSION_PTEXT;
135 145
136static void ssleay_rand_cleanup(void); 146static void ssleay_rand_cleanup(void);
137static void ssleay_rand_seed(const void *buf, int num); 147static void ssleay_rand_seed(const void *buf, int num);
138static void ssleay_rand_bytes(unsigned char *buf, int num); 148static void ssleay_rand_add(const void *buf, int num, double add_entropy);
149static int ssleay_rand_bytes(unsigned char *buf, int num);
150static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num);
139 151
140RAND_METHOD rand_ssleay_meth={ 152RAND_METHOD rand_ssleay_meth={
141 ssleay_rand_seed, 153 ssleay_rand_seed,
142 ssleay_rand_bytes, 154 ssleay_rand_bytes,
143 ssleay_rand_cleanup, 155 ssleay_rand_cleanup,
156 ssleay_rand_add,
157 ssleay_rand_pseudo_bytes,
144 }; 158 };
145 159
146RAND_METHOD *RAND_SSLeay(void) 160RAND_METHOD *RAND_SSLeay(void)
@@ -156,22 +170,49 @@ static void ssleay_rand_cleanup(void)
156 memset(md,0,MD_DIGEST_LENGTH); 170 memset(md,0,MD_DIGEST_LENGTH);
157 md_count[0]=0; 171 md_count[0]=0;
158 md_count[1]=0; 172 md_count[1]=0;
173 entropy=0;
159 } 174 }
160 175
161static void ssleay_rand_seed(const void *buf, int num) 176static void ssleay_rand_add(const void *buf, int num, double add)
162 { 177 {
163 int i,j,k,st_idx,st_num; 178 int i,j,k,st_idx;
179 long md_c[2];
180 unsigned char local_md[MD_DIGEST_LENGTH];
164 MD_CTX m; 181 MD_CTX m;
165 182
166#ifdef NORAND 183#ifdef NORAND
167 return; 184 return;
168#endif 185#endif
169 186
187 /*
188 * (Based on the rand(3) manpage)
189 *
190 * The input is chopped up into units of 20 bytes (or less for
191 * the last block). Each of these blocks is run through the hash
192 * function as follows: The data passed to the hash function
193 * is the current 'md', the same number of bytes from the 'state'
194 * (the location determined by in incremented looping index) as
195 * the current 'block', the new key data 'block', and 'count'
196 * (which is incremented after each use).
197 * The result of this is kept in 'md' and also xored into the
198 * 'state' at the same locations that were used as input into the
199 * hash function.
200 */
201
170 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 202 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
171 st_idx=state_index; 203 st_idx=state_index;
172 st_num=state_num;
173 204
174 state_index=(state_index+num); 205 /* use our own copies of the counters so that even
206 * if a concurrent thread seeds with exactly the
207 * same data and uses the same subarray there's _some_
208 * difference */
209 md_c[0] = md_count[0];
210 md_c[1] = md_count[1];
211
212 memcpy(local_md, md, sizeof md);
213
214 /* state_index <= state_num <= STATE_SIZE */
215 state_index += num;
175 if (state_index >= STATE_SIZE) 216 if (state_index >= STATE_SIZE)
176 { 217 {
177 state_index%=STATE_SIZE; 218 state_index%=STATE_SIZE;
@@ -182,6 +223,14 @@ static void ssleay_rand_seed(const void *buf, int num)
182 if (state_index > state_num) 223 if (state_index > state_num)
183 state_num=state_index; 224 state_num=state_index;
184 } 225 }
226 /* state_index <= state_num <= STATE_SIZE */
227
228 /* state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE]
229 * are what we will use now, but other threads may use them
230 * as well */
231
232 md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
233
185 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 234 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
186 235
187 for (i=0; i<num; i+=MD_DIGEST_LENGTH) 236 for (i=0; i<num; i+=MD_DIGEST_LENGTH)
@@ -190,7 +239,7 @@ static void ssleay_rand_seed(const void *buf, int num)
190 j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j; 239 j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j;
191 240
192 MD_Init(&m); 241 MD_Init(&m);
193 MD_Update(&m,md,MD_DIGEST_LENGTH); 242 MD_Update(&m,local_md,MD_DIGEST_LENGTH);
194 k=(st_idx+j)-STATE_SIZE; 243 k=(st_idx+j)-STATE_SIZE;
195 if (k > 0) 244 if (k > 0)
196 { 245 {
@@ -201,33 +250,107 @@ static void ssleay_rand_seed(const void *buf, int num)
201 MD_Update(&m,&(state[st_idx]),j); 250 MD_Update(&m,&(state[st_idx]),j);
202 251
203 MD_Update(&m,buf,j); 252 MD_Update(&m,buf,j);
204 MD_Update(&m,(unsigned char *)&(md_count[0]),sizeof(md_count)); 253 MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
205 MD_Final(md,&m); 254 MD_Final(local_md,&m);
206 md_count[1]++; 255 md_c[1]++;
207 256
208 buf=(const char *)buf + j; 257 buf=(const char *)buf + j;
209 258
210 for (k=0; k<j; k++) 259 for (k=0; k<j; k++)
211 { 260 {
212 state[st_idx++]^=md[k]; 261 /* Parallel threads may interfere with this,
262 * but always each byte of the new state is
263 * the XOR of some previous value of its
264 * and local_md (itermediate values may be lost).
265 * Alway using locking could hurt performance more
266 * than necessary given that conflicts occur only
267 * when the total seeding is longer than the random
268 * state. */
269 state[st_idx++]^=local_md[k];
213 if (st_idx >= STATE_SIZE) 270 if (st_idx >= STATE_SIZE)
214 {
215 st_idx=0; 271 st_idx=0;
216 st_num=STATE_SIZE;
217 }
218 } 272 }
219 } 273 }
220 memset((char *)&m,0,sizeof(m)); 274 memset((char *)&m,0,sizeof(m));
275
276 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
277 /* Don't just copy back local_md into md -- this could mean that
278 * other thread's seeding remains without effect (except for
279 * the incremented counter). By XORing it we keep at least as
280 * much entropy as fits into md. */
281 for (k = 0; k < sizeof md; k++)
282 {
283 md[k] ^= local_md[k];
284 }
285 if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
286 entropy += add;
287 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
288
289#ifndef THREADS
290 assert(md_c[1] == md_count[1]);
291#endif
221 } 292 }
222 293
223static void ssleay_rand_bytes(unsigned char *buf, int num) 294static void ssleay_rand_seed(const void *buf, int num)
295 {
296 ssleay_rand_add(buf, num, num);
297 }
298
299static void ssleay_rand_initialize(void)
224 { 300 {
225 int i,j,k,st_num,st_idx;
226 MD_CTX m;
227 static int init=1;
228 unsigned long l; 301 unsigned long l;
302#ifndef GETPID_IS_MEANINGLESS
303 pid_t curr_pid = getpid();
304#endif
229#ifdef DEVRANDOM 305#ifdef DEVRANDOM
230 int fd; 306 FILE *fh;
307#endif
308
309 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
310 /* put in some default random data, we need more than just this */
311#ifndef GETPID_IS_MEANINGLESS
312 l=curr_pid;
313 RAND_add(&l,sizeof(l),0);
314 l=getuid();
315 RAND_add(&l,sizeof(l),0);
316#endif
317 l=time(NULL);
318 RAND_add(&l,sizeof(l),0);
319
320#ifdef DEVRANDOM
321 /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD
322 * have this. Use /dev/urandom if you can as /dev/random may block
323 * if it runs out of random entries. */
324
325 if ((fh = fopen(DEVRANDOM, "r")) != NULL)
326 {
327 unsigned char tmpbuf[ENTROPY_NEEDED];
328 int n;
329
330 setvbuf(fh, NULL, _IONBF, 0);
331 n=fread((unsigned char *)tmpbuf,1,ENTROPY_NEEDED,fh);
332 fclose(fh);
333 RAND_add(tmpbuf,sizeof tmpbuf,n);
334 memset(tmpbuf,0,n);
335 }
336#endif
337#ifdef PURIFY
338 memset(state,0,STATE_SIZE);
339 memset(md,0,MD_DIGEST_LENGTH);
340#endif
341 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
342 initialized=1;
343 }
344
345static int ssleay_rand_bytes(unsigned char *buf, int num)
346 {
347 int i,j,k,st_num,st_idx;
348 int ok;
349 long md_c[2];
350 unsigned char local_md[MD_DIGEST_LENGTH];
351 MD_CTX m;
352#ifndef GETPID_IS_MEANINGLESS
353 pid_t curr_pid = getpid();
231#endif 354#endif
232 355
233#ifdef PREDICT 356#ifdef PREDICT
@@ -236,65 +359,63 @@ static void ssleay_rand_bytes(unsigned char *buf, int num)
236 359
237 for (i=0; i<num; i++) 360 for (i=0; i<num; i++)
238 buf[i]=val++; 361 buf[i]=val++;
239 return; 362 return(1);
240 } 363 }
241#endif 364#endif
242 365
366 /*
367 * (Based on the rand(3) manpage:)
368 *
369 * For each group of 10 bytes (or less), we do the following:
370 *
371 * Input into the hash function the top 10 bytes from the
372 * local 'md' (which is initialized from the global 'md'
373 * before any bytes are generated), the bytes that are
374 * to be overwritten by the random bytes, and bytes from the
375 * 'state' (incrementing looping index). From this digest output
376 * (which is kept in 'md'), the top (up to) 10 bytes are
377 * returned to the caller and the bottom (up to) 10 bytes are xored
378 * into the 'state'.
379 * Finally, after we have finished 'num' random bytes for the
380 * caller, 'count' (which is incremented) and the local and global 'md'
381 * are fed into the hash function and the results are kept in the
382 * global 'md'.
383 */
384
243 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 385 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
244 386
245 if (init) 387 if (!initialized)
388 ssleay_rand_initialize();
389
390 ok = (entropy >= ENTROPY_NEEDED);
391 if (!ok)
246 { 392 {
247 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 393 /* If the PRNG state is not yet unpredictable, then seeing
248 /* put in some default random data, we need more than 394 * the PRNG output may help attackers to determine the new
249 * just this */ 395 * state; thus we have to decrease the entropy estimate.
250 RAND_seed(&m,sizeof(m)); 396 * Once we've had enough initial seeding we don't bother to
251#ifndef MSDOS 397 * adjust the entropy count, though, because we're not ambitious
252 l=getpid(); 398 * to provide *information-theoretic* randomness.
253 RAND_seed(&l,sizeof(l));
254 l=getuid();
255 RAND_seed(&l,sizeof(l));
256#endif
257 l=time(NULL);
258 RAND_seed(&l,sizeof(l));
259
260/* #ifdef DEVRANDOM */
261 /*
262 * Use a random entropy pool device.
263 * Linux 1.3.x, OpenBSD, and FreeBSD have
264 * this. Use /dev/urandom if you can
265 * as /dev/random will block if it runs out
266 * of random entries.
267 */ 399 */
268 if ((fd = open(DEVRANDOM, O_RDONLY)) != NULL) 400 entropy -= num;
269 { 401 if (entropy < 0)
270 unsigned char tmpbuf[32]; 402 entropy = 0;
271
272 read(fd, tmpbuf, sizeof(tmpbuf));
273 /* we don't care how many bytes we read,
274 * we will just copy the 'stack' if there is
275 * nothing else :-) */
276 /* the above comment is EVIL. Security software
277 * RELIES ON THESE PRIMITIVES HAVING MORE SECURE
278 * BEHAVIOUR! Secure entropy is required in
279 * many cases! */
280 RAND_seed(tmpbuf,32);
281 memset(tmpbuf,0,32);
282 }
283/* #endif */
284#ifdef PURIFY
285 memset(state,0,STATE_SIZE);
286 memset(md,0,MD_DIGEST_LENGTH);
287#endif
288 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
289 init=0;
290 } 403 }
291 404
292 st_idx=state_index; 405 st_idx=state_index;
293 st_num=state_num; 406 st_num=state_num;
407 md_c[0] = md_count[0];
408 md_c[1] = md_count[1];
409 memcpy(local_md, md, sizeof md);
410
294 state_index+=num; 411 state_index+=num;
295 if (state_index > state_num) 412 if (state_index > state_num)
296 state_index=(state_index%state_num); 413 state_index %= state_num;
414
415 /* state[st_idx], ..., state[(st_idx + num - 1) % st_num]
416 * are now ours (but other threads may use them too) */
297 417
418 md_count[0] += 1;
298 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 419 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
299 420
300 while (num > 0) 421 while (num > 0)
@@ -302,8 +423,15 @@ static void ssleay_rand_bytes(unsigned char *buf, int num)
302 j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num; 423 j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num;
303 num-=j; 424 num-=j;
304 MD_Init(&m); 425 MD_Init(&m);
305 MD_Update(&m,&(md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2); 426#ifndef GETPID_IS_MEANINGLESS
306 MD_Update(&m,(unsigned char *)&(md_count[0]),sizeof(md_count)); 427 if (curr_pid) /* just in the first iteration to save time */
428 {
429 MD_Update(&m,(unsigned char*)&curr_pid,sizeof curr_pid);
430 curr_pid = 0;
431 }
432#endif
433 MD_Update(&m,&(local_md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2);
434 MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
307#ifndef PURIFY 435#ifndef PURIFY
308 MD_Update(&m,buf,j); /* purify complains */ 436 MD_Update(&m,buf,j); /* purify complains */
309#endif 437#endif
@@ -315,23 +443,57 @@ static void ssleay_rand_bytes(unsigned char *buf, int num)
315 } 443 }
316 else 444 else
317 MD_Update(&m,&(state[st_idx]),j); 445 MD_Update(&m,&(state[st_idx]),j);
318 MD_Final(md,&m); 446 MD_Final(local_md,&m);
319 447
320 for (i=0; i<j; i++) 448 for (i=0; i<j; i++)
321 { 449 {
450 state[st_idx++]^=local_md[i]; /* may compete with other threads */
451 *(buf++)=local_md[i+MD_DIGEST_LENGTH/2];
322 if (st_idx >= st_num) 452 if (st_idx >= st_num)
323 st_idx=0; 453 st_idx=0;
324 state[st_idx++]^=md[i];
325 *(buf++)=md[i+MD_DIGEST_LENGTH/2];
326 } 454 }
327 } 455 }
328 456
329 MD_Init(&m); 457 MD_Init(&m);
330 MD_Update(&m,(unsigned char *)&(md_count[0]),sizeof(md_count)); 458 MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
331 md_count[0]++; 459 MD_Update(&m,local_md,MD_DIGEST_LENGTH);
460 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
332 MD_Update(&m,md,MD_DIGEST_LENGTH); 461 MD_Update(&m,md,MD_DIGEST_LENGTH);
333 MD_Final(md,&m); 462 MD_Final(md,&m);
463 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
464
334 memset(&m,0,sizeof(m)); 465 memset(&m,0,sizeof(m));
466 if (ok)
467 return(1);
468 else
469 {
470 RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
471 return(0);
472 }
473 }
474
475/* pseudo-random bytes that are guaranteed to be unique but not
476 unpredictable */
477static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
478 {
479 int ret, err;
480
481 ret = RAND_bytes(buf, num);
482 if (ret == 0)
483 {
484 err = ERR_peek_error();
485 if (ERR_GET_LIB(err) == ERR_LIB_RAND &&
486 ERR_GET_REASON(err) == RAND_R_PRNG_NOT_SEEDED)
487 (void)ERR_get_error();
488 }
489 return (ret);
490 }
491
492int RAND_status(void)
493 {
494 if (!initialized)
495 ssleay_rand_initialize();
496 return (entropy >= ENTROPY_NEEDED);
335 } 497 }
336 498
337#ifdef WINDOWS 499#ifdef WINDOWS
@@ -358,12 +520,12 @@ static void ssleay_rand_bytes(unsigned char *buf, int num)
358 */ 520 */
359/* 521/*
360 * I have modified the loading of bytes via RAND_seed() mechanism since 522 * I have modified the loading of bytes via RAND_seed() mechanism since
361 * the origional would have been very very CPU intensive since RAND_seed() 523 * the original would have been very very CPU intensive since RAND_seed()
362 * does an MD5 per 16 bytes of input. The cost to digest 16 bytes is the same 524 * does an MD5 per 16 bytes of input. The cost to digest 16 bytes is the same
363 * as that to digest 56 bytes. So under the old system, a screen of 525 * as that to digest 56 bytes. So under the old system, a screen of
364 * 1024*768*256 would have been CPU cost of approximatly 49,000 56 byte MD5 526 * 1024*768*256 would have been CPU cost of approximately 49,000 56 byte MD5
365 * digests or digesting 2.7 mbytes. What I have put in place would 527 * digests or digesting 2.7 mbytes. What I have put in place would
366 * be 48 16k MD5 digests, or efectivly 48*16+48 MD5 bytes or 816 kbytes 528 * be 48 16k MD5 digests, or effectively 48*16+48 MD5 bytes or 816 kbytes
367 * or about 3.5 times as much. 529 * or about 3.5 times as much.
368 * - eric 530 * - eric
369 */ 531 */