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