blob: 62127dc7a8cc60c347d41e7d40ab472b653ecb37 [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
50#include "magick/studio.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/memory_.h"
54#include "magick/semaphore.h"
55#include "magick/random_.h"
56#include "magick/resource_.h"
57#include "magick/signature-private.h"
58#include "magick/string_.h"
59#include "magick/thread_.h"
60#include "magick/thread-private.h"
61#include "magick/utility.h"
62/*
63 Define declarations.
64*/
65#define PseudoRandomHash SHA256Hash
66#define RandomEntropyLevel 9
67#define RandomFilename "reservoir.xdm"
68#define RandomFiletype "random"
69#define RandomProtocolMajorVersion 1
70#define RandomProtocolMinorVersion 0
71
72/*
73 Typedef declarations.
74*/
75struct _RandomInfo
76{
77 SignatureInfo
78 *signature_info;
79
80 StringInfo
81 *nonce,
82 *reservoir;
83
84 size_t
85 i;
86
cristybb503372010-05-27 20:51:26 +000087 size_t
cristy3ed852e2009-09-05 21:47:34 +000088 seed[4];
89
90 double
91 normalize;
92
93 unsigned short
94 protocol_major,
95 protocol_minor;
96
97 SemaphoreInfo
98 *semaphore;
99
cristybb503372010-05-27 20:51:26 +0000100 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000101 timestamp;
102
cristybb503372010-05-27 20:51:26 +0000103 size_t
cristy3ed852e2009-09-05 21:47:34 +0000104 signature;
105};
106
107/*
108 External declarations.
109*/
cristya65f35b2010-04-20 01:10:41 +0000110#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
cristy3ed852e2009-09-05 21:47:34 +0000111#include <crt_externs.h>
112#define environ (*_NSGetEnviron())
113#endif
114
115extern char
116 **environ;
117
118/*
119 Global declarations.
120*/
121static SemaphoreInfo
122 *random_semaphore = (SemaphoreInfo *) NULL;
123
cristybb503372010-05-27 20:51:26 +0000124static size_t
cristy3ed852e2009-09-05 21:47:34 +0000125 random_seed = ~0UL;
126
127static MagickBooleanType
128 gather_true_random = MagickFalse;
129
130/*
131 Forward declarations.
132*/
133static StringInfo
134 *GenerateEntropicChaos(RandomInfo *);
135
136/*
137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138% %
139% %
140% %
141% A c q u i r e R a n d o m I n f o %
142% %
143% %
144% %
145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146%
147% AcquireRandomInfo() allocates the RandomInfo structure.
148%
149% The format of the AcquireRandomInfo method is:
150%
151% RandomInfo *AcquireRandomInfo(void)
152%
153*/
154
155static inline size_t MagickMin(const size_t x,const size_t y)
156{
157 if (x < y)
158 return(x);
159 return(y);
160}
161
162MagickExport RandomInfo *AcquireRandomInfo(void)
163{
164 const StringInfo
165 *digest;
166
167 RandomInfo
168 *random_info;
169
170 StringInfo
171 *entropy,
172 *key,
173 *nonce;
174
cristy73bd4a52010-10-05 11:24:23 +0000175 random_info=(RandomInfo *) AcquireMagickMemory(sizeof(*random_info));
cristy3ed852e2009-09-05 21:47:34 +0000176 if (random_info == (RandomInfo *) NULL)
177 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
178 (void) ResetMagickMemory(random_info,0,sizeof(*random_info));
179 random_info->signature_info=AcquireSignatureInfo();
180 random_info->nonce=AcquireStringInfo(2*GetSignatureDigestsize(
181 random_info->signature_info));
182 ResetStringInfo(random_info->nonce);
183 random_info->reservoir=AcquireStringInfo(GetSignatureDigestsize(
184 random_info->signature_info));
185 ResetStringInfo(random_info->reservoir);
186 random_info->normalize=1.0/(~0UL);
187 random_info->semaphore=AllocateSemaphoreInfo();
188 random_info->protocol_major=RandomProtocolMajorVersion;
189 random_info->protocol_minor=RandomProtocolMinorVersion;
cristybb503372010-05-27 20:51:26 +0000190 random_info->timestamp=(ssize_t) time(0);
cristy3ed852e2009-09-05 21:47:34 +0000191 random_info->signature=MagickSignature;
192 /*
193 Seed random nonce.
194 */
195 nonce=GenerateEntropicChaos(random_info);
196 if (nonce == (StringInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 InitializeSignature(random_info->signature_info);
199 UpdateSignature(random_info->signature_info,nonce);
200 FinalizeSignature(random_info->signature_info);
201 SetStringInfoLength(nonce,(GetSignatureDigestsize(
202 random_info->signature_info)+1)/2);
203 SetStringInfo(nonce,GetSignatureDigest(random_info->signature_info));
204 SetStringInfo(random_info->nonce,nonce);
205 nonce=DestroyStringInfo(nonce);
206 /*
207 Seed random reservoir with entropic data.
208 */
209 entropy=GenerateEntropicChaos(random_info);
210 if (entropy == (StringInfo *) NULL)
211 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
212 UpdateSignature(random_info->signature_info,entropy);
213 FinalizeSignature(random_info->signature_info);
214 SetStringInfo(random_info->reservoir,GetSignatureDigest(
215 random_info->signature_info));
216 entropy=DestroyStringInfo(entropy);
217 /*
218 Seed pseudo random number generator.
219 */
220 if (random_seed == ~0UL)
221 {
222 key=GetRandomKey(random_info,sizeof(random_seed));
223 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(key),
224 GetStringInfoLength(key));
225 key=DestroyStringInfo(key);
226 }
227 else
228 {
229 SignatureInfo
230 *signature_info;
231
232 signature_info=AcquireSignatureInfo();
233 key=AcquireStringInfo(sizeof(random_seed));
234 SetStringInfoDatum(key,(unsigned char *) &random_seed);
235 UpdateSignature(signature_info,key);
236 key=DestroyStringInfo(key);
237 FinalizeSignature(signature_info);
238 digest=GetSignatureDigest(signature_info);
239 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(digest),
240 MagickMin(GetSignatureDigestsize(signature_info),
241 sizeof(*random_info->seed)));
242 signature_info=DestroySignatureInfo(signature_info);
243 }
244 random_info->seed[1]=0x50a7f451UL;
245 random_info->seed[2]=0x5365417eUL;
246 random_info->seed[3]=0xc3a4171aUL;
247 return(random_info);
248}
249
250/*
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252% %
253% %
254% %
255+ D e s t r o y R a n d o m I n f o %
256% %
257% %
258% %
259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260%
261% DestroyRandomInfo() deallocates memory associated with the random
262% reservoir.
263%
264% The format of the DestroyRandomInfo method is:
265%
266% RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
267%
268% A description of each parameter follows:
269%
270% o random_info: the random info.
271%
272*/
273MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
274{
275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
276 assert(random_info != (RandomInfo *) NULL);
277 assert(random_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000278 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000279 if (random_info->reservoir != (StringInfo *) NULL)
280 random_info->reservoir=DestroyStringInfo(random_info->reservoir);
281 if (random_info->nonce != (StringInfo *) NULL)
282 random_info->nonce=DestroyStringInfo(random_info->nonce);
283 if (random_info->signature_info != (SignatureInfo *) NULL)
284 random_info->signature_info=DestroySignatureInfo(
285 random_info->signature_info);
286 (void) ResetMagickMemory(random_info->seed,0,sizeof(*random_info->seed));
287 random_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000288 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000289 DestroySemaphoreInfo(&random_info->semaphore);
cristyb41ee102010-10-04 16:46:15 +0000290 random_info=(RandomInfo *) RelinquishMagickMemory(random_info);
cristy3ed852e2009-09-05 21:47:34 +0000291 return(random_info);
292}
293
294/*
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296% %
297% %
298% %
cristy3ed852e2009-09-05 21:47:34 +0000299+ G e n e r a t e E n t r o p i c C h a o s %
300% %
301% %
302% %
303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304%
305% GenerateEntropicChaos() generate entropic chaos used to initialize the
306% random reservoir.
307%
308% The format of the GenerateEntropicChaos method is:
309%
310% StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
311%
312% A description of each parameter follows:
313%
314% o random_info: the random info.
315%
316*/
317
cristy0157aea2010-04-24 21:12:18 +0000318#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000319static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
320{
321 register unsigned char
322 *q;
323
324 ssize_t
325 offset,
326 count;
327
328 offset=0;
329 for (q=source; length != 0; length-=count)
330 {
331 count=(ssize_t) read(file,q,length);
332 if (count <= 0)
333 {
334 count=0;
335 if (errno == EINTR)
336 continue;
337 return(-1);
338 }
339 q+=count;
340 offset+=count;
341 }
342 return(offset);
343}
cristy39615682009-09-22 18:10:17 +0000344#endif
cristy3ed852e2009-09-05 21:47:34 +0000345
346static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
347{
348#define MaxEntropyExtent 64
349
cristybb503372010-05-27 20:51:26 +0000350 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000351 pid;
352
353 MagickThreadType
354 tid;
355
356 StringInfo
357 *chaos,
358 *entropy;
359
cristybb503372010-05-27 20:51:26 +0000360 size_t
cristy3ed852e2009-09-05 21:47:34 +0000361 nanoseconds,
362 seconds;
363
364 /*
365 Initialize random reservoir.
366 */
367 entropy=AcquireStringInfo(0);
cristyf84a1932010-01-03 18:00:18 +0000368 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000369 chaos=AcquireStringInfo(sizeof(unsigned char *));
370 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
371 ConcatenateStringInfo(entropy,chaos);
372 SetStringInfoDatum(chaos,(unsigned char *) entropy);
373 ConcatenateStringInfo(entropy,chaos);
cristybb503372010-05-27 20:51:26 +0000374 pid=(ssize_t) getpid();
cristy3ed852e2009-09-05 21:47:34 +0000375 SetStringInfoLength(chaos,sizeof(pid));
376 SetStringInfoDatum(chaos,(unsigned char *) &pid);
377 ConcatenateStringInfo(entropy,chaos);
378 tid=GetMagickThreadId();
379 SetStringInfoLength(chaos,sizeof(tid));
380 SetStringInfoDatum(chaos,(unsigned char *) &tid);
381 ConcatenateStringInfo(entropy,chaos);
382#if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
383 {
384 struct rusage
385 usage;
386
387 if (getrusage(RUSAGE_SELF,&usage) == 0)
388 {
389 SetStringInfoLength(chaos,sizeof(usage));
390 SetStringInfoDatum(chaos,(unsigned char *) &usage);
391 }
392 }
393#endif
394 seconds=time((time_t *) 0);
395 nanoseconds=0;
396#if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
397 {
398 struct timeval
399 timer;
400
cristy6d71f8d2010-02-28 00:46:02 +0000401 if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000402 {
403 seconds=timer.tv_sec;
404 nanoseconds=1000UL*timer.tv_usec;
405 }
406 }
407#endif
cristyc16a63e2009-09-28 13:20:14 +0000408#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
cristy3ed852e2009-09-05 21:47:34 +0000409 {
410 struct timespec
411 timer;
412
cristyc16a63e2009-09-28 13:20:14 +0000413 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000414 {
415 seconds=timer.tv_sec;
416 nanoseconds=timer.tv_nsec;
417 }
418 }
419#endif
420 SetStringInfoLength(chaos,sizeof(seconds));
421 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
422 ConcatenateStringInfo(entropy,chaos);
423 SetStringInfoLength(chaos,sizeof(nanoseconds));
424 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
425 ConcatenateStringInfo(entropy,chaos);
426 nanoseconds=0;
427#if defined(MAGICKCORE_HAVE_CLOCK)
428 nanoseconds=clock();
429#endif
430#if defined(MAGICKCORE_HAVE_TIMES)
431 {
432 struct tms
433 timer;
434
435 (void) times(&timer);
436 nanoseconds=timer.tms_utime+timer.tms_stime;
437 }
438#endif
439 SetStringInfoLength(chaos,sizeof(nanoseconds));
440 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
441 ConcatenateStringInfo(entropy,chaos);
442#if defined(MAGICKCORE_HAVE_MKSTEMP)
443 {
444 char
445 *filename;
446
447 int
448 file;
449
450 filename=ConstantString("magickXXXXXX");
451 file=mkstemp(filename);
452#if defined(__OS2__)
453 setmode(file,O_BINARY);
454#endif
455 if (file != -1)
456 (void) close(file);
457 (void) remove(filename);
458 SetStringInfoLength(chaos,strlen(filename));
459 SetStringInfoDatum(chaos,(unsigned char *) filename);
460 ConcatenateStringInfo(entropy,chaos);
461 filename=DestroyString(filename);
462 }
463#endif
cristy0157aea2010-04-24 21:12:18 +0000464#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000465 {
466 double
467 seconds;
468
469 LARGE_INTEGER
470 nanoseconds;
471
472 MagickBooleanType
473 status;
474
475 /*
476 Not crytographically strong but better than nothing.
477 */
478 seconds=NTElapsedTime()+NTUserTime();
479 SetStringInfoLength(chaos,sizeof(seconds));
480 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
481 ConcatenateStringInfo(entropy,chaos);
482 if (QueryPerformanceCounter(&nanoseconds) != 0)
483 {
484 SetStringInfoLength(chaos,sizeof(nanoseconds));
485 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
486 ConcatenateStringInfo(entropy,chaos);
487 }
488 /*
489 Our best hope for true entropy.
490 */
491 SetStringInfoLength(chaos,MaxEntropyExtent);
492 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
493 ConcatenateStringInfo(entropy,chaos);
494 }
495#else
496 {
497 char
498 *filename;
499
500 int
501 file;
502
503 ssize_t
504 count;
505
506 StringInfo
507 *device;
508
509 /*
510 Not crytographically strong but better than nothing.
511 */
512 if (environ != (char **) NULL)
513 {
cristybb503372010-05-27 20:51:26 +0000514 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000515 i;
516
517 /*
518 Squeeze some entropy from the sometimes unpredicatble environment.
519 */
520 for (i=0; environ[i] != (char *) NULL; i++)
521 {
522 SetStringInfoLength(chaos,strlen(environ[i]));
523 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
524 ConcatenateStringInfo(entropy,chaos);
525 }
526 }
527 filename=AcquireString("/dev/urandom");
528 device=StringToStringInfo(filename);
529 device=DestroyStringInfo(device);
530 file=open(filename,O_RDONLY | O_BINARY);
531 filename=DestroyString(filename);
532 if (file != -1)
533 {
534 SetStringInfoLength(chaos,MaxEntropyExtent);
535 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
536 (void) close(file);
537 SetStringInfoLength(chaos,(size_t) count);
538 ConcatenateStringInfo(entropy,chaos);
539 }
540 if (gather_true_random != MagickFalse)
541 {
542 /*
543 Our best hope for true entropy.
544 */
545 filename=AcquireString("/dev/random");
546 device=StringToStringInfo(filename);
547 device=DestroyStringInfo(device);
548 file=open(filename,O_RDONLY | O_BINARY);
549 filename=DestroyString(filename);
550 if (file == -1)
551 {
552 filename=AcquireString("/dev/srandom");
553 device=StringToStringInfo(filename);
554 device=DestroyStringInfo(device);
555 file=open(filename,O_RDONLY | O_BINARY);
556 }
557 if (file != -1)
558 {
559 SetStringInfoLength(chaos,MaxEntropyExtent);
560 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
561 (void) close(file);
562 SetStringInfoLength(chaos,(size_t) count);
563 ConcatenateStringInfo(entropy,chaos);
564 }
565 }
566 }
567#endif
568 chaos=DestroyStringInfo(chaos);
cristyf84a1932010-01-03 18:00:18 +0000569 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000570 return(entropy);
571}
572
573/*
574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575% %
576% %
577% %
578% G e t P s e u d o R a n d o m V a l u e %
579% %
580% %
581% %
582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583%
584% GetPseudoRandomValue() return a non-negative double-precision floating-point
585% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
586% 128th-1 period.
587%
588% The format of the GetPseudoRandomValue method is:
589%
590% double GetPseudoRandomValue(RandomInfo *randon_info)
591%
592% A description of each parameter follows:
593%
594% o random_info: the random info.
595%
596*/
597MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
598{
cristyebbcfea2011-02-25 02:43:54 +0000599 register unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000600 *seed;
601
cristyebbcfea2011-02-25 02:43:54 +0000602 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000603 alpha;
604
605 seed=random_info->seed;
606 do
607 {
cristyebbcfea2011-02-25 02:43:54 +0000608 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
cristy3ed852e2009-09-05 21:47:34 +0000609 seed[1]=seed[2];
610 seed[2]=seed[3];
611 seed[3]=seed[0];
612 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
613 } while (seed[0] == ~0UL);
614 return(random_info->normalize*seed[0]);
615}
616
617/*
618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619% %
620% %
621% %
622% G e t R a n d o m K e y %
623% %
624% %
625% %
626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627%
628% GetRandomKey() gets a random key from the reservoir.
629%
630% The format of the GetRandomKey method is:
631%
632% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
633%
634% A description of each parameter follows:
635%
636% o random_info: the random info.
637%
638% o length: the key length.
639%
640*/
641MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
642 const size_t length)
643{
644 StringInfo
645 *key;
646
647 assert(random_info != (RandomInfo *) NULL);
648 key=AcquireStringInfo(length);
649 SetRandomKey(random_info,length,GetStringInfoDatum(key));
650 return(key);
651}
652
653/*
654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
655% %
656% %
657% %
658% G e t R a n d o m V a l u e %
659% %
660% %
661% %
662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663%
664% GetRandomValue() return a non-negative double-precision floating-point
665% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
666% 128th-1 period (not cryptographically strong).
667%
668% The format of the GetRandomValue method is:
669%
670% double GetRandomValue(void)
671%
672*/
673MagickExport double GetRandomValue(RandomInfo *random_info)
674{
cristybb503372010-05-27 20:51:26 +0000675 size_t
cristy3ed852e2009-09-05 21:47:34 +0000676 key,
677 range;
678
679 range=(~0UL);
680 do
681 {
682 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
683 } while (key == range);
684 return((double) key/range);
685}
686
687/*
688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689% %
690% %
691% %
cristy18b17442009-10-25 18:36:48 +0000692+ 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 +0000693% %
694% %
695% %
696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697%
cristyf34a1452009-10-24 22:29:27 +0000698% RandomComponentGenesis() instantiates the random component.
cristy41c3c772009-10-19 02:17:37 +0000699%
cristyf34a1452009-10-24 22:29:27 +0000700% The format of the RandomComponentGenesis method is:
cristy41c3c772009-10-19 02:17:37 +0000701%
cristyf34a1452009-10-24 22:29:27 +0000702% MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000703%
704*/
cristyf34a1452009-10-24 22:29:27 +0000705MagickExport MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000706{
cristy165b6092009-10-26 13:52:10 +0000707 AcquireSemaphoreInfo(&random_semaphore);
cristy41c3c772009-10-19 02:17:37 +0000708 return(MagickTrue);
709}
710
711/*
712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
713% %
714% %
715% %
cristyf34a1452009-10-24 22:29:27 +0000716+ R a n d o m C o m p o n e n t T e r m i n u s %
717% %
718% %
719% %
720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721%
722% RandomComponentTerminus() destroys the random component.
723%
724% The format of the RandomComponentTerminus method is:
725%
726% RandomComponentTerminus(void)
727%
728*/
729MagickExport void RandomComponentTerminus(void)
730{
cristy18b17442009-10-25 18:36:48 +0000731 if (random_semaphore == (SemaphoreInfo *) NULL)
732 AcquireSemaphoreInfo(&random_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000733 DestroySemaphoreInfo(&random_semaphore);
734}
735
736/*
737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738% %
739% %
740% %
cristy3ed852e2009-09-05 21:47:34 +0000741% 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 %
742% %
743% %
744% %
745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746%
747% SeedPseudoRandomGenerator() initializes the pseudo-random number generator
748% with a random seed.
749%
750% The format of the SeedPseudoRandomGenerator method is:
751%
cristyebbcfea2011-02-25 02:43:54 +0000752% void SeedPseudoRandomGenerator(const unsigned long seed)
cristy3ed852e2009-09-05 21:47:34 +0000753%
754% A description of each parameter follows:
755%
756% o seed: the seed.
757%
758*/
cristybb503372010-05-27 20:51:26 +0000759MagickExport void SeedPseudoRandomGenerator(const size_t seed)
cristy3ed852e2009-09-05 21:47:34 +0000760{
761 random_seed=seed;
762}
763
764/*
765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766% %
767% %
768% %
769% S e t R a n d o m K e y %
770% %
771% %
772% %
773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774%
775% SetRandomKey() sets a random key from the reservoir.
776%
777% The format of the SetRandomKey method is:
778%
779% void SetRandomKey(RandomInfo *random_info,const size_t length,
780% unsigned char *key)
781%
782% A description of each parameter follows:
783%
784% o random_info: the random info.
785%
786% o length: the key length.
787%
788% o key: the key.
789%
790*/
791
792static inline void IncrementRandomNonce(StringInfo *nonce)
793{
cristybb503372010-05-27 20:51:26 +0000794 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000795 i;
796
797 unsigned char
798 *datum;
799
800 datum=GetStringInfoDatum(nonce);
cristybb503372010-05-27 20:51:26 +0000801 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
cristy3ed852e2009-09-05 21:47:34 +0000802 {
803 datum[i]++;
804 if (datum[i] != 0)
805 return;
806 }
807 ThrowFatalException(RandomFatalError,"SequenceWrapError");
808}
809
810MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
811 unsigned char *key)
812{
813 register size_t
814 i;
815
816 register unsigned char
817 *p;
818
819 SignatureInfo
820 *signature_info;
821
822 unsigned char
823 *datum;
824
825 assert(random_info != (RandomInfo *) NULL);
826 if (length == 0)
827 return;
cristyf84a1932010-01-03 18:00:18 +0000828 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000829 signature_info=random_info->signature_info;
830 datum=GetStringInfoDatum(random_info->reservoir);
831 i=length;
832 for (p=key; (i != 0) && (random_info->i != 0); i--)
833 {
834 *p++=datum[random_info->i];
835 random_info->i++;
836 if (random_info->i == GetSignatureDigestsize(signature_info))
837 random_info->i=0;
838 }
839 while (i >= GetSignatureDigestsize(signature_info))
840 {
841 InitializeSignature(signature_info);
842 UpdateSignature(signature_info,random_info->nonce);
843 FinalizeSignature(signature_info);
844 IncrementRandomNonce(random_info->nonce);
845 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
846 signature_info)),GetSignatureDigestsize(signature_info));
847 p+=GetSignatureDigestsize(signature_info);
848 i-=GetSignatureDigestsize(signature_info);
849 }
850 if (i != 0)
851 {
852 InitializeSignature(signature_info);
853 UpdateSignature(signature_info,random_info->nonce);
854 FinalizeSignature(signature_info);
855 IncrementRandomNonce(random_info->nonce);
856 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
857 random_info->i=i;
858 datum=GetStringInfoDatum(random_info->reservoir);
859 while (i-- != 0)
860 p[i]=datum[i];
861 }
cristyf84a1932010-01-03 18:00:18 +0000862 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000863}
864
865/*
866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867% %
868% %
869% %
870% S e t R a n d o m T r u e R a n d o m %
871% %
872% %
873% %
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875%
876% SetRandomTrueRandom() declares your intentions to use true random numbers.
877% True random numbers are encouraged but may not always be practical because
878% your application may block while entropy is gathered from your environment.
879%
880% The format of the SetRandomTrueRandom method is:
881%
882% void SetRandomTrueRandom(const MagickBooleanType true_random)
883%
884% A description of each parameter follows:
885%
886% o true_random: declare your intentions to use true-random number.
887%
888*/
889MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
890{
891 gather_true_random=true_random;
892}