random.c revision 04b11db5504ecdf205114ae7e9e68774a1ff0b9b
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-2014 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/memory_.h" 54#include "MagickCore/semaphore.h" 55#include "MagickCore/random_.h" 56#include "MagickCore/random-private.h" 57#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" 63#include "MagickCore/utility-private.h" 64/* 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 89 unsigned long 90 seed[4]; 91 92 double 93 normalize; 94 95 unsigned long 96 secret_key; 97 98 unsigned short 99 protocol_major, 100 protocol_minor; 101 102 SemaphoreInfo 103 *semaphore; 104 105 ssize_t 106 timestamp; 107 108 size_t 109 signature; 110}; 111 112/* 113 External declarations. 114*/ 115#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) 116#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 129static unsigned long 130 secret_key = ~0UL; 131 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 180 random_info=(RandomInfo *) AcquireMagickMemory(sizeof(*random_info)); 181 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); 191 random_info->normalize=1.0/(~0UL); 192 random_info->secret_key=secret_key; 193 random_info->protocol_major=RandomProtocolMajorVersion; 194 random_info->protocol_minor=RandomProtocolMinorVersion; 195 random_info->semaphore=AcquireSemaphoreInfo(); 196 random_info->timestamp=(ssize_t) time(0); 197 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 */ 226 if (random_info->secret_key == ~0UL) 227 { 228 key=GetRandomKey(random_info,sizeof(random_info->secret_key)); 229 (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(); 239 key=AcquireStringInfo(sizeof(random_info->secret_key)); 240 SetStringInfoDatum(key,(unsigned char *) &random_info->secret_key); 241 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); 284 LockSemaphoreInfo(random_info->semaphore); 285 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); 294 UnlockSemaphoreInfo(random_info->semaphore); 295 RelinquishSemaphoreInfo(&random_info->semaphore); 296 random_info=(RandomInfo *) RelinquishMagickMemory(random_info); 297 return(random_info); 298} 299 300/* 301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302% % 303% % 304% % 305+ 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 324#if !defined(MAGICKCORE_WINDOWS_SUPPORT) 325static 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} 350#endif 351 352static StringInfo *GenerateEntropicChaos(RandomInfo *random_info) 353{ 354#define MaxEntropyExtent 64 355 356 MagickThreadType 357 tid; 358 359 StringInfo 360 *chaos, 361 *entropy; 362 363 size_t 364 nanoseconds, 365 seconds; 366 367 ssize_t 368 pid; 369 370 /* 371 Initialize random reservoir. 372 */ 373 entropy=AcquireStringInfo(0); 374 LockSemaphoreInfo(random_info->semaphore); 375 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); 380 pid=(ssize_t) getpid(); 381 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 407 if (gettimeofday(&timer,(struct timezone *) NULL) == 0) 408 { 409 seconds=timer.tv_sec; 410 nanoseconds=1000UL*timer.tv_usec; 411 } 412 } 413#endif 414#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR) 415 { 416 struct timespec 417 timer; 418 419 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0) 420 { 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); 463 (void) remove_utf8(filename); 464 SetStringInfoLength(chaos,strlen(filename)); 465 SetStringInfoDatum(chaos,(unsigned char *) filename); 466 ConcatenateStringInfo(entropy,chaos); 467 filename=DestroyString(filename); 468 } 469#endif 470#if defined(MAGICKCORE_WINDOWS_SUPPORT) 471 { 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)); 499 (void) status; 500 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 { 521 register ssize_t 522 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); 537 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 538 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); 555 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 556 filename=DestroyString(filename); 557 if (file == -1) 558 { 559 filename=AcquireString("/dev/srandom"); 560 device=StringToStringInfo(filename); 561 device=DestroyStringInfo(device); 562 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 563 } 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); 576 UnlockSemaphoreInfo(random_info->semaphore); 577 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{ 606 register unsigned long 607 *seed; 608 609 unsigned long 610 alpha; 611 612 seed=random_info->seed; 613 do 614 { 615 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11)); 616 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% % 665% 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% % 691% 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{ 708 unsigned long 709 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% % 725+ R a n d o m C o m p o n e n t G e n e s i s % 726% % 727% % 728% % 729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 730% 731% RandomComponentGenesis() instantiates the random component. 732% 733% The format of the RandomComponentGenesis method is: 734% 735% MagickBooleanType RandomComponentGenesis(void) 736% 737*/ 738MagickPrivate MagickBooleanType RandomComponentGenesis(void) 739{ 740 random_semaphore=AcquireSemaphoreInfo(); 741 return(MagickTrue); 742} 743 744/* 745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 746% % 747% % 748% % 749+ 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*/ 762MagickPrivate void RandomComponentTerminus(void) 763{ 764 if (random_semaphore == (SemaphoreInfo *) NULL) 765 ActivateSemaphoreInfo(&random_semaphore); 766 RelinquishSemaphoreInfo(&random_semaphore); 767} 768 769/* 770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 771% % 772% % 773% % 774% 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{ 799 register ssize_t 800 i; 801 802 unsigned char 803 *datum; 804 805 datum=GetStringInfoDatum(nonce); 806 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--) 807 { 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; 833 LockSemaphoreInfo(random_info->semaphore); 834 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 } 867 UnlockSemaphoreInfo(random_info->semaphore); 868} 869 870/* 871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 872% % 873% % 874% % 875% 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% 889% o key: the secret seed. 890% 891*/ 892MagickExport void SetRandomSecretKey(const unsigned long key) 893{ 894 secret_key=key; 895} 896 897/* 898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 899% % 900% % 901% % 902% 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} 925 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} 937