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