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