blob: fe6a690de3462613b696aff74ef4f92fc9a87438 [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% %
cristy1454be72011-12-19 01:52:48 +000019% Copyright 1999-2012 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);
cristy728891d2011-10-07 18:55:11 +0000188 random_info->normalize=1.0/(~0UL);
cristy3ed852e2009-09-05 21:47:34 +0000189 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));
cristyd0933fd2012-02-19 22:05:42 +0000495 (void) status;
cristy3ed852e2009-09-05 21:47:34 +0000496 ConcatenateStringInfo(entropy,chaos);
497 }
498#else
499 {
500 char
501 *filename;
502
503 int
504 file;
505
506 ssize_t
507 count;
508
509 StringInfo
510 *device;
511
512 /*
513 Not crytographically strong but better than nothing.
514 */
515 if (environ != (char **) NULL)
516 {
cristybb503372010-05-27 20:51:26 +0000517 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000518 i;
519
520 /*
521 Squeeze some entropy from the sometimes unpredicatble environment.
522 */
523 for (i=0; environ[i] != (char *) NULL; i++)
524 {
525 SetStringInfoLength(chaos,strlen(environ[i]));
526 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
527 ConcatenateStringInfo(entropy,chaos);
528 }
529 }
530 filename=AcquireString("/dev/urandom");
531 device=StringToStringInfo(filename);
532 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000533 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000534 filename=DestroyString(filename);
535 if (file != -1)
536 {
537 SetStringInfoLength(chaos,MaxEntropyExtent);
538 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
539 (void) close(file);
540 SetStringInfoLength(chaos,(size_t) count);
541 ConcatenateStringInfo(entropy,chaos);
542 }
543 if (gather_true_random != MagickFalse)
544 {
545 /*
546 Our best hope for true entropy.
547 */
548 filename=AcquireString("/dev/random");
549 device=StringToStringInfo(filename);
550 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000551 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000552 filename=DestroyString(filename);
553 if (file == -1)
554 {
555 filename=AcquireString("/dev/srandom");
556 device=StringToStringInfo(filename);
557 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000558 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000559 }
560 if (file != -1)
561 {
562 SetStringInfoLength(chaos,MaxEntropyExtent);
563 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
564 (void) close(file);
565 SetStringInfoLength(chaos,(size_t) count);
566 ConcatenateStringInfo(entropy,chaos);
567 }
568 }
569 }
570#endif
571 chaos=DestroyStringInfo(chaos);
cristyf84a1932010-01-03 18:00:18 +0000572 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000573 return(entropy);
574}
575
576/*
577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578% %
579% %
580% %
581% G e t P s e u d o R a n d o m V a l u e %
582% %
583% %
584% %
585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586%
587% GetPseudoRandomValue() return a non-negative double-precision floating-point
588% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
589% 128th-1 period.
590%
591% The format of the GetPseudoRandomValue method is:
592%
593% double GetPseudoRandomValue(RandomInfo *randon_info)
594%
595% A description of each parameter follows:
596%
597% o random_info: the random info.
598%
599*/
600MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
601{
cristyebbcfea2011-02-25 02:43:54 +0000602 register unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000603 *seed;
604
cristyebbcfea2011-02-25 02:43:54 +0000605 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000606 alpha;
607
608 seed=random_info->seed;
609 do
610 {
cristyebbcfea2011-02-25 02:43:54 +0000611 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
cristy3ed852e2009-09-05 21:47:34 +0000612 seed[1]=seed[2];
613 seed[2]=seed[3];
614 seed[3]=seed[0];
615 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
616 } while (seed[0] == ~0UL);
617 return(random_info->normalize*seed[0]);
618}
619
620/*
621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622% %
623% %
624% %
625% G e t R a n d o m K e y %
626% %
627% %
628% %
629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630%
631% GetRandomKey() gets a random key from the reservoir.
632%
633% The format of the GetRandomKey method is:
634%
635% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
636%
637% A description of each parameter follows:
638%
639% o random_info: the random info.
640%
641% o length: the key length.
642%
643*/
644MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
645 const size_t length)
646{
647 StringInfo
648 *key;
649
650 assert(random_info != (RandomInfo *) NULL);
651 key=AcquireStringInfo(length);
652 SetRandomKey(random_info,length,GetStringInfoDatum(key));
653 return(key);
654}
655
656/*
657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658% %
659% %
660% %
661% G e t R a n d o m V a l u e %
662% %
663% %
664% %
665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666%
667% GetRandomValue() return a non-negative double-precision floating-point
668% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
669% 128th-1 period (not cryptographically strong).
670%
671% The format of the GetRandomValue method is:
672%
673% double GetRandomValue(void)
674%
675*/
676MagickExport double GetRandomValue(RandomInfo *random_info)
677{
cristy29405832011-02-26 22:07:13 +0000678 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000679 key,
680 range;
681
682 range=(~0UL);
683 do
684 {
685 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
686 } while (key == range);
687 return((double) key/range);
688}
689
690/*
691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692% %
693% %
694% %
cristy18b17442009-10-25 18:36:48 +0000695+ 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 +0000696% %
697% %
698% %
699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700%
cristyf34a1452009-10-24 22:29:27 +0000701% RandomComponentGenesis() instantiates the random component.
cristy41c3c772009-10-19 02:17:37 +0000702%
cristyf34a1452009-10-24 22:29:27 +0000703% The format of the RandomComponentGenesis method is:
cristy41c3c772009-10-19 02:17:37 +0000704%
cristyf34a1452009-10-24 22:29:27 +0000705% MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000706%
707*/
cristy5ff4eaf2011-09-03 01:38:02 +0000708MagickPrivate MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000709{
cristy165b6092009-10-26 13:52:10 +0000710 AcquireSemaphoreInfo(&random_semaphore);
cristy41c3c772009-10-19 02:17:37 +0000711 return(MagickTrue);
712}
713
714/*
715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716% %
717% %
718% %
cristyf34a1452009-10-24 22:29:27 +0000719+ R a n d o m C o m p o n e n t T e r m i n u s %
720% %
721% %
722% %
723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724%
725% RandomComponentTerminus() destroys the random component.
726%
727% The format of the RandomComponentTerminus method is:
728%
729% RandomComponentTerminus(void)
730%
731*/
cristy5ff4eaf2011-09-03 01:38:02 +0000732MagickPrivate void RandomComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000733{
cristy18b17442009-10-25 18:36:48 +0000734 if (random_semaphore == (SemaphoreInfo *) NULL)
735 AcquireSemaphoreInfo(&random_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000736 DestroySemaphoreInfo(&random_semaphore);
737}
738
739/*
740%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
741% %
742% %
743% %
cristy3ed852e2009-09-05 21:47:34 +0000744% 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 %
745% %
746% %
747% %
748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749%
750% SeedPseudoRandomGenerator() initializes the pseudo-random number generator
751% with a random seed.
752%
753% The format of the SeedPseudoRandomGenerator method is:
754%
cristyebbcfea2011-02-25 02:43:54 +0000755% void SeedPseudoRandomGenerator(const unsigned long seed)
cristy3ed852e2009-09-05 21:47:34 +0000756%
757% A description of each parameter follows:
758%
759% o seed: the seed.
760%
761*/
cristyec554072011-02-25 13:44:25 +0000762MagickExport void SeedPseudoRandomGenerator(const unsigned long seed)
cristy3ed852e2009-09-05 21:47:34 +0000763{
764 random_seed=seed;
765}
766
767/*
768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769% %
770% %
771% %
772% S e t R a n d o m K e y %
773% %
774% %
775% %
776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
777%
778% SetRandomKey() sets a random key from the reservoir.
779%
780% The format of the SetRandomKey method is:
781%
782% void SetRandomKey(RandomInfo *random_info,const size_t length,
783% unsigned char *key)
784%
785% A description of each parameter follows:
786%
787% o random_info: the random info.
788%
789% o length: the key length.
790%
791% o key: the key.
792%
793*/
794
795static inline void IncrementRandomNonce(StringInfo *nonce)
796{
cristybb503372010-05-27 20:51:26 +0000797 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000798 i;
799
800 unsigned char
801 *datum;
802
803 datum=GetStringInfoDatum(nonce);
cristybb503372010-05-27 20:51:26 +0000804 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
cristy3ed852e2009-09-05 21:47:34 +0000805 {
806 datum[i]++;
807 if (datum[i] != 0)
808 return;
809 }
810 ThrowFatalException(RandomFatalError,"SequenceWrapError");
811}
812
813MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
814 unsigned char *key)
815{
816 register size_t
817 i;
818
819 register unsigned char
820 *p;
821
822 SignatureInfo
823 *signature_info;
824
825 unsigned char
826 *datum;
827
828 assert(random_info != (RandomInfo *) NULL);
829 if (length == 0)
830 return;
cristyf84a1932010-01-03 18:00:18 +0000831 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000832 signature_info=random_info->signature_info;
833 datum=GetStringInfoDatum(random_info->reservoir);
834 i=length;
835 for (p=key; (i != 0) && (random_info->i != 0); i--)
836 {
837 *p++=datum[random_info->i];
838 random_info->i++;
839 if (random_info->i == GetSignatureDigestsize(signature_info))
840 random_info->i=0;
841 }
842 while (i >= GetSignatureDigestsize(signature_info))
843 {
844 InitializeSignature(signature_info);
845 UpdateSignature(signature_info,random_info->nonce);
846 FinalizeSignature(signature_info);
847 IncrementRandomNonce(random_info->nonce);
848 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
849 signature_info)),GetSignatureDigestsize(signature_info));
850 p+=GetSignatureDigestsize(signature_info);
851 i-=GetSignatureDigestsize(signature_info);
852 }
853 if (i != 0)
854 {
855 InitializeSignature(signature_info);
856 UpdateSignature(signature_info,random_info->nonce);
857 FinalizeSignature(signature_info);
858 IncrementRandomNonce(random_info->nonce);
859 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
860 random_info->i=i;
861 datum=GetStringInfoDatum(random_info->reservoir);
862 while (i-- != 0)
863 p[i]=datum[i];
864 }
cristyf84a1932010-01-03 18:00:18 +0000865 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000866}
867
868/*
869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870% %
871% %
872% %
873% S e t R a n d o m T r u e R a n d o m %
874% %
875% %
876% %
877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
878%
879% SetRandomTrueRandom() declares your intentions to use true random numbers.
880% True random numbers are encouraged but may not always be practical because
881% your application may block while entropy is gathered from your environment.
882%
883% The format of the SetRandomTrueRandom method is:
884%
885% void SetRandomTrueRandom(const MagickBooleanType true_random)
886%
887% A description of each parameter follows:
888%
889% o true_random: declare your intentions to use true-random number.
890%
891*/
892MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
893{
894 gather_true_random=true_random;
895}