]> granicus.if.org Git - imagemagick/blob - magick/random.c
(no commit message)
[imagemagick] / magick / 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 "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 \f
72 /*
73   Typedef declarations.
74 */
75 struct _RandomInfo
76 {
77   SignatureInfo
78     *signature_info;
79
80   StringInfo
81     *nonce,
82     *reservoir;
83
84   size_t
85     i;
86
87   size_t
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   ssize_t
101     timestamp;
102
103   size_t
104     signature;
105 };
106 \f
107 /*
108   External declarations.
109 */
110 #if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
111 #include <crt_externs.h>
112 #define environ (*_NSGetEnviron())
113 #endif
114
115 extern char
116   **environ;
117 \f
118 /*
119   Global declarations.
120 */
121 static SemaphoreInfo
122   *random_semaphore = (SemaphoreInfo *) NULL;
123
124 static size_t
125   random_seed = ~0UL;
126
127 static MagickBooleanType
128   gather_true_random = MagickFalse;
129 \f
130 /*
131   Forward declarations.
132 */
133 static StringInfo
134   *GenerateEntropicChaos(RandomInfo *);
135 \f
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
155 static 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
162 MagickExport 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 *) AcquireMagickMemory(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=(ssize_t) 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 \f
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 */
273 MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
274 {
275   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
276   assert(random_info != (RandomInfo *) NULL);
277   assert(random_info->signature == MagickSignature);
278   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   UnlockSemaphoreInfo(random_info->semaphore);
289   DestroySemaphoreInfo(&random_info->semaphore);
290   random_info=(RandomInfo *) RelinquishMagickMemory(random_info);
291   return(random_info);
292 }
293 \f
294 /*
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 %                                                                             %
297 %                                                                             %
298 %                                                                             %
299 +   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
318 #if !defined(MAGICKCORE_WINDOWS_SUPPORT)
319 static 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 }
344 #endif
345
346 static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
347 {
348 #define MaxEntropyExtent  64
349
350   ssize_t
351     pid;
352
353   MagickThreadType
354     tid;
355
356   StringInfo
357     *chaos,
358     *entropy;
359
360   size_t
361     nanoseconds,
362     seconds;
363
364   /*
365     Initialize random reservoir.
366   */
367   entropy=AcquireStringInfo(0);
368   LockSemaphoreInfo(random_info->semaphore);
369   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);
374   pid=(ssize_t) getpid();
375   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
401     if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
402       {
403         seconds=timer.tv_sec;
404         nanoseconds=1000UL*timer.tv_usec;
405       }
406   }
407 #endif
408 #if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
409   {
410     struct timespec
411       timer;
412
413     if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
414       {
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
464 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
465   {
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       {
514         register ssize_t
515           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);
569   UnlockSemaphoreInfo(random_info->semaphore);
570   return(entropy);
571 }
572 \f
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 */
597 MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
598 {
599   register size_t
600     *seed;
601
602   size_t
603     alpha;
604
605   seed=random_info->seed;
606   do
607   {
608     alpha=(size_t) (seed[1] ^ (seed[1] << 11));
609     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 \f
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 */
641 MagickExport 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 \f
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 */
673 MagickExport double GetRandomValue(RandomInfo *random_info)
674 {
675   size_t
676     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 \f
687 /*
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 +   R a n d o m C o m p o n e n t G e n e s i s                               %
693 %                                                                             %
694 %                                                                             %
695 %                                                                             %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %
698 %  RandomComponentGenesis() instantiates the random component.
699 %
700 %  The format of the RandomComponentGenesis method is:
701 %
702 %      MagickBooleanType RandomComponentGenesis(void)
703 %
704 */
705 MagickExport MagickBooleanType RandomComponentGenesis(void)
706 {
707   AcquireSemaphoreInfo(&random_semaphore);
708   return(MagickTrue);
709 }
710 \f
711 /*
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
713 %                                                                             %
714 %                                                                             %
715 %                                                                             %
716 +   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 */
729 MagickExport void RandomComponentTerminus(void)
730 {
731   if (random_semaphore == (SemaphoreInfo *) NULL)
732     AcquireSemaphoreInfo(&random_semaphore);
733   DestroySemaphoreInfo(&random_semaphore);
734 }
735 \f
736 /*
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 %                                                                             %
739 %                                                                             %
740 %                                                                             %
741 %   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 %
752 %      void SeedPseudoRandomGenerator(const size_t seed)
753 %
754 %  A description of each parameter follows:
755 %
756 %    o seed: the seed.
757 %
758 */
759 MagickExport void SeedPseudoRandomGenerator(const size_t seed)
760 {
761   random_seed=seed;
762 }
763 \f
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
792 static inline void IncrementRandomNonce(StringInfo *nonce)
793 {
794   register ssize_t
795     i;
796
797   unsigned char
798     *datum;
799
800   datum=GetStringInfoDatum(nonce);
801   for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
802   {
803     datum[i]++;
804     if (datum[i] != 0)
805       return;
806   }
807   ThrowFatalException(RandomFatalError,"SequenceWrapError");
808 }
809
810 MagickExport 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;
828   LockSemaphoreInfo(random_info->semaphore);
829   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     }
862   UnlockSemaphoreInfo(random_info->semaphore);
863 }
864 \f
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 */
889 MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
890 {
891   gather_true_random=true_random;
892 }