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