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