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