blob: 81f52bc141b45e4927634389cef978b0b369f2a4 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% RRRR AAA N N DDDD OOO M M %
6% R R A A NN N D D O O MM MM %
7% RRRR AAAAA N N N D D O O M M M %
8% R R A A N NN D D O O M M %
9% R R A A N N DDDD OOO M M %
10% %
11% %
12% MagickCore Methods to Generate Random Numbers %
13% %
14% Software Design %
15% John Cristy %
16% December 2001 %
17% %
18% %
cristy7e41fe82010-12-04 23:12:08 +000019% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000020% dedicated to making software imaging solutions freely available. %
21% %
22% You may not use this file except in compliance with the License. You may %
23% obtain a copy of the License at %
24% %
25% http://www.imagemagick.org/script/license.php %
26% %
27% Unless required by applicable law or agreed to in writing, software %
28% distributed under the License is distributed on an "AS IS" BASIS, %
29% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
30% See the License for the specific language governing permissions and %
31% limitations under the License. %
32% %
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34%
35% The generation of random numbers is too important to be left to chance.
36% -- Tom Christiansen <tchrist@mox.perl.com>
37%
38%
39*/
40
41/*
42 Include declarations.
43*/
44#if defined(__VMS)
45#include <time.h>
46#endif
47#if defined(__MINGW32__)
48#include <sys/time.h>
49#endif
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/studio.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/memory_.h"
54#include "MagickCore/semaphore.h"
55#include "MagickCore/random_.h"
cristy5ff4eaf2011-09-03 01:38:02 +000056#include "MagickCore/random-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/resource_.h"
58#include "MagickCore/signature-private.h"
59#include "MagickCore/string_.h"
60#include "MagickCore/thread_.h"
61#include "MagickCore/thread-private.h"
62#include "MagickCore/utility.h"
cristy18c6c272011-09-23 14:40:37 +000063#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000064/*
65 Define declarations.
66*/
67#define PseudoRandomHash SHA256Hash
68#define RandomEntropyLevel 9
69#define RandomFilename "reservoir.xdm"
70#define RandomFiletype "random"
71#define RandomProtocolMajorVersion 1
72#define RandomProtocolMinorVersion 0
73
74/*
75 Typedef declarations.
76*/
77struct _RandomInfo
78{
79 SignatureInfo
80 *signature_info;
81
82 StringInfo
83 *nonce,
84 *reservoir;
85
86 size_t
87 i;
88
cristy2c54ad32011-02-25 02:45:27 +000089 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000090 seed[4];
91
92 double
93 normalize;
94
95 unsigned short
96 protocol_major,
97 protocol_minor;
98
99 SemaphoreInfo
100 *semaphore;
101
cristybb503372010-05-27 20:51:26 +0000102 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000103 timestamp;
104
cristybb503372010-05-27 20:51:26 +0000105 size_t
cristy3ed852e2009-09-05 21:47:34 +0000106 signature;
107};
108
109/*
110 External declarations.
111*/
cristya65f35b2010-04-20 01:10:41 +0000112#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
cristy3ed852e2009-09-05 21:47:34 +0000113#include <crt_externs.h>
114#define environ (*_NSGetEnviron())
115#endif
116
117extern char
118 **environ;
119
120/*
121 Global declarations.
122*/
123static SemaphoreInfo
124 *random_semaphore = (SemaphoreInfo *) NULL;
125
cristy4bc38542011-02-25 12:59:29 +0000126static unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000127 random_seed = ~0UL;
128
129static MagickBooleanType
130 gather_true_random = MagickFalse;
131
132/*
133 Forward declarations.
134*/
135static StringInfo
136 *GenerateEntropicChaos(RandomInfo *);
137
138/*
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140% %
141% %
142% %
143% A c q u i r e R a n d o m I n f o %
144% %
145% %
146% %
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148%
149% AcquireRandomInfo() allocates the RandomInfo structure.
150%
151% The format of the AcquireRandomInfo method is:
152%
153% RandomInfo *AcquireRandomInfo(void)
154%
155*/
156
157static inline size_t MagickMin(const size_t x,const size_t y)
158{
159 if (x < y)
160 return(x);
161 return(y);
162}
163
164MagickExport RandomInfo *AcquireRandomInfo(void)
165{
166 const StringInfo
167 *digest;
168
169 RandomInfo
170 *random_info;
171
172 StringInfo
173 *entropy,
174 *key,
175 *nonce;
176
cristy73bd4a52010-10-05 11:24:23 +0000177 random_info=(RandomInfo *) AcquireMagickMemory(sizeof(*random_info));
cristy3ed852e2009-09-05 21:47:34 +0000178 if (random_info == (RandomInfo *) NULL)
179 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
180 (void) ResetMagickMemory(random_info,0,sizeof(*random_info));
181 random_info->signature_info=AcquireSignatureInfo();
182 random_info->nonce=AcquireStringInfo(2*GetSignatureDigestsize(
183 random_info->signature_info));
184 ResetStringInfo(random_info->nonce);
185 random_info->reservoir=AcquireStringInfo(GetSignatureDigestsize(
186 random_info->signature_info));
187 ResetStringInfo(random_info->reservoir);
188 random_info->normalize=1.0/(~0UL);
189 random_info->semaphore=AllocateSemaphoreInfo();
190 random_info->protocol_major=RandomProtocolMajorVersion;
191 random_info->protocol_minor=RandomProtocolMinorVersion;
cristybb503372010-05-27 20:51:26 +0000192 random_info->timestamp=(ssize_t) time(0);
cristy3ed852e2009-09-05 21:47:34 +0000193 random_info->signature=MagickSignature;
194 /*
195 Seed random nonce.
196 */
197 nonce=GenerateEntropicChaos(random_info);
198 if (nonce == (StringInfo *) NULL)
199 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
200 InitializeSignature(random_info->signature_info);
201 UpdateSignature(random_info->signature_info,nonce);
202 FinalizeSignature(random_info->signature_info);
203 SetStringInfoLength(nonce,(GetSignatureDigestsize(
204 random_info->signature_info)+1)/2);
205 SetStringInfo(nonce,GetSignatureDigest(random_info->signature_info));
206 SetStringInfo(random_info->nonce,nonce);
207 nonce=DestroyStringInfo(nonce);
208 /*
209 Seed random reservoir with entropic data.
210 */
211 entropy=GenerateEntropicChaos(random_info);
212 if (entropy == (StringInfo *) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
214 UpdateSignature(random_info->signature_info,entropy);
215 FinalizeSignature(random_info->signature_info);
216 SetStringInfo(random_info->reservoir,GetSignatureDigest(
217 random_info->signature_info));
218 entropy=DestroyStringInfo(entropy);
219 /*
220 Seed pseudo random number generator.
221 */
222 if (random_seed == ~0UL)
223 {
224 key=GetRandomKey(random_info,sizeof(random_seed));
225 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(key),
226 GetStringInfoLength(key));
227 key=DestroyStringInfo(key);
228 }
229 else
230 {
231 SignatureInfo
232 *signature_info;
233
234 signature_info=AcquireSignatureInfo();
235 key=AcquireStringInfo(sizeof(random_seed));
236 SetStringInfoDatum(key,(unsigned char *) &random_seed);
237 UpdateSignature(signature_info,key);
238 key=DestroyStringInfo(key);
239 FinalizeSignature(signature_info);
240 digest=GetSignatureDigest(signature_info);
241 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(digest),
242 MagickMin(GetSignatureDigestsize(signature_info),
243 sizeof(*random_info->seed)));
244 signature_info=DestroySignatureInfo(signature_info);
245 }
246 random_info->seed[1]=0x50a7f451UL;
247 random_info->seed[2]=0x5365417eUL;
248 random_info->seed[3]=0xc3a4171aUL;
249 return(random_info);
250}
251
252/*
253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254% %
255% %
256% %
257+ D e s t r o y R a n d o m I n f o %
258% %
259% %
260% %
261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
262%
263% DestroyRandomInfo() deallocates memory associated with the random
264% reservoir.
265%
266% The format of the DestroyRandomInfo method is:
267%
268% RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
269%
270% A description of each parameter follows:
271%
272% o random_info: the random info.
273%
274*/
275MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
276{
277 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
278 assert(random_info != (RandomInfo *) NULL);
279 assert(random_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000280 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000281 if (random_info->reservoir != (StringInfo *) NULL)
282 random_info->reservoir=DestroyStringInfo(random_info->reservoir);
283 if (random_info->nonce != (StringInfo *) NULL)
284 random_info->nonce=DestroyStringInfo(random_info->nonce);
285 if (random_info->signature_info != (SignatureInfo *) NULL)
286 random_info->signature_info=DestroySignatureInfo(
287 random_info->signature_info);
288 (void) ResetMagickMemory(random_info->seed,0,sizeof(*random_info->seed));
289 random_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000290 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000291 DestroySemaphoreInfo(&random_info->semaphore);
cristyb41ee102010-10-04 16:46:15 +0000292 random_info=(RandomInfo *) RelinquishMagickMemory(random_info);
cristy3ed852e2009-09-05 21:47:34 +0000293 return(random_info);
294}
295
296/*
297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298% %
299% %
300% %
cristy3ed852e2009-09-05 21:47:34 +0000301+ G e n e r a t e E n t r o p i c C h a o s %
302% %
303% %
304% %
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306%
307% GenerateEntropicChaos() generate entropic chaos used to initialize the
308% random reservoir.
309%
310% The format of the GenerateEntropicChaos method is:
311%
312% StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
313%
314% A description of each parameter follows:
315%
316% o random_info: the random info.
317%
318*/
319
cristy0157aea2010-04-24 21:12:18 +0000320#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000321static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
322{
323 register unsigned char
324 *q;
325
326 ssize_t
327 offset,
328 count;
329
330 offset=0;
331 for (q=source; length != 0; length-=count)
332 {
333 count=(ssize_t) read(file,q,length);
334 if (count <= 0)
335 {
336 count=0;
337 if (errno == EINTR)
338 continue;
339 return(-1);
340 }
341 q+=count;
342 offset+=count;
343 }
344 return(offset);
345}
cristy39615682009-09-22 18:10:17 +0000346#endif
cristy3ed852e2009-09-05 21:47:34 +0000347
348static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
349{
350#define MaxEntropyExtent 64
351
cristy3ed852e2009-09-05 21:47:34 +0000352 MagickThreadType
353 tid;
354
355 StringInfo
356 *chaos,
357 *entropy;
358
cristybb503372010-05-27 20:51:26 +0000359 size_t
cristy3ed852e2009-09-05 21:47:34 +0000360 nanoseconds,
361 seconds;
362
cristy9d314ff2011-03-09 01:30:28 +0000363 ssize_t
364 pid;
365
cristy3ed852e2009-09-05 21:47:34 +0000366 /*
367 Initialize random reservoir.
368 */
369 entropy=AcquireStringInfo(0);
cristyf84a1932010-01-03 18:00:18 +0000370 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000371 chaos=AcquireStringInfo(sizeof(unsigned char *));
372 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
373 ConcatenateStringInfo(entropy,chaos);
374 SetStringInfoDatum(chaos,(unsigned char *) entropy);
375 ConcatenateStringInfo(entropy,chaos);
cristybb503372010-05-27 20:51:26 +0000376 pid=(ssize_t) getpid();
cristy3ed852e2009-09-05 21:47:34 +0000377 SetStringInfoLength(chaos,sizeof(pid));
378 SetStringInfoDatum(chaos,(unsigned char *) &pid);
379 ConcatenateStringInfo(entropy,chaos);
380 tid=GetMagickThreadId();
381 SetStringInfoLength(chaos,sizeof(tid));
382 SetStringInfoDatum(chaos,(unsigned char *) &tid);
383 ConcatenateStringInfo(entropy,chaos);
384#if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
385 {
386 struct rusage
387 usage;
388
389 if (getrusage(RUSAGE_SELF,&usage) == 0)
390 {
391 SetStringInfoLength(chaos,sizeof(usage));
392 SetStringInfoDatum(chaos,(unsigned char *) &usage);
393 }
394 }
395#endif
396 seconds=time((time_t *) 0);
397 nanoseconds=0;
398#if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
399 {
400 struct timeval
401 timer;
402
cristy6d71f8d2010-02-28 00:46:02 +0000403 if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000404 {
405 seconds=timer.tv_sec;
406 nanoseconds=1000UL*timer.tv_usec;
407 }
408 }
409#endif
cristyc16a63e2009-09-28 13:20:14 +0000410#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
cristy3ed852e2009-09-05 21:47:34 +0000411 {
412 struct timespec
413 timer;
414
cristyc16a63e2009-09-28 13:20:14 +0000415 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000416 {
417 seconds=timer.tv_sec;
418 nanoseconds=timer.tv_nsec;
419 }
420 }
421#endif
422 SetStringInfoLength(chaos,sizeof(seconds));
423 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
424 ConcatenateStringInfo(entropy,chaos);
425 SetStringInfoLength(chaos,sizeof(nanoseconds));
426 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
427 ConcatenateStringInfo(entropy,chaos);
428 nanoseconds=0;
429#if defined(MAGICKCORE_HAVE_CLOCK)
430 nanoseconds=clock();
431#endif
432#if defined(MAGICKCORE_HAVE_TIMES)
433 {
434 struct tms
435 timer;
436
437 (void) times(&timer);
438 nanoseconds=timer.tms_utime+timer.tms_stime;
439 }
440#endif
441 SetStringInfoLength(chaos,sizeof(nanoseconds));
442 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
443 ConcatenateStringInfo(entropy,chaos);
444#if defined(MAGICKCORE_HAVE_MKSTEMP)
445 {
446 char
447 *filename;
448
449 int
450 file;
451
452 filename=ConstantString("magickXXXXXX");
453 file=mkstemp(filename);
454#if defined(__OS2__)
455 setmode(file,O_BINARY);
456#endif
457 if (file != -1)
458 (void) close(file);
cristy18c6c272011-09-23 14:40:37 +0000459 (void) remove_utf8(filename);
cristy3ed852e2009-09-05 21:47:34 +0000460 SetStringInfoLength(chaos,strlen(filename));
461 SetStringInfoDatum(chaos,(unsigned char *) filename);
462 ConcatenateStringInfo(entropy,chaos);
463 filename=DestroyString(filename);
464 }
465#endif
cristy0157aea2010-04-24 21:12:18 +0000466#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000467 {
468 double
469 seconds;
470
471 LARGE_INTEGER
472 nanoseconds;
473
474 MagickBooleanType
475 status;
476
477 /*
478 Not crytographically strong but better than nothing.
479 */
480 seconds=NTElapsedTime()+NTUserTime();
481 SetStringInfoLength(chaos,sizeof(seconds));
482 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
483 ConcatenateStringInfo(entropy,chaos);
484 if (QueryPerformanceCounter(&nanoseconds) != 0)
485 {
486 SetStringInfoLength(chaos,sizeof(nanoseconds));
487 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
488 ConcatenateStringInfo(entropy,chaos);
489 }
490 /*
491 Our best hope for true entropy.
492 */
493 SetStringInfoLength(chaos,MaxEntropyExtent);
494 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
495 ConcatenateStringInfo(entropy,chaos);
496 }
497#else
498 {
499 char
500 *filename;
501
502 int
503 file;
504
505 ssize_t
506 count;
507
508 StringInfo
509 *device;
510
511 /*
512 Not crytographically strong but better than nothing.
513 */
514 if (environ != (char **) NULL)
515 {
cristybb503372010-05-27 20:51:26 +0000516 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000517 i;
518
519 /*
520 Squeeze some entropy from the sometimes unpredicatble environment.
521 */
522 for (i=0; environ[i] != (char *) NULL; i++)
523 {
524 SetStringInfoLength(chaos,strlen(environ[i]));
525 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
526 ConcatenateStringInfo(entropy,chaos);
527 }
528 }
529 filename=AcquireString("/dev/urandom");
530 device=StringToStringInfo(filename);
531 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000532 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000533 filename=DestroyString(filename);
534 if (file != -1)
535 {
536 SetStringInfoLength(chaos,MaxEntropyExtent);
537 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
538 (void) close(file);
539 SetStringInfoLength(chaos,(size_t) count);
540 ConcatenateStringInfo(entropy,chaos);
541 }
542 if (gather_true_random != MagickFalse)
543 {
544 /*
545 Our best hope for true entropy.
546 */
547 filename=AcquireString("/dev/random");
548 device=StringToStringInfo(filename);
549 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000550 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000551 filename=DestroyString(filename);
552 if (file == -1)
553 {
554 filename=AcquireString("/dev/srandom");
555 device=StringToStringInfo(filename);
556 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000557 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000558 }
559 if (file != -1)
560 {
561 SetStringInfoLength(chaos,MaxEntropyExtent);
562 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
563 (void) close(file);
564 SetStringInfoLength(chaos,(size_t) count);
565 ConcatenateStringInfo(entropy,chaos);
566 }
567 }
568 }
569#endif
570 chaos=DestroyStringInfo(chaos);
cristyf84a1932010-01-03 18:00:18 +0000571 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000572 return(entropy);
573}
574
575/*
576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577% %
578% %
579% %
580% G e t P s e u d o R a n d o m V a l u e %
581% %
582% %
583% %
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585%
586% GetPseudoRandomValue() return a non-negative double-precision floating-point
587% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
588% 128th-1 period.
589%
590% The format of the GetPseudoRandomValue method is:
591%
592% double GetPseudoRandomValue(RandomInfo *randon_info)
593%
594% A description of each parameter follows:
595%
596% o random_info: the random info.
597%
598*/
599MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
600{
cristyebbcfea2011-02-25 02:43:54 +0000601 register unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000602 *seed;
603
cristyebbcfea2011-02-25 02:43:54 +0000604 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000605 alpha;
606
607 seed=random_info->seed;
608 do
609 {
cristyebbcfea2011-02-25 02:43:54 +0000610 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
cristy3ed852e2009-09-05 21:47:34 +0000611 seed[1]=seed[2];
612 seed[2]=seed[3];
613 seed[3]=seed[0];
614 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
615 } while (seed[0] == ~0UL);
616 return(random_info->normalize*seed[0]);
617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
624% G e t R a n d o m K e y %
625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629%
630% GetRandomKey() gets a random key from the reservoir.
631%
632% The format of the GetRandomKey method is:
633%
634% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
635%
636% A description of each parameter follows:
637%
638% o random_info: the random info.
639%
640% o length: the key length.
641%
642*/
643MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
644 const size_t length)
645{
646 StringInfo
647 *key;
648
649 assert(random_info != (RandomInfo *) NULL);
650 key=AcquireStringInfo(length);
651 SetRandomKey(random_info,length,GetStringInfoDatum(key));
652 return(key);
653}
654
655/*
656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657% %
658% %
659% %
660% G e t R a n d o m V a l u e %
661% %
662% %
663% %
664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665%
666% GetRandomValue() return a non-negative double-precision floating-point
667% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
668% 128th-1 period (not cryptographically strong).
669%
670% The format of the GetRandomValue method is:
671%
672% double GetRandomValue(void)
673%
674*/
675MagickExport double GetRandomValue(RandomInfo *random_info)
676{
cristy29405832011-02-26 22:07:13 +0000677 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000678 key,
679 range;
680
681 range=(~0UL);
682 do
683 {
684 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
685 } while (key == range);
686 return((double) key/range);
687}
688
689/*
690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691% %
692% %
693% %
cristy18b17442009-10-25 18:36:48 +0000694+ R a n d o m C o m p o n e n t G e n e s i s %
cristy41c3c772009-10-19 02:17:37 +0000695% %
696% %
697% %
698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699%
cristyf34a1452009-10-24 22:29:27 +0000700% RandomComponentGenesis() instantiates the random component.
cristy41c3c772009-10-19 02:17:37 +0000701%
cristyf34a1452009-10-24 22:29:27 +0000702% The format of the RandomComponentGenesis method is:
cristy41c3c772009-10-19 02:17:37 +0000703%
cristyf34a1452009-10-24 22:29:27 +0000704% MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000705%
706*/
cristy5ff4eaf2011-09-03 01:38:02 +0000707MagickPrivate MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000708{
cristy165b6092009-10-26 13:52:10 +0000709 AcquireSemaphoreInfo(&random_semaphore);
cristy41c3c772009-10-19 02:17:37 +0000710 return(MagickTrue);
711}
712
713/*
714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715% %
716% %
717% %
cristyf34a1452009-10-24 22:29:27 +0000718+ R a n d o m C o m p o n e n t T e r m i n u s %
719% %
720% %
721% %
722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723%
724% RandomComponentTerminus() destroys the random component.
725%
726% The format of the RandomComponentTerminus method is:
727%
728% RandomComponentTerminus(void)
729%
730*/
cristy5ff4eaf2011-09-03 01:38:02 +0000731MagickPrivate void RandomComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000732{
cristy18b17442009-10-25 18:36:48 +0000733 if (random_semaphore == (SemaphoreInfo *) NULL)
734 AcquireSemaphoreInfo(&random_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000735 DestroySemaphoreInfo(&random_semaphore);
736}
737
738/*
739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
740% %
741% %
742% %
cristy3ed852e2009-09-05 21:47:34 +0000743% S e e d P s e u d o R a n d o m G e n e r a t o r %
744% %
745% %
746% %
747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748%
749% SeedPseudoRandomGenerator() initializes the pseudo-random number generator
750% with a random seed.
751%
752% The format of the SeedPseudoRandomGenerator method is:
753%
cristyebbcfea2011-02-25 02:43:54 +0000754% void SeedPseudoRandomGenerator(const unsigned long seed)
cristy3ed852e2009-09-05 21:47:34 +0000755%
756% A description of each parameter follows:
757%
758% o seed: the seed.
759%
760*/
cristyec554072011-02-25 13:44:25 +0000761MagickExport void SeedPseudoRandomGenerator(const unsigned long seed)
cristy3ed852e2009-09-05 21:47:34 +0000762{
763 random_seed=seed;
764}
765
766/*
767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768% %
769% %
770% %
771% S e t R a n d o m K e y %
772% %
773% %
774% %
775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776%
777% SetRandomKey() sets a random key from the reservoir.
778%
779% The format of the SetRandomKey method is:
780%
781% void SetRandomKey(RandomInfo *random_info,const size_t length,
782% unsigned char *key)
783%
784% A description of each parameter follows:
785%
786% o random_info: the random info.
787%
788% o length: the key length.
789%
790% o key: the key.
791%
792*/
793
794static inline void IncrementRandomNonce(StringInfo *nonce)
795{
cristybb503372010-05-27 20:51:26 +0000796 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000797 i;
798
799 unsigned char
800 *datum;
801
802 datum=GetStringInfoDatum(nonce);
cristybb503372010-05-27 20:51:26 +0000803 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
cristy3ed852e2009-09-05 21:47:34 +0000804 {
805 datum[i]++;
806 if (datum[i] != 0)
807 return;
808 }
809 ThrowFatalException(RandomFatalError,"SequenceWrapError");
810}
811
812MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
813 unsigned char *key)
814{
815 register size_t
816 i;
817
818 register unsigned char
819 *p;
820
821 SignatureInfo
822 *signature_info;
823
824 unsigned char
825 *datum;
826
827 assert(random_info != (RandomInfo *) NULL);
828 if (length == 0)
829 return;
cristyf84a1932010-01-03 18:00:18 +0000830 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000831 signature_info=random_info->signature_info;
832 datum=GetStringInfoDatum(random_info->reservoir);
833 i=length;
834 for (p=key; (i != 0) && (random_info->i != 0); i--)
835 {
836 *p++=datum[random_info->i];
837 random_info->i++;
838 if (random_info->i == GetSignatureDigestsize(signature_info))
839 random_info->i=0;
840 }
841 while (i >= GetSignatureDigestsize(signature_info))
842 {
843 InitializeSignature(signature_info);
844 UpdateSignature(signature_info,random_info->nonce);
845 FinalizeSignature(signature_info);
846 IncrementRandomNonce(random_info->nonce);
847 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
848 signature_info)),GetSignatureDigestsize(signature_info));
849 p+=GetSignatureDigestsize(signature_info);
850 i-=GetSignatureDigestsize(signature_info);
851 }
852 if (i != 0)
853 {
854 InitializeSignature(signature_info);
855 UpdateSignature(signature_info,random_info->nonce);
856 FinalizeSignature(signature_info);
857 IncrementRandomNonce(random_info->nonce);
858 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
859 random_info->i=i;
860 datum=GetStringInfoDatum(random_info->reservoir);
861 while (i-- != 0)
862 p[i]=datum[i];
863 }
cristyf84a1932010-01-03 18:00:18 +0000864 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000865}
866
867/*
868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
869% %
870% %
871% %
872% S e t R a n d o m T r u e R a n d o m %
873% %
874% %
875% %
876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
877%
878% SetRandomTrueRandom() declares your intentions to use true random numbers.
879% True random numbers are encouraged but may not always be practical because
880% your application may block while entropy is gathered from your environment.
881%
882% The format of the SetRandomTrueRandom method is:
883%
884% void SetRandomTrueRandom(const MagickBooleanType true_random)
885%
886% A description of each parameter follows:
887%
888% o true_random: declare your intentions to use true-random number.
889%
890*/
891MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
892{
893 gather_true_random=true_random;
894}