00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #if defined(__VMS)
00045 #include <time.h>
00046 #endif
00047 #if defined(__MINGW32__)
00048 #include <sys/time.h>
00049 #endif
00050 #include "magick/studio.h"
00051 #include "magick/exception.h"
00052 #include "magick/exception-private.h"
00053 #include "magick/memory_.h"
00054 #include "magick/semaphore.h"
00055 #include "magick/random_.h"
00056 #include "magick/resource_.h"
00057 #include "magick/signature-private.h"
00058 #include "magick/string_.h"
00059 #include "magick/thread_.h"
00060 #include "magick/thread-private.h"
00061 #include "magick/utility.h"
00062
00063
00064
00065 #define PseudoRandomHash SHA256Hash
00066 #define RandomEntropyLevel 9
00067 #define RandomFilename "reservoir.xdm"
00068 #define RandomFiletype "random"
00069 #define RandomProtocolMajorVersion 1
00070 #define RandomProtocolMinorVersion 0
00071
00072
00073
00074
00075 struct _RandomInfo
00076 {
00077 SignatureInfo
00078 *signature_info;
00079
00080 StringInfo
00081 *nonce,
00082 *reservoir;
00083
00084 size_t
00085 i;
00086
00087 unsigned long
00088 seed[4];
00089
00090 double
00091 normalize;
00092
00093 unsigned short
00094 protocol_major,
00095 protocol_minor;
00096
00097 SemaphoreInfo
00098 *semaphore;
00099
00100 long
00101 timestamp;
00102
00103 unsigned long
00104 signature;
00105 };
00106
00107
00108
00109
00110 #if defined(__APPLE__)
00111 #include <crt_externs.h>
00112 #define environ (*_NSGetEnviron())
00113 #endif
00114
00115 extern char
00116 **environ;
00117
00118
00119
00120
00121 static SemaphoreInfo
00122 *random_semaphore = (SemaphoreInfo *) NULL;
00123
00124 static unsigned long
00125 random_seed = ~0UL;
00126
00127 static MagickBooleanType
00128 gather_true_random = MagickFalse;
00129
00130
00131
00132
00133 static StringInfo
00134 *GenerateEntropicChaos(RandomInfo *);
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 static inline size_t MagickMin(const size_t x,const size_t y)
00156 {
00157 if (x < y)
00158 return(x);
00159 return(y);
00160 }
00161
00162 MagickExport RandomInfo *AcquireRandomInfo(void)
00163 {
00164 const StringInfo
00165 *digest;
00166
00167 RandomInfo
00168 *random_info;
00169
00170 StringInfo
00171 *entropy,
00172 *key,
00173 *nonce;
00174
00175 random_info=(RandomInfo *) AcquireAlignedMemory(1,sizeof(*random_info));
00176 if (random_info == (RandomInfo *) NULL)
00177 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00178 (void) ResetMagickMemory(random_info,0,sizeof(*random_info));
00179 random_info->signature_info=AcquireSignatureInfo();
00180 random_info->nonce=AcquireStringInfo(2*GetSignatureDigestsize(
00181 random_info->signature_info));
00182 ResetStringInfo(random_info->nonce);
00183 random_info->reservoir=AcquireStringInfo(GetSignatureDigestsize(
00184 random_info->signature_info));
00185 ResetStringInfo(random_info->reservoir);
00186 random_info->normalize=1.0/(~0UL);
00187 random_info->semaphore=AllocateSemaphoreInfo();
00188 random_info->protocol_major=RandomProtocolMajorVersion;
00189 random_info->protocol_minor=RandomProtocolMinorVersion;
00190 random_info->timestamp=(long) time(0);
00191 random_info->signature=MagickSignature;
00192
00193
00194
00195 nonce=GenerateEntropicChaos(random_info);
00196 if (nonce == (StringInfo *) NULL)
00197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00198 InitializeSignature(random_info->signature_info);
00199 UpdateSignature(random_info->signature_info,nonce);
00200 FinalizeSignature(random_info->signature_info);
00201 SetStringInfoLength(nonce,(GetSignatureDigestsize(
00202 random_info->signature_info)+1)/2);
00203 SetStringInfo(nonce,GetSignatureDigest(random_info->signature_info));
00204 SetStringInfo(random_info->nonce,nonce);
00205 nonce=DestroyStringInfo(nonce);
00206
00207
00208
00209 entropy=GenerateEntropicChaos(random_info);
00210 if (entropy == (StringInfo *) NULL)
00211 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00212 UpdateSignature(random_info->signature_info,entropy);
00213 FinalizeSignature(random_info->signature_info);
00214 SetStringInfo(random_info->reservoir,GetSignatureDigest(
00215 random_info->signature_info));
00216 entropy=DestroyStringInfo(entropy);
00217
00218
00219
00220 if (random_seed == ~0UL)
00221 {
00222 key=GetRandomKey(random_info,sizeof(random_seed));
00223 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(key),
00224 GetStringInfoLength(key));
00225 key=DestroyStringInfo(key);
00226 }
00227 else
00228 {
00229 SignatureInfo
00230 *signature_info;
00231
00232 signature_info=AcquireSignatureInfo();
00233 key=AcquireStringInfo(sizeof(random_seed));
00234 SetStringInfoDatum(key,(unsigned char *) &random_seed);
00235 UpdateSignature(signature_info,key);
00236 key=DestroyStringInfo(key);
00237 FinalizeSignature(signature_info);
00238 digest=GetSignatureDigest(signature_info);
00239 (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(digest),
00240 MagickMin(GetSignatureDigestsize(signature_info),
00241 sizeof(*random_info->seed)));
00242 signature_info=DestroySignatureInfo(signature_info);
00243 }
00244 random_info->seed[1]=0x50a7f451UL;
00245 random_info->seed[2]=0x5365417eUL;
00246 random_info->seed[3]=0xc3a4171aUL;
00247 return(random_info);
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
00274 {
00275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00276 assert(random_info != (RandomInfo *) NULL);
00277 assert(random_info->signature == MagickSignature);
00278 (void) LockSemaphoreInfo(random_info->semaphore);
00279 if (random_info->reservoir != (StringInfo *) NULL)
00280 random_info->reservoir=DestroyStringInfo(random_info->reservoir);
00281 if (random_info->nonce != (StringInfo *) NULL)
00282 random_info->nonce=DestroyStringInfo(random_info->nonce);
00283 if (random_info->signature_info != (SignatureInfo *) NULL)
00284 random_info->signature_info=DestroySignatureInfo(
00285 random_info->signature_info);
00286 (void) ResetMagickMemory(random_info->seed,0,sizeof(*random_info->seed));
00287 random_info->signature=(~MagickSignature);
00288 (void) UnlockSemaphoreInfo(random_info->semaphore);
00289 DestroySemaphoreInfo(&random_info->semaphore);
00290 random_info=(RandomInfo *) RelinquishAlignedMemory(random_info);
00291 return(random_info);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 #if !defined(__WINDOWS__)
00319 static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
00320 {
00321 register unsigned char
00322 *q;
00323
00324 ssize_t
00325 offset,
00326 count;
00327
00328 offset=0;
00329 for (q=source; length != 0; length-=count)
00330 {
00331 count=(ssize_t) read(file,q,length);
00332 if (count <= 0)
00333 {
00334 count=0;
00335 if (errno == EINTR)
00336 continue;
00337 return(-1);
00338 }
00339 q+=count;
00340 offset+=count;
00341 }
00342 return(offset);
00343 }
00344 #endif
00345
00346 static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
00347 {
00348 #define MaxEntropyExtent 64
00349
00350 long
00351 pid;
00352
00353 MagickThreadType
00354 tid;
00355
00356 StringInfo
00357 *chaos,
00358 *entropy;
00359
00360 unsigned long
00361 nanoseconds,
00362 seconds;
00363
00364
00365
00366
00367 entropy=AcquireStringInfo(0);
00368 (void) LockSemaphoreInfo(random_info->semaphore);
00369 chaos=AcquireStringInfo(sizeof(unsigned char *));
00370 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
00371 ConcatenateStringInfo(entropy,chaos);
00372 SetStringInfoDatum(chaos,(unsigned char *) entropy);
00373 ConcatenateStringInfo(entropy,chaos);
00374 pid=(long) getpid();
00375 SetStringInfoLength(chaos,sizeof(pid));
00376 SetStringInfoDatum(chaos,(unsigned char *) &pid);
00377 ConcatenateStringInfo(entropy,chaos);
00378 tid=GetMagickThreadId();
00379 SetStringInfoLength(chaos,sizeof(tid));
00380 SetStringInfoDatum(chaos,(unsigned char *) &tid);
00381 ConcatenateStringInfo(entropy,chaos);
00382 #if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
00383 {
00384 struct rusage
00385 usage;
00386
00387 if (getrusage(RUSAGE_SELF,&usage) == 0)
00388 {
00389 SetStringInfoLength(chaos,sizeof(usage));
00390 SetStringInfoDatum(chaos,(unsigned char *) &usage);
00391 }
00392 }
00393 #endif
00394 seconds=time((time_t *) 0);
00395 nanoseconds=0;
00396 #if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
00397 {
00398 struct timeval
00399 timer;
00400
00401 if (gettimeofday(&timer,0) == 0)
00402 {
00403 seconds=timer.tv_sec;
00404 nanoseconds=1000UL*timer.tv_usec;
00405 }
00406 }
00407 #endif
00408 #if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
00409 {
00410 struct timespec
00411 timer;
00412
00413 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
00414 {
00415 seconds=timer.tv_sec;
00416 nanoseconds=timer.tv_nsec;
00417 }
00418 }
00419 #endif
00420 SetStringInfoLength(chaos,sizeof(seconds));
00421 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
00422 ConcatenateStringInfo(entropy,chaos);
00423 SetStringInfoLength(chaos,sizeof(nanoseconds));
00424 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00425 ConcatenateStringInfo(entropy,chaos);
00426 nanoseconds=0;
00427 #if defined(MAGICKCORE_HAVE_CLOCK)
00428 nanoseconds=clock();
00429 #endif
00430 #if defined(MAGICKCORE_HAVE_TIMES)
00431 {
00432 struct tms
00433 timer;
00434
00435 (void) times(&timer);
00436 nanoseconds=timer.tms_utime+timer.tms_stime;
00437 }
00438 #endif
00439 SetStringInfoLength(chaos,sizeof(nanoseconds));
00440 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00441 ConcatenateStringInfo(entropy,chaos);
00442 #if defined(MAGICKCORE_HAVE_MKSTEMP)
00443 {
00444 char
00445 *filename;
00446
00447 int
00448 file;
00449
00450 filename=ConstantString("magickXXXXXX");
00451 file=mkstemp(filename);
00452 #if defined(__OS2__)
00453 setmode(file,O_BINARY);
00454 #endif
00455 if (file != -1)
00456 (void) close(file);
00457 (void) remove(filename);
00458 SetStringInfoLength(chaos,strlen(filename));
00459 SetStringInfoDatum(chaos,(unsigned char *) filename);
00460 ConcatenateStringInfo(entropy,chaos);
00461 filename=DestroyString(filename);
00462 }
00463 #endif
00464 #if defined(__WINDOWS__)
00465 {
00466 double
00467 seconds;
00468
00469 LARGE_INTEGER
00470 nanoseconds;
00471
00472 MagickBooleanType
00473 status;
00474
00475
00476
00477
00478 seconds=NTElapsedTime()+NTUserTime();
00479 SetStringInfoLength(chaos,sizeof(seconds));
00480 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
00481 ConcatenateStringInfo(entropy,chaos);
00482 if (QueryPerformanceCounter(&nanoseconds) != 0)
00483 {
00484 SetStringInfoLength(chaos,sizeof(nanoseconds));
00485 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00486 ConcatenateStringInfo(entropy,chaos);
00487 }
00488
00489
00490
00491 SetStringInfoLength(chaos,MaxEntropyExtent);
00492 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
00493 ConcatenateStringInfo(entropy,chaos);
00494 }
00495 #else
00496 {
00497 char
00498 *filename;
00499
00500 int
00501 file;
00502
00503 ssize_t
00504 count;
00505
00506 StringInfo
00507 *device;
00508
00509
00510
00511
00512 if (environ != (char **) NULL)
00513 {
00514 register long
00515 i;
00516
00517
00518
00519
00520 for (i=0; environ[i] != (char *) NULL; i++)
00521 {
00522 SetStringInfoLength(chaos,strlen(environ[i]));
00523 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
00524 ConcatenateStringInfo(entropy,chaos);
00525 }
00526 }
00527 filename=AcquireString("/dev/urandom");
00528 device=StringToStringInfo(filename);
00529 device=DestroyStringInfo(device);
00530 file=open(filename,O_RDONLY | O_BINARY);
00531 filename=DestroyString(filename);
00532 if (file != -1)
00533 {
00534 SetStringInfoLength(chaos,MaxEntropyExtent);
00535 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
00536 (void) close(file);
00537 SetStringInfoLength(chaos,(size_t) count);
00538 ConcatenateStringInfo(entropy,chaos);
00539 }
00540 if (gather_true_random != MagickFalse)
00541 {
00542
00543
00544
00545 filename=AcquireString("/dev/random");
00546 device=StringToStringInfo(filename);
00547 device=DestroyStringInfo(device);
00548 file=open(filename,O_RDONLY | O_BINARY);
00549 filename=DestroyString(filename);
00550 if (file == -1)
00551 {
00552 filename=AcquireString("/dev/srandom");
00553 device=StringToStringInfo(filename);
00554 device=DestroyStringInfo(device);
00555 file=open(filename,O_RDONLY | O_BINARY);
00556 }
00557 if (file != -1)
00558 {
00559 SetStringInfoLength(chaos,MaxEntropyExtent);
00560 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
00561 (void) close(file);
00562 SetStringInfoLength(chaos,(size_t) count);
00563 ConcatenateStringInfo(entropy,chaos);
00564 }
00565 }
00566 }
00567 #endif
00568 chaos=DestroyStringInfo(chaos);
00569 (void) UnlockSemaphoreInfo(random_info->semaphore);
00570 return(entropy);
00571 }
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
00598 {
00599 register unsigned long
00600 *seed;
00601
00602 unsigned long
00603 alpha;
00604
00605 seed=random_info->seed;
00606 do
00607 {
00608 alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
00609 seed[1]=seed[2];
00610 seed[2]=seed[3];
00611 seed[3]=seed[0];
00612 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
00613 } while (seed[0] == ~0UL);
00614 return(random_info->normalize*seed[0]);
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
00642 const size_t length)
00643 {
00644 StringInfo
00645 *key;
00646
00647 assert(random_info != (RandomInfo *) NULL);
00648 key=AcquireStringInfo(length);
00649 SetRandomKey(random_info,length,GetStringInfoDatum(key));
00650 return(key);
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 MagickExport double GetRandomValue(RandomInfo *random_info)
00674 {
00675 unsigned long
00676 key,
00677 range;
00678
00679 range=(~0UL);
00680 do
00681 {
00682 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
00683 } while (key == range);
00684 return((double) key/range);
00685 }
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 MagickExport MagickBooleanType RandomComponentGenesis(void)
00706 {
00707 AcquireSemaphoreInfo(&random_semaphore);
00708 return(MagickTrue);
00709 }
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 MagickExport void RandomComponentTerminus(void)
00730 {
00731 if (random_semaphore == (SemaphoreInfo *) NULL)
00732 AcquireSemaphoreInfo(&random_semaphore);
00733 DestroySemaphoreInfo(&random_semaphore);
00734 }
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 MagickExport void SeedPseudoRandomGenerator(const unsigned long seed)
00760 {
00761 random_seed=seed;
00762 }
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 static inline void IncrementRandomNonce(StringInfo *nonce)
00793 {
00794 register long
00795 i;
00796
00797 unsigned char
00798 *datum;
00799
00800 datum=GetStringInfoDatum(nonce);
00801 for (i=(long) (GetStringInfoLength(nonce)-1); i != 0; i--)
00802 {
00803 datum[i]++;
00804 if (datum[i] != 0)
00805 return;
00806 }
00807 ThrowFatalException(RandomFatalError,"SequenceWrapError");
00808 }
00809
00810 MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
00811 unsigned char *key)
00812 {
00813 register size_t
00814 i;
00815
00816 register unsigned char
00817 *p;
00818
00819 SignatureInfo
00820 *signature_info;
00821
00822 unsigned char
00823 *datum;
00824
00825 assert(random_info != (RandomInfo *) NULL);
00826 if (length == 0)
00827 return;
00828 (void) LockSemaphoreInfo(random_info->semaphore);
00829 signature_info=random_info->signature_info;
00830 datum=GetStringInfoDatum(random_info->reservoir);
00831 i=length;
00832 for (p=key; (i != 0) && (random_info->i != 0); i--)
00833 {
00834 *p++=datum[random_info->i];
00835 random_info->i++;
00836 if (random_info->i == GetSignatureDigestsize(signature_info))
00837 random_info->i=0;
00838 }
00839 while (i >= GetSignatureDigestsize(signature_info))
00840 {
00841 InitializeSignature(signature_info);
00842 UpdateSignature(signature_info,random_info->nonce);
00843 FinalizeSignature(signature_info);
00844 IncrementRandomNonce(random_info->nonce);
00845 (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
00846 signature_info)),GetSignatureDigestsize(signature_info));
00847 p+=GetSignatureDigestsize(signature_info);
00848 i-=GetSignatureDigestsize(signature_info);
00849 }
00850 if (i != 0)
00851 {
00852 InitializeSignature(signature_info);
00853 UpdateSignature(signature_info,random_info->nonce);
00854 FinalizeSignature(signature_info);
00855 IncrementRandomNonce(random_info->nonce);
00856 SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
00857 random_info->i=i;
00858 datum=GetStringInfoDatum(random_info->reservoir);
00859 while (i-- != 0)
00860 p[i]=datum[i];
00861 }
00862 (void) UnlockSemaphoreInfo(random_info->semaphore);
00863 }
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889 MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
00890 {
00891 gather_true_random=true_random;
00892 }