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