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-2016 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=MagickCoreSignature; 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 == MagickCoreSignature); 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=(~MagickCoreSignature); 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#if defined(MAGICKCORE_HAVE_FCHMOD) 468 (void) fchmod(file,0600); 469#endif 470#if defined(__OS2__) 471 setmode(file,O_BINARY); 472#endif 473 (void) close(file); 474 } 475 (void) remove_utf8(path); 476 SetStringInfoLength(chaos,strlen(path)); 477 SetStringInfoDatum(chaos,(unsigned char *) path); 478 ConcatenateStringInfo(entropy,chaos); 479 } 480#endif 481#if defined(MAGICKCORE_WINDOWS_SUPPORT) 482 { 483 double 484 seconds; 485 486 LARGE_INTEGER 487 nanoseconds; 488 489 MagickBooleanType 490 status; 491 492 /* 493 Not crytographically strong but better than nothing. 494 */ 495 seconds=NTElapsedTime()+NTUserTime(); 496 SetStringInfoLength(chaos,sizeof(seconds)); 497 SetStringInfoDatum(chaos,(unsigned char *) &seconds); 498 ConcatenateStringInfo(entropy,chaos); 499 if (QueryPerformanceCounter(&nanoseconds) != 0) 500 { 501 SetStringInfoLength(chaos,sizeof(nanoseconds)); 502 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds); 503 ConcatenateStringInfo(entropy,chaos); 504 } 505 /* 506 Our best hope for true entropy. 507 */ 508 SetStringInfoLength(chaos,MaxEntropyExtent); 509 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos)); 510 (void) status; 511 ConcatenateStringInfo(entropy,chaos); 512 } 513#else 514 { 515 char 516 *filename; 517 518 int 519 file; 520 521 ssize_t 522 count; 523 524 StringInfo 525 *device; 526 527 /* 528 Not crytographically strong but better than nothing. 529 */ 530 if (environ != (char **) NULL) 531 { 532 register ssize_t 533 i; 534 535 /* 536 Squeeze some entropy from the sometimes unpredicatble environment. 537 */ 538 for (i=0; environ[i] != (char *) NULL; i++) 539 { 540 SetStringInfoLength(chaos,strlen(environ[i])); 541 SetStringInfoDatum(chaos,(unsigned char *) environ[i]); 542 ConcatenateStringInfo(entropy,chaos); 543 } 544 } 545 filename=AcquireString("/dev/urandom"); 546 device=StringToStringInfo(filename); 547 device=DestroyStringInfo(device); 548 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 549 filename=DestroyString(filename); 550 if (file != -1) 551 { 552 SetStringInfoLength(chaos,MaxEntropyExtent); 553 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent); 554 (void) close(file); 555 SetStringInfoLength(chaos,(size_t) count); 556 ConcatenateStringInfo(entropy,chaos); 557 } 558 if (gather_true_random != MagickFalse) 559 { 560 /* 561 Our best hope for true entropy. 562 */ 563 filename=AcquireString("/dev/random"); 564 device=StringToStringInfo(filename); 565 device=DestroyStringInfo(device); 566 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 567 filename=DestroyString(filename); 568 if (file == -1) 569 { 570 filename=AcquireString("/dev/srandom"); 571 device=StringToStringInfo(filename); 572 device=DestroyStringInfo(device); 573 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 574 } 575 if (file != -1) 576 { 577 SetStringInfoLength(chaos,MaxEntropyExtent); 578 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent); 579 (void) close(file); 580 SetStringInfoLength(chaos,(size_t) count); 581 ConcatenateStringInfo(entropy,chaos); 582 } 583 } 584 } 585#endif 586 chaos=DestroyStringInfo(chaos); 587 UnlockSemaphoreInfo(random_info->semaphore); 588 return(entropy); 589} 590 591/* 592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 593% % 594% % 595% % 596% G e t P s e u d o R a n d o m V a l u e % 597% % 598% % 599% % 600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 601% 602% GetPseudoRandomValue() return a non-negative double-precision floating-point 603% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the 604% 128th-1 period. 605% 606% The format of the GetPseudoRandomValue method is: 607% 608% double GetPseudoRandomValue(RandomInfo *randon_info) 609% 610% A description of each parameter follows: 611% 612% o random_info: the random info. 613% 614*/ 615MagickExport double GetPseudoRandomValue(RandomInfo *random_info) 616{ 617 register unsigned long 618 *seed; 619 620 unsigned long 621 alpha; 622 623 seed=random_info->seed; 624 do 625 { 626 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11)); 627 seed[1]=seed[2]; 628 seed[2]=seed[3]; 629 seed[3]=seed[0]; 630 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8)); 631 } while (seed[0] == ~0UL); 632 return(random_info->normalize*seed[0]); 633} 634 635/* 636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 637% % 638% % 639% % 640+ G e t R a n d o m I n f o N o r m a l i z e % 641% % 642% % 643% % 644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 645% 646% GetRandomInfoNormalize() returns the random normalize value. 647% 648% The format of the GetRandomInfoNormalize method is: 649% 650% double GetRandomInfoNormalize(const RandomInfo *random_info) 651% 652% A description of each parameter follows: 653% 654% o random_info: the random info. 655% 656*/ 657MagickPrivate double GetRandomInfoNormalize(const RandomInfo *random_info) 658{ 659 assert(random_info != (const RandomInfo *) NULL); 660 return(random_info->normalize); 661} 662 663/* 664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 665% % 666% % 667% % 668+ G e t R a n d o m I n f o S e e d % 669% % 670% % 671% % 672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 673% 674% GetRandomInfoSeed() returns the random seed. 675% 676% The format of the GetRandomInfoSeed method is: 677% 678% unsigned long *GetRandomInfoSeed(RandomInfo *random_info) 679% 680% A description of each parameter follows: 681% 682% o random_info: the random info. 683% 684*/ 685MagickPrivate unsigned long *GetRandomInfoSeed(RandomInfo *random_info) 686{ 687 assert(random_info != (RandomInfo *) NULL); 688 return(random_info->seed); 689} 690 691/* 692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 693% % 694% % 695% % 696% G e t R a n d o m K e y % 697% % 698% % 699% % 700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 701% 702% GetRandomKey() gets a random key from the reservoir. 703% 704% The format of the GetRandomKey method is: 705% 706% StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length) 707% 708% A description of each parameter follows: 709% 710% o random_info: the random info. 711% 712% o length: the key length. 713% 714*/ 715MagickExport StringInfo *GetRandomKey(RandomInfo *random_info, 716 const size_t length) 717{ 718 StringInfo 719 *key; 720 721 assert(random_info != (RandomInfo *) NULL); 722 key=AcquireStringInfo(length); 723 SetRandomKey(random_info,length,GetStringInfoDatum(key)); 724 return(key); 725} 726 727/* 728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 729% % 730% % 731% % 732% G e t R a n d o m S e c r e t K e y % 733% % 734% % 735% % 736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 737% 738% GetRandomSecretKey() returns the random secet key. 739% 740% The format of the GetRandomSecretKey method is: 741% 742% unsigned long GetRandomSecretKey(const RandomInfo *random_info) 743% 744% A description of each parameter follows: 745% 746% o random_info: the random info. 747*/ 748MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info) 749{ 750 return(random_info->secret_key); 751} 752 753/* 754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 755% % 756% % 757% % 758% G e t R a n d o m V a l u e % 759% % 760% % 761% % 762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 763% 764% GetRandomValue() return a non-negative double-precision floating-point 765% value uniformly distributed over the interval [0.0, 1.0) with a 2 to the 766% 128th-1 period (not cryptographically strong). 767% 768% The format of the GetRandomValue method is: 769% 770% double GetRandomValue(void) 771% 772*/ 773MagickExport double GetRandomValue(RandomInfo *random_info) 774{ 775 unsigned long 776 key, 777 range; 778 779 range=(~0UL); 780 do 781 { 782 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key); 783 } while (key == range); 784 return((double) key/range); 785} 786 787/* 788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 789% % 790% % 791% % 792+ R a n d o m C o m p o n e n t G e n e s i s % 793% % 794% % 795% % 796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 797% 798% RandomComponentGenesis() instantiates the random component. 799% 800% The format of the RandomComponentGenesis method is: 801% 802% MagickBooleanType RandomComponentGenesis(void) 803% 804*/ 805MagickPrivate MagickBooleanType RandomComponentGenesis(void) 806{ 807 if (random_semaphore == (SemaphoreInfo *) NULL) 808 random_semaphore=AcquireSemaphoreInfo(); 809 return(MagickTrue); 810} 811 812/* 813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 814% % 815% % 816% % 817+ R a n d o m C o m p o n e n t T e r m i n u s % 818% % 819% % 820% % 821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 822% 823% RandomComponentTerminus() destroys the random component. 824% 825% The format of the RandomComponentTerminus method is: 826% 827% RandomComponentTerminus(void) 828% 829*/ 830MagickPrivate void RandomComponentTerminus(void) 831{ 832 if (random_semaphore == (SemaphoreInfo *) NULL) 833 ActivateSemaphoreInfo(&random_semaphore); 834 RelinquishSemaphoreInfo(&random_semaphore); 835} 836 837/* 838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 839% % 840% % 841% % 842% S e t R a n d o m K e y % 843% % 844% % 845% % 846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 847% 848% SetRandomKey() sets a random key from the reservoir. 849% 850% The format of the SetRandomKey method is: 851% 852% void SetRandomKey(RandomInfo *random_info,const size_t length, 853% unsigned char *key) 854% 855% A description of each parameter follows: 856% 857% o random_info: the random info. 858% 859% o length: the key length. 860% 861% o key: the key. 862% 863*/ 864 865static inline void IncrementRandomNonce(StringInfo *nonce) 866{ 867 register ssize_t 868 i; 869 870 unsigned char 871 *datum; 872 873 datum=GetStringInfoDatum(nonce); 874 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--) 875 { 876 datum[i]++; 877 if (datum[i] != 0) 878 return; 879 } 880 ThrowFatalException(RandomFatalError,"SequenceWrapError"); 881} 882 883MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length, 884 unsigned char *key) 885{ 886 register size_t 887 i; 888 889 register unsigned char 890 *p; 891 892 SignatureInfo 893 *signature_info; 894 895 unsigned char 896 *datum; 897 898 assert(random_info != (RandomInfo *) NULL); 899 if (length == 0) 900 return; 901 LockSemaphoreInfo(random_info->semaphore); 902 signature_info=random_info->signature_info; 903 datum=GetStringInfoDatum(random_info->reservoir); 904 i=length; 905 for (p=key; (i != 0) && (random_info->i != 0); i--) 906 { 907 *p++=datum[random_info->i]; 908 random_info->i++; 909 if (random_info->i == GetSignatureDigestsize(signature_info)) 910 random_info->i=0; 911 } 912 while (i >= GetSignatureDigestsize(signature_info)) 913 { 914 InitializeSignature(signature_info); 915 UpdateSignature(signature_info,random_info->nonce); 916 FinalizeSignature(signature_info); 917 IncrementRandomNonce(random_info->nonce); 918 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest( 919 signature_info)),GetSignatureDigestsize(signature_info)); 920 p+=GetSignatureDigestsize(signature_info); 921 i-=GetSignatureDigestsize(signature_info); 922 } 923 if (i != 0) 924 { 925 InitializeSignature(signature_info); 926 UpdateSignature(signature_info,random_info->nonce); 927 FinalizeSignature(signature_info); 928 IncrementRandomNonce(random_info->nonce); 929 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info)); 930 random_info->i=i; 931 datum=GetStringInfoDatum(random_info->reservoir); 932 while (i-- != 0) 933 p[i]=datum[i]; 934 } 935 UnlockSemaphoreInfo(random_info->semaphore); 936} 937 938/* 939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 940% % 941% % 942% % 943% S e t R a n d o m S e c r e t K e y % 944% % 945% % 946% % 947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 948% 949% SetRandomSecretKey() sets the pseudo-random number generator secret key. 950% 951% The format of the SetRandomSecretKey method is: 952% 953% void SetRandomSecretKey(const unsigned long key) 954% 955% A description of each parameter follows: 956% 957% o key: the secret seed. 958% 959*/ 960MagickExport void SetRandomSecretKey(const unsigned long key) 961{ 962 secret_key=key; 963} 964 965/* 966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 967% % 968% % 969% % 970% S e t R a n d o m T r u e R a n d o m % 971% % 972% % 973% % 974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 975% 976% SetRandomTrueRandom() declares your intentions to use true random numbers. 977% True random numbers are encouraged but may not always be practical because 978% your application may block while entropy is gathered from your environment. 979% 980% The format of the SetRandomTrueRandom method is: 981% 982% void SetRandomTrueRandom(const MagickBooleanType true_random) 983% 984% A description of each parameter follows: 985% 986% o true_random: declare your intentions to use true-random number. 987% 988*/ 989MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random) 990{ 991 gather_true_random=true_random; 992} 993