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