blob: fe0c78402e04d2a7568764689f92ac5ca6f1bdc9 [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% %
19% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
20% 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
87 unsigned long
88 seed[4];
89
90 double
91 normalize;
92
93 unsigned short
94 protocol_major,
95 protocol_minor;
96
97 SemaphoreInfo
98 *semaphore;
99
100 long
101 timestamp;
102
103 unsigned long
104 signature;
105};
106
107/*
108 External declarations.
109*/
110#if defined(__APPLE__)
111#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
124static unsigned long
125 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
175 random_info=(RandomInfo *) AcquireAlignedMemory(1,sizeof(*random_info));
176 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;
190 random_info->timestamp=(long) time(0);
191 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);
278 (void) LockSemaphoreInfo(random_info->semaphore);
279 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);
288 (void) UnlockSemaphoreInfo(random_info->semaphore);
289 DestroySemaphoreInfo(&random_info->semaphore);
290 random_info=(RandomInfo *) RelinquishAlignedMemory(random_info);
291 return(random_info);
292}
293
294/*
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296% %
297% %
298% %
299+ D e s t r o y R a n d o m R e s e r v i o r %
300% %
301% %
302% %
303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304%
305% DestroyRandomReservoir() deallocates memory associated with the random
306% reservoir.
307%
308% The format of the DestroyRandomReservoir method is:
309%
310% DestroyRandomReservoir(void)
311%
312*/
313MagickExport void DestroyRandomReservoir(void)
314{
315 AcquireSemaphoreInfo(&random_semaphore);
316 (void) UnlockSemaphoreInfo(random_semaphore);
317 DestroySemaphoreInfo(&random_semaphore);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
325+ G e n e r a t e E n t r o p i c C h a o s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% GenerateEntropicChaos() generate entropic chaos used to initialize the
332% random reservoir.
333%
334% The format of the GenerateEntropicChaos method is:
335%
336% StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
337%
338% A description of each parameter follows:
339%
340% o random_info: the random info.
341%
342*/
343
cristy39615682009-09-22 18:10:17 +0000344#if !defined(__WINDOWS__)
cristy3ed852e2009-09-05 21:47:34 +0000345static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
346{
347 register unsigned char
348 *q;
349
350 ssize_t
351 offset,
352 count;
353
354 offset=0;
355 for (q=source; length != 0; length-=count)
356 {
357 count=(ssize_t) read(file,q,length);
358 if (count <= 0)
359 {
360 count=0;
361 if (errno == EINTR)
362 continue;
363 return(-1);
364 }
365 q+=count;
366 offset+=count;
367 }
368 return(offset);
369}
cristy39615682009-09-22 18:10:17 +0000370#endif
cristy3ed852e2009-09-05 21:47:34 +0000371
372static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
373{
374#define MaxEntropyExtent 64
375
376 long
377 pid;
378
379 MagickThreadType
380 tid;
381
382 StringInfo
383 *chaos,
384 *entropy;
385
386 unsigned long
387 nanoseconds,
388 seconds;
389
390 /*
391 Initialize random reservoir.
392 */
393 entropy=AcquireStringInfo(0);
394 (void) LockSemaphoreInfo(random_info->semaphore);
395 chaos=AcquireStringInfo(sizeof(unsigned char *));
396 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
397 ConcatenateStringInfo(entropy,chaos);
398 SetStringInfoDatum(chaos,(unsigned char *) entropy);
399 ConcatenateStringInfo(entropy,chaos);
400 pid=(long) getpid();
401 SetStringInfoLength(chaos,sizeof(pid));
402 SetStringInfoDatum(chaos,(unsigned char *) &pid);
403 ConcatenateStringInfo(entropy,chaos);
404 tid=GetMagickThreadId();
405 SetStringInfoLength(chaos,sizeof(tid));
406 SetStringInfoDatum(chaos,(unsigned char *) &tid);
407 ConcatenateStringInfo(entropy,chaos);
408#if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
409 {
410 struct rusage
411 usage;
412
413 if (getrusage(RUSAGE_SELF,&usage) == 0)
414 {
415 SetStringInfoLength(chaos,sizeof(usage));
416 SetStringInfoDatum(chaos,(unsigned char *) &usage);
417 }
418 }
419#endif
420 seconds=time((time_t *) 0);
421 nanoseconds=0;
422#if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
423 {
424 struct timeval
425 timer;
426
427 if (gettimeofday(&timer,0) == 0)
428 {
429 seconds=timer.tv_sec;
430 nanoseconds=1000UL*timer.tv_usec;
431 }
432 }
433#endif
cristyc16a63e2009-09-28 13:20:14 +0000434#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
cristy3ed852e2009-09-05 21:47:34 +0000435 {
436 struct timespec
437 timer;
438
cristyc16a63e2009-09-28 13:20:14 +0000439 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000440 {
441 seconds=timer.tv_sec;
442 nanoseconds=timer.tv_nsec;
443 }
444 }
445#endif
446 SetStringInfoLength(chaos,sizeof(seconds));
447 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
448 ConcatenateStringInfo(entropy,chaos);
449 SetStringInfoLength(chaos,sizeof(nanoseconds));
450 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
451 ConcatenateStringInfo(entropy,chaos);
452 nanoseconds=0;
453#if defined(MAGICKCORE_HAVE_CLOCK)
454 nanoseconds=clock();
455#endif
456#if defined(MAGICKCORE_HAVE_TIMES)
457 {
458 struct tms
459 timer;
460
461 (void) times(&timer);
462 nanoseconds=timer.tms_utime+timer.tms_stime;
463 }
464#endif
465 SetStringInfoLength(chaos,sizeof(nanoseconds));
466 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
467 ConcatenateStringInfo(entropy,chaos);
468#if defined(MAGICKCORE_HAVE_MKSTEMP)
469 {
470 char
471 *filename;
472
473 int
474 file;
475
476 filename=ConstantString("magickXXXXXX");
477 file=mkstemp(filename);
478#if defined(__OS2__)
479 setmode(file,O_BINARY);
480#endif
481 if (file != -1)
482 (void) close(file);
483 (void) remove(filename);
484 SetStringInfoLength(chaos,strlen(filename));
485 SetStringInfoDatum(chaos,(unsigned char *) filename);
486 ConcatenateStringInfo(entropy,chaos);
487 filename=DestroyString(filename);
488 }
489#endif
490#if defined(__WINDOWS__)
491 {
492 double
493 seconds;
494
495 LARGE_INTEGER
496 nanoseconds;
497
498 MagickBooleanType
499 status;
500
501 /*
502 Not crytographically strong but better than nothing.
503 */
504 seconds=NTElapsedTime()+NTUserTime();
505 SetStringInfoLength(chaos,sizeof(seconds));
506 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
507 ConcatenateStringInfo(entropy,chaos);
508 if (QueryPerformanceCounter(&nanoseconds) != 0)
509 {
510 SetStringInfoLength(chaos,sizeof(nanoseconds));
511 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
512 ConcatenateStringInfo(entropy,chaos);
513 }
514 /*
515 Our best hope for true entropy.
516 */
517 SetStringInfoLength(chaos,MaxEntropyExtent);
518 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
519 ConcatenateStringInfo(entropy,chaos);
520 }
521#else
522 {
523 char
524 *filename;
525
526 int
527 file;
528
529 ssize_t
530 count;
531
532 StringInfo
533 *device;
534
535 /*
536 Not crytographically strong but better than nothing.
537 */
538 if (environ != (char **) NULL)
539 {
540 register long
541 i;
542
543 /*
544 Squeeze some entropy from the sometimes unpredicatble environment.
545 */
546 for (i=0; environ[i] != (char *) NULL; i++)
547 {
548 SetStringInfoLength(chaos,strlen(environ[i]));
549 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
550 ConcatenateStringInfo(entropy,chaos);
551 }
552 }
553 filename=AcquireString("/dev/urandom");
554 device=StringToStringInfo(filename);
555 device=DestroyStringInfo(device);
556 file=open(filename,O_RDONLY | O_BINARY);
557 filename=DestroyString(filename);
558 if (file != -1)
559 {
560 SetStringInfoLength(chaos,MaxEntropyExtent);
561 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
562 (void) close(file);
563 SetStringInfoLength(chaos,(size_t) count);
564 ConcatenateStringInfo(entropy,chaos);
565 }
566 if (gather_true_random != MagickFalse)
567 {
568 /*
569 Our best hope for true entropy.
570 */
571 filename=AcquireString("/dev/random");
572 device=StringToStringInfo(filename);
573 device=DestroyStringInfo(device);
574 file=open(filename,O_RDONLY | O_BINARY);
575 filename=DestroyString(filename);
576 if (file == -1)
577 {
578 filename=AcquireString("/dev/srandom");
579 device=StringToStringInfo(filename);
580 device=DestroyStringInfo(device);
581 file=open(filename,O_RDONLY | O_BINARY);
582 }
583 if (file != -1)
584 {
585 SetStringInfoLength(chaos,MaxEntropyExtent);
586 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
587 (void) close(file);
588 SetStringInfoLength(chaos,(size_t) count);
589 ConcatenateStringInfo(entropy,chaos);
590 }
591 }
592 }
593#endif
594 chaos=DestroyStringInfo(chaos);
595 (void) UnlockSemaphoreInfo(random_info->semaphore);
596 return(entropy);
597}
598
599/*
600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601% %
602% %
603% %
604% G e t P s e u d o R a n d o m V a l u e %
605% %
606% %
607% %
608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609%
610% GetPseudoRandomValue() return a non-negative double-precision floating-point
611% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
612% 128th-1 period.
613%
614% The format of the GetPseudoRandomValue method is:
615%
616% double GetPseudoRandomValue(RandomInfo *randon_info)
617%
618% A description of each parameter follows:
619%
620% o random_info: the random info.
621%
622*/
623MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
624{
625 register unsigned long
626 *seed;
627
628 unsigned long
629 alpha;
630
631 seed=random_info->seed;
632 do
633 {
634 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
635 seed[1]=seed[2];
636 seed[2]=seed[3];
637 seed[3]=seed[0];
638 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
639 } while (seed[0] == ~0UL);
640 return(random_info->normalize*seed[0]);
641}
642
643/*
644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
645% %
646% %
647% %
648% G e t R a n d o m K e y %
649% %
650% %
651% %
652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653%
654% GetRandomKey() gets a random key from the reservoir.
655%
656% The format of the GetRandomKey method is:
657%
658% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
659%
660% A description of each parameter follows:
661%
662% o random_info: the random info.
663%
664% o length: the key length.
665%
666*/
667MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
668 const size_t length)
669{
670 StringInfo
671 *key;
672
673 assert(random_info != (RandomInfo *) NULL);
674 key=AcquireStringInfo(length);
675 SetRandomKey(random_info,length,GetStringInfoDatum(key));
676 return(key);
677}
678
679/*
680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681% %
682% %
683% %
684% G e t R a n d o m V a l u e %
685% %
686% %
687% %
688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689%
690% GetRandomValue() return a non-negative double-precision floating-point
691% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
692% 128th-1 period (not cryptographically strong).
693%
694% The format of the GetRandomValue method is:
695%
696% double GetRandomValue(void)
697%
698*/
699MagickExport double GetRandomValue(RandomInfo *random_info)
700{
701 unsigned long
702 key,
703 range;
704
705 range=(~0UL);
706 do
707 {
708 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
709 } while (key == range);
710 return((double) key/range);
711}
712
713/*
714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715% %
716% %
717% %
718% 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 %
719% %
720% %
721% %
722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723%
724% SeedPseudoRandomGenerator() initializes the pseudo-random number generator
725% with a random seed.
726%
727% The format of the SeedPseudoRandomGenerator method is:
728%
729% void SeedPseudoRandomGenerator(const unsigned long seed)
730%
731% A description of each parameter follows:
732%
733% o seed: the seed.
734%
735*/
736MagickExport void SeedPseudoRandomGenerator(const unsigned long seed)
737{
738 random_seed=seed;
739}
740
741/*
742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
743% %
744% %
745% %
746% S e t R a n d o m K e y %
747% %
748% %
749% %
750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751%
752% SetRandomKey() sets a random key from the reservoir.
753%
754% The format of the SetRandomKey method is:
755%
756% void SetRandomKey(RandomInfo *random_info,const size_t length,
757% unsigned char *key)
758%
759% A description of each parameter follows:
760%
761% o random_info: the random info.
762%
763% o length: the key length.
764%
765% o key: the key.
766%
767*/
768
769static inline void IncrementRandomNonce(StringInfo *nonce)
770{
771 register long
772 i;
773
774 unsigned char
775 *datum;
776
777 datum=GetStringInfoDatum(nonce);
778 for (i=(long) (GetStringInfoLength(nonce)-1); i != 0; i--)
779 {
780 datum[i]++;
781 if (datum[i] != 0)
782 return;
783 }
784 ThrowFatalException(RandomFatalError,"SequenceWrapError");
785}
786
787MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
788 unsigned char *key)
789{
790 register size_t
791 i;
792
793 register unsigned char
794 *p;
795
796 SignatureInfo
797 *signature_info;
798
799 unsigned char
800 *datum;
801
802 assert(random_info != (RandomInfo *) NULL);
803 if (length == 0)
804 return;
805 (void) LockSemaphoreInfo(random_info->semaphore);
806 signature_info=random_info->signature_info;
807 datum=GetStringInfoDatum(random_info->reservoir);
808 i=length;
809 for (p=key; (i != 0) && (random_info->i != 0); i--)
810 {
811 *p++=datum[random_info->i];
812 random_info->i++;
813 if (random_info->i == GetSignatureDigestsize(signature_info))
814 random_info->i=0;
815 }
816 while (i >= GetSignatureDigestsize(signature_info))
817 {
818 InitializeSignature(signature_info);
819 UpdateSignature(signature_info,random_info->nonce);
820 FinalizeSignature(signature_info);
821 IncrementRandomNonce(random_info->nonce);
822 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
823 signature_info)),GetSignatureDigestsize(signature_info));
824 p+=GetSignatureDigestsize(signature_info);
825 i-=GetSignatureDigestsize(signature_info);
826 }
827 if (i != 0)
828 {
829 InitializeSignature(signature_info);
830 UpdateSignature(signature_info,random_info->nonce);
831 FinalizeSignature(signature_info);
832 IncrementRandomNonce(random_info->nonce);
833 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
834 random_info->i=i;
835 datum=GetStringInfoDatum(random_info->reservoir);
836 while (i-- != 0)
837 p[i]=datum[i];
838 }
839 (void) UnlockSemaphoreInfo(random_info->semaphore);
840}
841
842/*
843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844% %
845% %
846% %
847% S e t R a n d o m T r u e R a n d o m %
848% %
849% %
850% %
851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852%
853% SetRandomTrueRandom() declares your intentions to use true random numbers.
854% True random numbers are encouraged but may not always be practical because
855% your application may block while entropy is gathered from your environment.
856%
857% The format of the SetRandomTrueRandom method is:
858%
859% void SetRandomTrueRandom(const MagickBooleanType true_random)
860%
861% A description of each parameter follows:
862%
863% o true_random: declare your intentions to use true-random number.
864%
865*/
866MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
867{
868 gather_true_random=true_random;
869}