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