blob: 25b6fdc742a7830393fb4c6915195a84715aabf2 [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% %
cristyfe676ee2013-11-18 13:03:38 +000019% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000020% 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
cristy07a3cca2012-12-10 13:09:10 +000047#if defined(__MINGW32__) || defined(__MINGW64__)
cristy3ed852e2009-09-05 21:47:34 +000048#include <sys/time.h>
49#endif
cristy4c08aed2011-07-01 19:47:50 +000050#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"
cristy5ff4eaf2011-09-03 01:38:02 +000056#include "MagickCore/random-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#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"
cristy18c6c272011-09-23 14:40:37 +000063#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000064/*
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
cristy2c54ad32011-02-25 02:45:27 +000089 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000090 seed[4];
91
92 double
93 normalize;
94
cristye7452652012-04-14 01:34:21 +000095 unsigned long
96 secret_key;
97
cristy3ed852e2009-09-05 21:47:34 +000098 unsigned short
99 protocol_major,
100 protocol_minor;
101
102 SemaphoreInfo
103 *semaphore;
104
cristybb503372010-05-27 20:51:26 +0000105 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000106 timestamp;
107
cristybb503372010-05-27 20:51:26 +0000108 size_t
cristy3ed852e2009-09-05 21:47:34 +0000109 signature;
110};
111
112/*
113 External declarations.
114*/
cristya65f35b2010-04-20 01:10:41 +0000115#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
cristy3ed852e2009-09-05 21:47:34 +0000116#include <crt_externs.h>
117#define environ (*_NSGetEnviron())
118#endif
119
120extern char
121 **environ;
122
123/*
124 Global declarations.
125*/
126static SemaphoreInfo
127 *random_semaphore = (SemaphoreInfo *) NULL;
128
cristy4bc38542011-02-25 12:59:29 +0000129static unsigned long
cristybaf31e92012-04-14 01:44:01 +0000130 secret_key = ~0UL;
cristy3ed852e2009-09-05 21:47:34 +0000131
132static MagickBooleanType
133 gather_true_random = MagickFalse;
134
135/*
136 Forward declarations.
137*/
138static StringInfo
139 *GenerateEntropicChaos(RandomInfo *);
140
141/*
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143% %
144% %
145% %
146% A c q u i r e R a n d o m I n f o %
147% %
148% %
149% %
150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151%
152% AcquireRandomInfo() allocates the RandomInfo structure.
153%
154% The format of the AcquireRandomInfo method is:
155%
156% RandomInfo *AcquireRandomInfo(void)
157%
158*/
159
160static inline size_t MagickMin(const size_t x,const size_t y)
161{
162 if (x < y)
163 return(x);
164 return(y);
165}
166
167MagickExport RandomInfo *AcquireRandomInfo(void)
168{
169 const StringInfo
170 *digest;
171
172 RandomInfo
173 *random_info;
174
175 StringInfo
176 *entropy,
177 *key,
178 *nonce;
179
cristy73bd4a52010-10-05 11:24:23 +0000180 random_info=(RandomInfo *) AcquireMagickMemory(sizeof(*random_info));
cristy3ed852e2009-09-05 21:47:34 +0000181 if (random_info == (RandomInfo *) NULL)
182 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
183 (void) ResetMagickMemory(random_info,0,sizeof(*random_info));
184 random_info->signature_info=AcquireSignatureInfo();
185 random_info->nonce=AcquireStringInfo(2*GetSignatureDigestsize(
186 random_info->signature_info));
187 ResetStringInfo(random_info->nonce);
188 random_info->reservoir=AcquireStringInfo(GetSignatureDigestsize(
189 random_info->signature_info));
190 ResetStringInfo(random_info->reservoir);
cristy728891d2011-10-07 18:55:11 +0000191 random_info->normalize=1.0/(~0UL);
cristybaf31e92012-04-14 01:44:01 +0000192 random_info->secret_key=secret_key;
cristy3ed852e2009-09-05 21:47:34 +0000193 random_info->protocol_major=RandomProtocolMajorVersion;
194 random_info->protocol_minor=RandomProtocolMinorVersion;
cristye7452652012-04-14 01:34:21 +0000195 random_info->semaphore=AllocateSemaphoreInfo();
cristybb503372010-05-27 20:51:26 +0000196 random_info->timestamp=(ssize_t) time(0);
cristy3ed852e2009-09-05 21:47:34 +0000197 random_info->signature=MagickSignature;
198 /*
199 Seed random nonce.
200 */
201 nonce=GenerateEntropicChaos(random_info);
202 if (nonce == (StringInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 InitializeSignature(random_info->signature_info);
205 UpdateSignature(random_info->signature_info,nonce);
206 FinalizeSignature(random_info->signature_info);
207 SetStringInfoLength(nonce,(GetSignatureDigestsize(
208 random_info->signature_info)+1)/2);
209 SetStringInfo(nonce,GetSignatureDigest(random_info->signature_info));
210 SetStringInfo(random_info->nonce,nonce);
211 nonce=DestroyStringInfo(nonce);
212 /*
213 Seed random reservoir with entropic data.
214 */
215 entropy=GenerateEntropicChaos(random_info);
216 if (entropy == (StringInfo *) NULL)
217 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
218 UpdateSignature(random_info->signature_info,entropy);
219 FinalizeSignature(random_info->signature_info);
220 SetStringInfo(random_info->reservoir,GetSignatureDigest(
221 random_info->signature_info));
222 entropy=DestroyStringInfo(entropy);
223 /*
224 Seed pseudo random number generator.
225 */
cristye7452652012-04-14 01:34:21 +0000226 if (random_info->secret_key == ~0UL)
cristy3ed852e2009-09-05 21:47:34 +0000227 {
cristye7452652012-04-14 01:34:21 +0000228 key=GetRandomKey(random_info,sizeof(random_info->secret_key));
cristy3ed852e2009-09-05 21:47:34 +0000229 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(key),
230 GetStringInfoLength(key));
231 key=DestroyStringInfo(key);
232 }
233 else
234 {
235 SignatureInfo
236 *signature_info;
237
238 signature_info=AcquireSignatureInfo();
cristye7452652012-04-14 01:34:21 +0000239 key=AcquireStringInfo(sizeof(random_info->secret_key));
240 SetStringInfoDatum(key,(unsigned char *) &random_info->secret_key);
cristy3ed852e2009-09-05 21:47:34 +0000241 UpdateSignature(signature_info,key);
242 key=DestroyStringInfo(key);
243 FinalizeSignature(signature_info);
244 digest=GetSignatureDigest(signature_info);
245 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(digest),
246 MagickMin(GetSignatureDigestsize(signature_info),
247 sizeof(*random_info->seed)));
248 signature_info=DestroySignatureInfo(signature_info);
249 }
250 random_info->seed[1]=0x50a7f451UL;
251 random_info->seed[2]=0x5365417eUL;
252 random_info->seed[3]=0xc3a4171aUL;
253 return(random_info);
254}
255
256/*
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258% %
259% %
260% %
261+ D e s t r o y R a n d o m I n f o %
262% %
263% %
264% %
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266%
267% DestroyRandomInfo() deallocates memory associated with the random
268% reservoir.
269%
270% The format of the DestroyRandomInfo method is:
271%
272% RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
273%
274% A description of each parameter follows:
275%
276% o random_info: the random info.
277%
278*/
279MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
280{
281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
282 assert(random_info != (RandomInfo *) NULL);
283 assert(random_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000284 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000285 if (random_info->reservoir != (StringInfo *) NULL)
286 random_info->reservoir=DestroyStringInfo(random_info->reservoir);
287 if (random_info->nonce != (StringInfo *) NULL)
288 random_info->nonce=DestroyStringInfo(random_info->nonce);
289 if (random_info->signature_info != (SignatureInfo *) NULL)
290 random_info->signature_info=DestroySignatureInfo(
291 random_info->signature_info);
292 (void) ResetMagickMemory(random_info->seed,0,sizeof(*random_info->seed));
293 random_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000294 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000295 DestroySemaphoreInfo(&random_info->semaphore);
cristyb41ee102010-10-04 16:46:15 +0000296 random_info=(RandomInfo *) RelinquishMagickMemory(random_info);
cristy3ed852e2009-09-05 21:47:34 +0000297 return(random_info);
298}
299
300/*
301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302% %
303% %
304% %
cristy3ed852e2009-09-05 21:47:34 +0000305+ G e n e r a t e E n t r o p i c C h a o s %
306% %
307% %
308% %
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310%
311% GenerateEntropicChaos() generate entropic chaos used to initialize the
312% random reservoir.
313%
314% The format of the GenerateEntropicChaos method is:
315%
316% StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
317%
318% A description of each parameter follows:
319%
320% o random_info: the random info.
321%
322*/
323
cristy0157aea2010-04-24 21:12:18 +0000324#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000325static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
326{
327 register unsigned char
328 *q;
329
330 ssize_t
331 offset,
332 count;
333
334 offset=0;
335 for (q=source; length != 0; length-=count)
336 {
337 count=(ssize_t) read(file,q,length);
338 if (count <= 0)
339 {
340 count=0;
341 if (errno == EINTR)
342 continue;
343 return(-1);
344 }
345 q+=count;
346 offset+=count;
347 }
348 return(offset);
349}
cristy39615682009-09-22 18:10:17 +0000350#endif
cristy3ed852e2009-09-05 21:47:34 +0000351
352static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
353{
354#define MaxEntropyExtent 64
355
cristy3ed852e2009-09-05 21:47:34 +0000356 MagickThreadType
357 tid;
358
359 StringInfo
360 *chaos,
361 *entropy;
362
cristybb503372010-05-27 20:51:26 +0000363 size_t
cristy3ed852e2009-09-05 21:47:34 +0000364 nanoseconds,
365 seconds;
366
cristy9d314ff2011-03-09 01:30:28 +0000367 ssize_t
368 pid;
369
cristy3ed852e2009-09-05 21:47:34 +0000370 /*
371 Initialize random reservoir.
372 */
373 entropy=AcquireStringInfo(0);
cristyf84a1932010-01-03 18:00:18 +0000374 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000375 chaos=AcquireStringInfo(sizeof(unsigned char *));
376 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
377 ConcatenateStringInfo(entropy,chaos);
378 SetStringInfoDatum(chaos,(unsigned char *) entropy);
379 ConcatenateStringInfo(entropy,chaos);
cristybb503372010-05-27 20:51:26 +0000380 pid=(ssize_t) getpid();
cristy3ed852e2009-09-05 21:47:34 +0000381 SetStringInfoLength(chaos,sizeof(pid));
382 SetStringInfoDatum(chaos,(unsigned char *) &pid);
383 ConcatenateStringInfo(entropy,chaos);
384 tid=GetMagickThreadId();
385 SetStringInfoLength(chaos,sizeof(tid));
386 SetStringInfoDatum(chaos,(unsigned char *) &tid);
387 ConcatenateStringInfo(entropy,chaos);
388#if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
389 {
390 struct rusage
391 usage;
392
393 if (getrusage(RUSAGE_SELF,&usage) == 0)
394 {
395 SetStringInfoLength(chaos,sizeof(usage));
396 SetStringInfoDatum(chaos,(unsigned char *) &usage);
397 }
398 }
399#endif
400 seconds=time((time_t *) 0);
401 nanoseconds=0;
402#if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
403 {
404 struct timeval
405 timer;
406
cristy6d71f8d2010-02-28 00:46:02 +0000407 if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000408 {
409 seconds=timer.tv_sec;
410 nanoseconds=1000UL*timer.tv_usec;
411 }
412 }
413#endif
cristyc16a63e2009-09-28 13:20:14 +0000414#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
cristy3ed852e2009-09-05 21:47:34 +0000415 {
416 struct timespec
417 timer;
418
cristyc16a63e2009-09-28 13:20:14 +0000419 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000420 {
421 seconds=timer.tv_sec;
422 nanoseconds=timer.tv_nsec;
423 }
424 }
425#endif
426 SetStringInfoLength(chaos,sizeof(seconds));
427 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
428 ConcatenateStringInfo(entropy,chaos);
429 SetStringInfoLength(chaos,sizeof(nanoseconds));
430 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
431 ConcatenateStringInfo(entropy,chaos);
432 nanoseconds=0;
433#if defined(MAGICKCORE_HAVE_CLOCK)
434 nanoseconds=clock();
435#endif
436#if defined(MAGICKCORE_HAVE_TIMES)
437 {
438 struct tms
439 timer;
440
441 (void) times(&timer);
442 nanoseconds=timer.tms_utime+timer.tms_stime;
443 }
444#endif
445 SetStringInfoLength(chaos,sizeof(nanoseconds));
446 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
447 ConcatenateStringInfo(entropy,chaos);
448#if defined(MAGICKCORE_HAVE_MKSTEMP)
449 {
450 char
451 *filename;
452
453 int
454 file;
455
456 filename=ConstantString("magickXXXXXX");
457 file=mkstemp(filename);
458#if defined(__OS2__)
459 setmode(file,O_BINARY);
460#endif
461 if (file != -1)
462 (void) close(file);
cristy91afbeb2013-04-18 16:03:06 +0000463 (void) remove_utf8(filename);
cristy3ed852e2009-09-05 21:47:34 +0000464 SetStringInfoLength(chaos,strlen(filename));
465 SetStringInfoDatum(chaos,(unsigned char *) filename);
466 ConcatenateStringInfo(entropy,chaos);
467 filename=DestroyString(filename);
468 }
469#endif
cristy0157aea2010-04-24 21:12:18 +0000470#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000471 {
472 double
473 seconds;
474
475 LARGE_INTEGER
476 nanoseconds;
477
478 MagickBooleanType
479 status;
480
481 /*
482 Not crytographically strong but better than nothing.
483 */
484 seconds=NTElapsedTime()+NTUserTime();
485 SetStringInfoLength(chaos,sizeof(seconds));
486 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
487 ConcatenateStringInfo(entropy,chaos);
488 if (QueryPerformanceCounter(&nanoseconds) != 0)
489 {
490 SetStringInfoLength(chaos,sizeof(nanoseconds));
491 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
492 ConcatenateStringInfo(entropy,chaos);
493 }
494 /*
495 Our best hope for true entropy.
496 */
497 SetStringInfoLength(chaos,MaxEntropyExtent);
498 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
cristyd0933fd2012-02-19 22:05:42 +0000499 (void) status;
cristy3ed852e2009-09-05 21:47:34 +0000500 ConcatenateStringInfo(entropy,chaos);
501 }
502#else
503 {
504 char
505 *filename;
506
507 int
508 file;
509
510 ssize_t
511 count;
512
513 StringInfo
514 *device;
515
516 /*
517 Not crytographically strong but better than nothing.
518 */
519 if (environ != (char **) NULL)
520 {
cristybb503372010-05-27 20:51:26 +0000521 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000522 i;
523
524 /*
525 Squeeze some entropy from the sometimes unpredicatble environment.
526 */
527 for (i=0; environ[i] != (char *) NULL; i++)
528 {
529 SetStringInfoLength(chaos,strlen(environ[i]));
530 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
531 ConcatenateStringInfo(entropy,chaos);
532 }
533 }
534 filename=AcquireString("/dev/urandom");
535 device=StringToStringInfo(filename);
536 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000537 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000538 filename=DestroyString(filename);
539 if (file != -1)
540 {
541 SetStringInfoLength(chaos,MaxEntropyExtent);
542 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
543 (void) close(file);
544 SetStringInfoLength(chaos,(size_t) count);
545 ConcatenateStringInfo(entropy,chaos);
546 }
547 if (gather_true_random != MagickFalse)
548 {
549 /*
550 Our best hope for true entropy.
551 */
552 filename=AcquireString("/dev/random");
553 device=StringToStringInfo(filename);
554 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000555 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000556 filename=DestroyString(filename);
557 if (file == -1)
558 {
559 filename=AcquireString("/dev/srandom");
560 device=StringToStringInfo(filename);
561 device=DestroyStringInfo(device);
cristy18c6c272011-09-23 14:40:37 +0000562 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000563 }
564 if (file != -1)
565 {
566 SetStringInfoLength(chaos,MaxEntropyExtent);
567 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
568 (void) close(file);
569 SetStringInfoLength(chaos,(size_t) count);
570 ConcatenateStringInfo(entropy,chaos);
571 }
572 }
573 }
574#endif
575 chaos=DestroyStringInfo(chaos);
cristyf84a1932010-01-03 18:00:18 +0000576 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000577 return(entropy);
578}
579
580/*
581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582% %
583% %
584% %
585% G e t P s e u d o R a n d o m V a l u e %
586% %
587% %
588% %
589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590%
591% GetPseudoRandomValue() return a non-negative double-precision floating-point
592% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
593% 128th-1 period.
594%
595% The format of the GetPseudoRandomValue method is:
596%
597% double GetPseudoRandomValue(RandomInfo *randon_info)
598%
599% A description of each parameter follows:
600%
601% o random_info: the random info.
602%
603*/
604MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
605{
cristyebbcfea2011-02-25 02:43:54 +0000606 register unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000607 *seed;
608
cristyebbcfea2011-02-25 02:43:54 +0000609 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000610 alpha;
611
612 seed=random_info->seed;
613 do
614 {
cristyebbcfea2011-02-25 02:43:54 +0000615 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
cristy3ed852e2009-09-05 21:47:34 +0000616 seed[1]=seed[2];
617 seed[2]=seed[3];
618 seed[3]=seed[0];
619 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
620 } while (seed[0] == ~0UL);
621 return(random_info->normalize*seed[0]);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
629% G e t R a n d o m K e y %
630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634%
635% GetRandomKey() gets a random key from the reservoir.
636%
637% The format of the GetRandomKey method is:
638%
639% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
640%
641% A description of each parameter follows:
642%
643% o random_info: the random info.
644%
645% o length: the key length.
646%
647*/
648MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
649 const size_t length)
650{
651 StringInfo
652 *key;
653
654 assert(random_info != (RandomInfo *) NULL);
655 key=AcquireStringInfo(length);
656 SetRandomKey(random_info,length,GetStringInfoDatum(key));
657 return(key);
658}
659
660/*
661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662% %
663% %
664% %
cristye7452652012-04-14 01:34:21 +0000665% G e t R a n d o m S e c r e t K e y %
666% %
667% %
668% %
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670%
671% GetRandomSecretKey() returns the random secet key.
672%
673% The format of the GetRandomSecretKey method is:
674%
675% unsigned long GetRandomSecretKey(const RandomInfo *random_info)
676%
677% A description of each parameter follows:
678%
679% o random_info: the random info.
680*/
681MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info)
682{
683 return(random_info->secret_key);
684}
685
686/*
687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688% %
689% %
690% %
cristy3ed852e2009-09-05 21:47:34 +0000691% G e t R a n d o m V a l u e %
692% %
693% %
694% %
695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696%
697% GetRandomValue() return a non-negative double-precision floating-point
698% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
699% 128th-1 period (not cryptographically strong).
700%
701% The format of the GetRandomValue method is:
702%
703% double GetRandomValue(void)
704%
705*/
706MagickExport double GetRandomValue(RandomInfo *random_info)
707{
cristy29405832011-02-26 22:07:13 +0000708 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000709 key,
710 range;
711
712 range=(~0UL);
713 do
714 {
715 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
716 } while (key == range);
717 return((double) key/range);
718}
719
720/*
721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722% %
723% %
724% %
cristy18b17442009-10-25 18:36:48 +0000725+ R a n d o m C o m p o n e n t G e n e s i s %
cristy41c3c772009-10-19 02:17:37 +0000726% %
727% %
728% %
729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730%
cristyf34a1452009-10-24 22:29:27 +0000731% RandomComponentGenesis() instantiates the random component.
cristy41c3c772009-10-19 02:17:37 +0000732%
cristyf34a1452009-10-24 22:29:27 +0000733% The format of the RandomComponentGenesis method is:
cristy41c3c772009-10-19 02:17:37 +0000734%
cristyf34a1452009-10-24 22:29:27 +0000735% MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000736%
737*/
cristy5ff4eaf2011-09-03 01:38:02 +0000738MagickPrivate MagickBooleanType RandomComponentGenesis(void)
cristy41c3c772009-10-19 02:17:37 +0000739{
cristy165b6092009-10-26 13:52:10 +0000740 AcquireSemaphoreInfo(&random_semaphore);
cristy41c3c772009-10-19 02:17:37 +0000741 return(MagickTrue);
742}
743
744/*
745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746% %
747% %
748% %
cristyf34a1452009-10-24 22:29:27 +0000749+ R a n d o m C o m p o n e n t T e r m i n u s %
750% %
751% %
752% %
753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754%
755% RandomComponentTerminus() destroys the random component.
756%
757% The format of the RandomComponentTerminus method is:
758%
759% RandomComponentTerminus(void)
760%
761*/
cristy5ff4eaf2011-09-03 01:38:02 +0000762MagickPrivate void RandomComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000763{
cristy18b17442009-10-25 18:36:48 +0000764 if (random_semaphore == (SemaphoreInfo *) NULL)
765 AcquireSemaphoreInfo(&random_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000766 DestroySemaphoreInfo(&random_semaphore);
767}
768
769/*
770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771% %
772% %
773% %
cristy3ed852e2009-09-05 21:47:34 +0000774% S e t R a n d o m K e y %
775% %
776% %
777% %
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779%
780% SetRandomKey() sets a random key from the reservoir.
781%
782% The format of the SetRandomKey method is:
783%
784% void SetRandomKey(RandomInfo *random_info,const size_t length,
785% unsigned char *key)
786%
787% A description of each parameter follows:
788%
789% o random_info: the random info.
790%
791% o length: the key length.
792%
793% o key: the key.
794%
795*/
796
797static inline void IncrementRandomNonce(StringInfo *nonce)
798{
cristybb503372010-05-27 20:51:26 +0000799 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000800 i;
801
802 unsigned char
803 *datum;
804
805 datum=GetStringInfoDatum(nonce);
cristybb503372010-05-27 20:51:26 +0000806 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
cristy3ed852e2009-09-05 21:47:34 +0000807 {
808 datum[i]++;
809 if (datum[i] != 0)
810 return;
811 }
812 ThrowFatalException(RandomFatalError,"SequenceWrapError");
813}
814
815MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
816 unsigned char *key)
817{
818 register size_t
819 i;
820
821 register unsigned char
822 *p;
823
824 SignatureInfo
825 *signature_info;
826
827 unsigned char
828 *datum;
829
830 assert(random_info != (RandomInfo *) NULL);
831 if (length == 0)
832 return;
cristyf84a1932010-01-03 18:00:18 +0000833 LockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000834 signature_info=random_info->signature_info;
835 datum=GetStringInfoDatum(random_info->reservoir);
836 i=length;
837 for (p=key; (i != 0) && (random_info->i != 0); i--)
838 {
839 *p++=datum[random_info->i];
840 random_info->i++;
841 if (random_info->i == GetSignatureDigestsize(signature_info))
842 random_info->i=0;
843 }
844 while (i >= GetSignatureDigestsize(signature_info))
845 {
846 InitializeSignature(signature_info);
847 UpdateSignature(signature_info,random_info->nonce);
848 FinalizeSignature(signature_info);
849 IncrementRandomNonce(random_info->nonce);
850 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
851 signature_info)),GetSignatureDigestsize(signature_info));
852 p+=GetSignatureDigestsize(signature_info);
853 i-=GetSignatureDigestsize(signature_info);
854 }
855 if (i != 0)
856 {
857 InitializeSignature(signature_info);
858 UpdateSignature(signature_info,random_info->nonce);
859 FinalizeSignature(signature_info);
860 IncrementRandomNonce(random_info->nonce);
861 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
862 random_info->i=i;
863 datum=GetStringInfoDatum(random_info->reservoir);
864 while (i-- != 0)
865 p[i]=datum[i];
866 }
cristyf84a1932010-01-03 18:00:18 +0000867 UnlockSemaphoreInfo(random_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000868}
869
870/*
871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872% %
873% %
874% %
cristybaf31e92012-04-14 01:44:01 +0000875% S e t R a n d o m S e c r e t K e y %
876% %
877% %
878% %
879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880%
881% SetRandomSecretKey() sets the pseudo-random number generator secret key.
882%
883% The format of the SetRandomSecretKey method is:
884%
885% void SetRandomSecretKey(const unsigned long key)
886%
887% A description of each parameter follows:
888%
cristy4122eeb2012-04-14 01:48:43 +0000889% o key: the secret seed.
cristybaf31e92012-04-14 01:44:01 +0000890%
891*/
892MagickExport void SetRandomSecretKey(const unsigned long key)
893{
894 secret_key=key;
895}
896
897/*
898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899% %
900% %
901% %
cristy3ed852e2009-09-05 21:47:34 +0000902% S e t R a n d o m T r u e R a n d o m %
903% %
904% %
905% %
906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907%
908% SetRandomTrueRandom() declares your intentions to use true random numbers.
909% True random numbers are encouraged but may not always be practical because
910% your application may block while entropy is gathered from your environment.
911%
912% The format of the SetRandomTrueRandom method is:
913%
914% void SetRandomTrueRandom(const MagickBooleanType true_random)
915%
916% A description of each parameter follows:
917%
918% o true_random: declare your intentions to use true-random number.
919%
920*/
921MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
922{
923 gather_true_random=true_random;
924}
cristye85d0f72013-11-27 02:25:43 +0000925
926MagickPrivate unsigned long *GetRandomInfoSeed(RandomInfo *random_info)
927{
928 assert(random_info != (RandomInfo *) NULL);
929 return random_info->seed;
930}
931
932MagickPrivate double GetRandomInfoNormalize(RandomInfo *random_info)
933{
934 assert(random_info != (RandomInfo *) NULL);
935 return random_info->normalize;
936}