summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/rand/md_rand_munged.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/rand/md_rand_munged.c')
-rw-r--r--src/lib/libcrypto/rand/md_rand_munged.c515
1 files changed, 515 insertions, 0 deletions
diff --git a/src/lib/libcrypto/rand/md_rand_munged.c b/src/lib/libcrypto/rand/md_rand_munged.c
new file mode 100644
index 0000000000..1611bf335b
--- /dev/null
+++ b/src/lib/libcrypto/rand/md_rand_munged.c
@@ -0,0 +1,515 @@
1/* crypto/rand/md_rand.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * "This product includes cryptographic software written by
34 * Eric Young (eay@cryptsoft.com)"
35 * The word 'cryptographic' can be left out if the rouines from the library
36 * being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 * the apps directory (application code) you must include an acknowledgement:
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed. i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#include <stdio.h>
60#include <sys/types.h>
61#include <fcntl.h>
62#include <time.h>
63#include <string.h>
64
65#include "openssl/e_os.h"
66
67#include <openssl/crypto.h>
68
69#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)
71#define USE_SHA1_RAND
72#elif !defined(NO_MD5)
73#define USE_MD5_RAND
74#elif !defined(NO_MDC2) && !defined(NO_DES)
75#define USE_MDC2_RAND
76#elif !defined(NO_MD2)
77#define USE_MD2_RAND
78#else
79#error No message digest algorithm available
80#endif
81#endif
82
83/* Changed how the state buffer used. I now attempt to 'wrap' such
84 * that I don't run over the same locations the next time go through
85 * the 1023 bytes - many thanks to
86 * Robert J. LeBlanc <rjl@renaissoft.com> for his comments
87 */
88
89#if defined(USE_MD5_RAND)
90#include <openssl/md5.h>
91#define MD_DIGEST_LENGTH MD5_DIGEST_LENGTH
92#define MD_CTX MD5_CTX
93#define MD_Init(a) MD5_Init(a)
94#define MD_Update(a,b,c) MD5_Update(a,b,c)
95#define MD_Final(a,b) MD5_Final(a,b)
96#define MD(a,b,c) MD5(a,b,c)
97#elif defined(USE_SHA1_RAND)
98#include <openssl/sha.h>
99#define MD_DIGEST_LENGTH SHA_DIGEST_LENGTH
100#define MD_CTX SHA_CTX
101#define MD_Init(a) SHA1_Init(a)
102#define MD_Update(a,b,c) SHA1_Update(a,b,c)
103#define MD_Final(a,b) SHA1_Final(a,b)
104#define MD(a,b,c) SHA1(a,b,c)
105#elif defined(USE_MDC2_RAND)
106#include <openssl/mdc2.h>
107#define MD_DIGEST_LENGTH MDC2_DIGEST_LENGTH
108#define MD_CTX MDC2_CTX
109#define MD_Init(a) MDC2_Init(a)
110#define MD_Update(a,b,c) MDC2_Update(a,b,c)
111#define MD_Final(a,b) MDC2_Final(a,b)
112#define MD(a,b,c) MDC2(a,b,c)
113#elif defined(USE_MD2_RAND)
114#include <openssl/md2.h>
115#define MD_DIGEST_LENGTH MD2_DIGEST_LENGTH
116#define MD_CTX MD2_CTX
117#define MD_Init(a) MD2_Init(a)
118#define MD_Update(a,b,c) MD2_Update(a,b,c)
119#define MD_Final(a,b) MD2_Final(a,b)
120#define MD(a,b,c) MD2(a,b,c)
121#endif
122
123#include <openssl/rand.h>
124
125/* #define NORAND 1 */
126/* #define PREDICT 1 */
127
128#define STATE_SIZE 1023
129static int state_num=0,state_index=0;
130static unsigned char state[STATE_SIZE+MD_DIGEST_LENGTH];
131static unsigned char md[MD_DIGEST_LENGTH];
132static long md_count[2]={0,0};
133static double entropy=0;
134static int initialized=0;
135
136const char *RAND_version="RAND" OPENSSL_VERSION_PTEXT;
137
138static void ssleay_rand_cleanup(void);
139static void ssleay_rand_seed(const void *buf, int num);
140static void ssleay_rand_add(const void *buf, int num, double add_entropy);
141static int ssleay_rand_bytes(unsigned char *buf, int num);
142static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num);
143
144RAND_METHOD rand_ssleay_meth={
145 ssleay_rand_seed,
146 ssleay_rand_bytes,
147 ssleay_rand_cleanup,
148 ssleay_rand_add,
149 ssleay_rand_pseudo_bytes,
150 };
151
152RAND_METHOD *RAND_SSLeay(void)
153 {
154 return(&rand_ssleay_meth);
155 }
156
157static void ssleay_rand_cleanup(void)
158 {
159 memset(state,0,sizeof(state));
160 state_num=0;
161 state_index=0;
162 memset(md,0,MD_DIGEST_LENGTH);
163 md_count[0]=0;
164 md_count[1]=0;
165 entropy=0;
166 }
167
168static void ssleay_rand_add(const void *buf, int num, double add)
169 {
170 int i,j,k,st_idx;
171 long md_c[2];
172 unsigned char local_md[MD_DIGEST_LENGTH];
173 MD_CTX m;
174
175#ifdef NORAND
176 return;
177#endif
178
179 /*
180 * (Based on the rand(3) manpage)
181 *
182 * The input is chopped up into units of 20 bytes (or less for
183 * the last block). Each of these blocks is run through the hash
184 * function as follows: The data passed to the hash function
185 * is the current 'md', the same number of bytes from the 'state'
186 * (the location determined by in incremented looping index) as
187 * the current 'block', the new key data 'block', and 'count'
188 * (which is incremented after each use).
189 * The result of this is kept in 'md' and also xored into the
190 * 'state' at the same locations that were used as input into the
191 * hash function.
192 */
193
194 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
195 st_idx=state_index;
196
197 /* use our own copies of the counters so that even
198 * if a concurrent thread seeds with exactly the
199 * same data and uses the same subarray there's _some_
200 * difference */
201 md_c[0] = md_count[0];
202 md_c[1] = md_count[1];
203
204 memcpy(local_md, md, sizeof md);
205
206 /* state_index <= state_num <= STATE_SIZE */
207 state_index += num;
208 if (state_index >= STATE_SIZE)
209 {
210 state_index%=STATE_SIZE;
211 state_num=STATE_SIZE;
212 }
213 else if (state_num < STATE_SIZE)
214 {
215 if (state_index > state_num)
216 state_num=state_index;
217 }
218 /* state_index <= state_num <= STATE_SIZE */
219
220 /* state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE]
221 * are what we will use now, but other threads may use them
222 * as well */
223
224 md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
225
226 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
227
228 for (i=0; i<num; i+=MD_DIGEST_LENGTH)
229 {
230 j=(num-i);
231 j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j;
232
233 MD_Init(&m);
234 MD_Update(&m,local_md,MD_DIGEST_LENGTH);
235 k=(st_idx+j)-STATE_SIZE;
236 if (k > 0)
237 {
238 MD_Update(&m,&(state[st_idx]),j-k);
239 MD_Update(&m,&(state[0]),k);
240 }
241 else
242 MD_Update(&m,&(state[st_idx]),j);
243
244 MD_Update(&m,buf,j);
245 MD_Update(&m,(unsigned char *)&(md_count[0]),sizeof(md_count));
246 MD_Final(md,&m);
247 md_count[1]++;
248
249 buf=(const char *)buf + j;
250
251 for (k=0; k<j; k++)
252 {
253 state[st_idx++]^=md[k];
254 if (st_idx >= STATE_SIZE)
255 {
256 st_idx=0;
257 st_num=STATE_SIZE;
258 }
259 }
260 }
261 memset((char *)&m,0,sizeof(m));
262 }
263
264static void ssleay_rand_bytes(unsigned char *buf, int num)
265 {
266 int i,j,k,st_num,st_idx;
267 MD_CTX m;
268 static int init=1;
269 unsigned long l;
270#ifdef DEVRANDOM
271 int fd;
272#endif
273
274#ifdef PREDICT
275 {
276 static unsigned char val=0;
277
278 for (i=0; i<num; i++)
279 buf[i]=val++;
280 return;
281 }
282#endif
283
284 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
285
286 if (init)
287 {
288 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
289 /* put in some default random data, we need more than
290 * just this */
291 RAND_seed(&m,sizeof(m));
292#ifndef MSDOS
293 l=getpid();
294 RAND_seed(&l,sizeof(l));
295 l=getuid();
296 RAND_seed(&l,sizeof(l));
297#endif
298 l=time(NULL);
299 RAND_seed(&l,sizeof(l));
300
301/* #ifdef DEVRANDOM */
302 /*
303 * Use a random entropy pool device.
304 * Linux 1.3.x, OpenBSD, and FreeBSD have
305 * this. Use /dev/urandom if you can
306 * as /dev/random will block if it runs out
307 * of random entries.
308 */
309 if ((fd = open(DEVRANDOM, O_RDONLY)) != NULL)
310 {
311 unsigned char tmpbuf[32];
312
313 read(fd, tmpbuf, sizeof(tmpbuf));
314 /* we don't care how many bytes we read,
315 * we will just copy the 'stack' if there is
316 * nothing else :-) */
317 /* the above comment is EVIL. Security software
318 * RELIES ON THESE PRIMITIVES HAVING MORE SECURE
319 * BEHAVIOUR! Secure entropy is required in
320 * many cases! */
321 RAND_seed(tmpbuf,32);
322 memset(tmpbuf,0,32);
323 }
324/* #endif */
325#ifdef PURIFY
326 memset(state,0,STATE_SIZE);
327 memset(md,0,MD_DIGEST_LENGTH);
328#endif
329 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
330 init=0;
331 }
332
333 st_idx=state_index;
334 st_num=state_num;
335 state_index+=num;
336 if (state_index > state_num)
337 state_index=(state_index%state_num);
338
339 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
340
341 while (num > 0)
342 {
343 j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num;
344 num-=j;
345 MD_Init(&m);
346#ifndef GETPID_IS_MEANINGLESS
347 if (curr_pid) /* just in the first iteration to save time */
348 {
349 MD_Update(&m,(unsigned char*)&curr_pid,sizeof curr_pid);
350 curr_pid = 0;
351 }
352#endif
353 MD_Update(&m,&(local_md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2);
354 MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
355#ifndef PURIFY
356 MD_Update(&m,buf,j); /* purify complains */
357#endif
358 k=(st_idx+j)-st_num;
359 if (k > 0)
360 {
361 MD_Update(&m,&(state[st_idx]),j-k);
362 MD_Update(&m,&(state[0]),k);
363 }
364 else
365 MD_Update(&m,&(state[st_idx]),j);
366 MD_Final(local_md,&m);
367
368 for (i=0; i<j; i++)
369 {
370 state[st_idx++]^=local_md[i]; /* may compete with other threads */
371 *(buf++)=local_md[i+MD_DIGEST_LENGTH/2];
372 if (st_idx >= st_num)
373 st_idx=0;
374 }
375 }
376
377 MD_Init(&m);
378 MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
379 MD_Update(&m,local_md,MD_DIGEST_LENGTH);
380 CRYPTO_w_lock(CRYPTO_LOCK_RAND);
381 MD_Update(&m,md,MD_DIGEST_LENGTH);
382 MD_Final(md,&m);
383 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
384
385 memset(&m,0,sizeof(m));
386 if (ok)
387 return(1);
388 else
389 {
390 RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
391 return(0);
392 }
393 }
394
395/* pseudo-random bytes that are guaranteed to be unique but not
396 unpredictable */
397static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
398 {
399 int ret, err;
400
401 ret = RAND_bytes(buf, num);
402 if (ret == 0)
403 {
404 err = ERR_peek_error();
405 if (ERR_GET_LIB(err) == ERR_LIB_RAND &&
406 ERR_GET_REASON(err) == RAND_R_PRNG_NOT_SEEDED)
407 (void)ERR_get_error();
408 }
409 return (ret);
410 }
411
412int RAND_status(void)
413 {
414 if (!initialized)
415 ssleay_rand_initialize();
416 return (entropy >= ENTROPY_NEEDED);
417 }
418
419#ifdef WINDOWS
420#include <windows.h>
421#include <openssl/rand.h>
422
423/*****************************************************************************
424 * Initialisation function for the SSL random generator. Takes the contents
425 * of the screen as random seed.
426 *
427 * Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
428 *
429 * Code adapted from
430 * <URL:http://www.microsoft.com/kb/developr/win_dk/q97193.htm>;
431 * the original copyright message is:
432 *
433 * (C) Copyright Microsoft Corp. 1993. All rights reserved.
434 *
435 * You have a royalty-free right to use, modify, reproduce and
436 * distribute the Sample Files (and/or any modified version) in
437 * any way you find useful, provided that you agree that
438 * Microsoft has no warranty obligations or liability for any
439 * Sample Application Files which are modified.
440 */
441/*
442 * I have modified the loading of bytes via RAND_seed() mechanism since
443 * the original would have been very very CPU intensive since RAND_seed()
444 * does an MD5 per 16 bytes of input. The cost to digest 16 bytes is the same
445 * as that to digest 56 bytes. So under the old system, a screen of
446 * 1024*768*256 would have been CPU cost of approximately 49,000 56 byte MD5
447 * digests or digesting 2.7 mbytes. What I have put in place would
448 * be 48 16k MD5 digests, or effectively 48*16+48 MD5 bytes or 816 kbytes
449 * or about 3.5 times as much.
450 * - eric
451 */
452void RAND_screen(void)
453{
454 HDC hScrDC; /* screen DC */
455 HDC hMemDC; /* memory DC */
456 HBITMAP hBitmap; /* handle for our bitmap */
457 HBITMAP hOldBitmap; /* handle for previous bitmap */
458 BITMAP bm; /* bitmap properties */
459 unsigned int size; /* size of bitmap */
460 char *bmbits; /* contents of bitmap */
461 int w; /* screen width */
462 int h; /* screen height */
463 int y; /* y-coordinate of screen lines to grab */
464 int n = 16; /* number of screen lines to grab at a time */
465
466 /* Create a screen DC and a memory DC compatible to screen DC */
467 hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
468 hMemDC = CreateCompatibleDC(hScrDC);
469
470 /* Get screen resolution */
471 w = GetDeviceCaps(hScrDC, HORZRES);
472 h = GetDeviceCaps(hScrDC, VERTRES);
473
474 /* Create a bitmap compatible with the screen DC */
475 hBitmap = CreateCompatibleBitmap(hScrDC, w, n);
476
477 /* Select new bitmap into memory DC */
478 hOldBitmap = SelectObject(hMemDC, hBitmap);
479
480 /* Get bitmap properties */
481 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
482 size = (unsigned int)bm.bmWidthBytes * bm.bmHeight * bm.bmPlanes;
483
484 bmbits = Malloc(size);
485 if (bmbits) {
486 /* Now go through the whole screen, repeatedly grabbing n lines */
487 for (y = 0; y < h-n; y += n)
488 {
489 unsigned char md[MD_DIGEST_LENGTH];
490
491 /* Bitblt screen DC to memory DC */
492 BitBlt(hMemDC, 0, 0, w, n, hScrDC, 0, y, SRCCOPY);
493
494 /* Copy bitmap bits from memory DC to bmbits */
495 GetBitmapBits(hBitmap, size, bmbits);
496
497 /* Get the MD5 of the bitmap */
498 MD(bmbits,size,md);
499
500 /* Seed the random generator with the MD5 digest */
501 RAND_seed(md, MD_DIGEST_LENGTH);
502 }
503
504 Free(bmbits);
505 }
506
507 /* Select old bitmap back into memory DC */
508 hBitmap = SelectObject(hMemDC, hOldBitmap);
509
510 /* Clean up */
511 DeleteObject(hBitmap);
512 DeleteDC(hMemDC);
513 DeleteDC(hScrDC);
514}
515#endif