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 #if defined(__MINGW32__)
00043 #include <sys/time.h>
00044 #endif
00045 #include "wizard/studio.h"
00046 #include "wizard/entropy.h"
00047 #include "wizard/exception.h"
00048 #include "wizard/exception-private.h"
00049 #include "wizard/file.h"
00050 #include "wizard/hash.h"
00051 #include "wizard/magick.h"
00052 #include "wizard/memory_.h"
00053 #include "wizard/random_.h"
00054 #include "wizard/thread_.h"
00055 #include "wizard/thread-private.h"
00056 #include "wizard/semaphore.h"
00057
00058
00059
00060
00061 #define PseudoRandomHash SHA256Hash
00062 #define RandomEntropyLevel 9
00063 #define RandomFilename "reservoir.xdm"
00064 #define RandomFiletype "random"
00065 #define RandomProtocolMajorVersion 1
00066 #define RandomProtocolMinorVersion 1
00067
00068
00069
00070
00071 struct _RandomInfo
00072 {
00073 HMACInfo
00074 *hmac_info;
00075
00076 StringInfo
00077 *nonce,
00078 *reservoir;
00079
00080 size_t
00081 i;
00082
00083 size_t
00084 seed[4];
00085
00086 double
00087 normalize;
00088
00089 unsigned short
00090 protocol_major,
00091 protocol_minor;
00092
00093 SemaphoreInfo
00094 *semaphore;
00095
00096 time_t
00097 timestamp;
00098
00099 size_t
00100 signature;
00101 };
00102
00103
00104
00105
00106 #if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
00107 #include <crt_externs.h>
00108 #define environ (*_NSGetEnviron())
00109 #endif
00110
00111 extern char
00112 **environ;
00113
00114
00115
00116
00117 static SemaphoreInfo
00118 *random_semaphore = (SemaphoreInfo *) NULL;
00119
00120 static size_t
00121 random_seed = ~0UL;
00122
00123 static WizardBooleanType
00124 gather_true_random = WizardFalse;
00125
00126
00127
00128
00129 static WizardBooleanType
00130 SaveEntropyToReservoir(RandomInfo *,ExceptionInfo *);
00131
00132 static StringInfo
00133 *GenerateEntropicChaos(RandomInfo *,ExceptionInfo *),
00134 *GetEntropyFromReservoir(RandomInfo *,ExceptionInfo *);
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 static inline size_t WizardMin(const size_t x,const size_t y)
00160 {
00161 if (x < y)
00162 return(x);
00163 return(y);
00164 }
00165
00166 WizardExport RandomInfo *AcquireRandomInfo(const HashType hash)
00167 {
00168 ExceptionInfo
00169 *exception;
00170
00171 RandomInfo
00172 *random_info;
00173
00174 WizardBooleanType
00175 status;
00176
00177 StringInfo
00178 *entropy,
00179 *key,
00180 *nonce;
00181
00182 random_info=(RandomInfo *) AcquireAlignedMemory(1,sizeof(*random_info));
00183 if (random_info == (RandomInfo *) NULL)
00184 ThrowWizardFatalError(HashDomain,MemoryError);
00185 (void) ResetWizardMemory(random_info,0,sizeof(*random_info));
00186 random_info->hmac_info=AcquireHMACInfo(hash);
00187 random_info->nonce=AcquireStringInfo(2*GetHMACDigestsize(
00188 random_info->hmac_info));
00189 ResetStringInfo(random_info->nonce);
00190 random_info->reservoir=AcquireStringInfo(GetHMACDigestsize(
00191 random_info->hmac_info));
00192 ResetStringInfo(random_info->reservoir);
00193 random_info->normalize=1.0/(~0UL);
00194 random_info->semaphore=AllocateSemaphoreInfo();
00195 random_info->protocol_major=RandomProtocolMajorVersion;
00196 random_info->protocol_minor=RandomProtocolMinorVersion;
00197 random_info->timestamp=time(0);
00198 random_info->signature=WizardSignature;
00199
00200
00201
00202 exception=AcquireExceptionInfo();
00203 nonce=GenerateEntropicChaos(random_info,exception);
00204 if (nonce == (StringInfo *) NULL)
00205 ThrowFatalException(RandomFatalError,"Failed to initialize random "
00206 "reservoir `%s'");
00207 InitializeHMAC(random_info->hmac_info,nonce);
00208 SetStringInfoLength(nonce,(GetHMACDigestsize(random_info->hmac_info)+1)/2);
00209 SetStringInfo(nonce,GetHMACDigest(random_info->hmac_info));
00210 SetStringInfo(random_info->nonce,nonce);
00211 nonce=DestroyStringInfo(nonce);
00212
00213
00214
00215 entropy=GenerateEntropicChaos(random_info,exception);
00216 if (entropy == (StringInfo *) NULL)
00217 ThrowFatalException(RandomFatalError,"Failed to initialize random "
00218 "reservoir `%s'");
00219 InitializeHMAC(random_info->hmac_info,entropy);
00220 SetStringInfo(random_info->reservoir,GetHMACDigest(random_info->hmac_info));
00221 status=SaveEntropyToReservoir(random_info,exception);
00222 entropy=DestroyStringInfo(entropy);
00223 exception=DestroyExceptionInfo(exception);
00224
00225
00226
00227 if (random_seed == ~0UL)
00228 {
00229 key=GetRandomKey(random_info,sizeof(random_seed));
00230 (void) CopyWizardMemory(random_info->seed,GetStringInfoDatum(key),
00231 GetStringInfoLength(key));
00232 key=DestroyStringInfo(key);
00233 }
00234 else
00235 {
00236 const StringInfo
00237 *digest;
00238
00239 HashInfo
00240 *signature_info;
00241
00242 signature_info=AcquireHashInfo(PseudoRandomHash);
00243 key=AcquireStringInfo(sizeof(random_seed));
00244 SetStringInfoDatum(key,(unsigned char *) &random_seed);
00245 UpdateHash(signature_info,key);
00246 key=DestroyStringInfo(key);
00247 FinalizeHash(signature_info);
00248 digest=GetHashDigest(signature_info);
00249 (void) CopyWizardMemory(random_info->seed,GetStringInfoDatum(digest),
00250 WizardMin(GetHashDigestsize(signature_info),
00251 sizeof(*random_info->seed)));
00252 signature_info=DestroyHashInfo(signature_info);
00253 }
00254 random_info->seed[1]=0x50a7f451UL;
00255 random_info->seed[2]=0x5365417eUL;
00256 random_info->seed[3]=0xc3a4171aUL;
00257 return(random_info);
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 WizardExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
00284 {
00285 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00286 WizardAssert(CipherDomain,random_info != (RandomInfo *) NULL);
00287 WizardAssert(CipherDomain,random_info->signature == WizardSignature);
00288 LockSemaphoreInfo(random_info->semaphore);
00289 if (random_info->reservoir != (StringInfo *) NULL)
00290 random_info->reservoir=DestroyStringInfo(random_info->reservoir);
00291 if (random_info->nonce != (StringInfo *) NULL)
00292 random_info->nonce=DestroyStringInfo(random_info->nonce);
00293 if (random_info->hmac_info != (HMACInfo *) NULL)
00294 random_info->hmac_info=DestroyHMACInfo(random_info->hmac_info);
00295 (void) ResetWizardMemory(random_info->seed,0,sizeof(*random_info->seed));
00296 random_info->signature=(~WizardSignature);
00297 UnlockSemaphoreInfo(random_info->semaphore);
00298 DestroySemaphoreInfo(&random_info->semaphore);
00299 random_info=(RandomInfo *) RelinquishWizardMemory(random_info);
00300 return(random_info);
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
00331 {
00332 register unsigned char
00333 *q;
00334
00335 ssize_t
00336 offset,
00337 count;
00338
00339 offset=0;
00340 for (q=source; length != 0; length-=count)
00341 {
00342 count=(ssize_t) read(file,q,length);
00343 if (count <= 0)
00344 {
00345 count=0;
00346 if (errno == EINTR)
00347 continue;
00348 return(-1);
00349 }
00350 q+=count;
00351 offset+=count;
00352 }
00353 return(offset);
00354 }
00355
00356 static StringInfo *GenerateEntropicChaos(RandomInfo *random_info,
00357 ExceptionInfo *exception)
00358 {
00359 #define MaxEntropyExtent 64
00360
00361 ssize_t
00362 pid;
00363
00364 StringInfo
00365 *chaos,
00366 *entropy;
00367
00368 size_t
00369 nanoseconds,
00370 seconds;
00371
00372 WizardThreadType
00373 tid;
00374
00375
00376
00377
00378 entropy=GetEntropyFromReservoir(random_info,exception);
00379 if (entropy == (StringInfo *) NULL)
00380 entropy=AcquireStringInfo(0);
00381 LockSemaphoreInfo(random_info->semaphore);
00382 chaos=AcquireStringInfo(sizeof(unsigned char *));
00383 SetStringInfoDatum(chaos,(unsigned char *) &entropy);
00384 ConcatenateStringInfo(entropy,chaos);
00385 SetStringInfoDatum(chaos,(unsigned char *) entropy);
00386 ConcatenateStringInfo(entropy,chaos);
00387 pid=(ssize_t) getpid();
00388 SetStringInfoLength(chaos,sizeof(pid));
00389 SetStringInfoDatum(chaos,(unsigned char *) &pid);
00390 ConcatenateStringInfo(entropy,chaos);
00391 tid=GetWizardThreadId();
00392 SetStringInfoLength(chaos,sizeof(tid));
00393 SetStringInfoDatum(chaos,(unsigned char *) &tid);
00394 ConcatenateStringInfo(entropy,chaos);
00395 #if defined(WIZARDSTOOLKIT_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
00396 {
00397 struct rusage
00398 usage;
00399
00400 if (getrusage(RUSAGE_SELF,&usage) == 0)
00401 {
00402 SetStringInfoLength(chaos,sizeof(usage));
00403 SetStringInfoDatum(chaos,(unsigned char *) &usage);
00404 }
00405 }
00406 #endif
00407 seconds=time((time_t *) 0);
00408 nanoseconds=0;
00409 #if defined(WIZARDSTOOLKIT_HAVE_GETTIMEOFDAY)
00410 {
00411 struct timeval
00412 timer;
00413
00414 if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
00415 {
00416 seconds=timer.tv_sec;
00417 nanoseconds=1000UL*timer.tv_usec;
00418 }
00419 }
00420 #endif
00421 #if defined(WIZARDSTOOLKIT_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
00422 {
00423 struct timespec
00424 timer;
00425
00426 if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
00427 {
00428 seconds=timer.tv_sec;
00429 nanoseconds=timer.tv_nsec;
00430 }
00431 }
00432 #endif
00433 SetStringInfoLength(chaos,sizeof(seconds));
00434 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
00435 ConcatenateStringInfo(entropy,chaos);
00436 SetStringInfoLength(chaos,sizeof(nanoseconds));
00437 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00438 ConcatenateStringInfo(entropy,chaos);
00439 nanoseconds=0;
00440 #if defined(WIZARDSTOOLKIT_HAVE_CLOCK)
00441 nanoseconds=clock();
00442 #endif
00443 #if defined(WIZARDSTOOLKIT_HAVE_TIMES)
00444 {
00445 struct tms
00446 timer;
00447
00448 (void) times(&timer);
00449 nanoseconds=timer.tms_utime+timer.tms_stime;
00450 }
00451 #endif
00452 SetStringInfoLength(chaos,sizeof(nanoseconds));
00453 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00454 ConcatenateStringInfo(entropy,chaos);
00455 #if defined(WIZARDSTOOLKIT_HAVE_MKSTEMP)
00456 {
00457 char
00458 *filename;
00459
00460 int
00461 file;
00462
00463 filename=AcquireString("wizardXXXXXX");
00464 file=mkstemp(filename);
00465 if (file != -1)
00466 if (close(file) == -1)
00467 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00468 "unable to close file `%s': %s",filename,strerror(errno));
00469 if (remove(filename) == -1)
00470 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00471 "unable to remove file `%s': %s",filename,strerror(errno));
00472 SetStringInfoLength(chaos,strlen(filename));
00473 SetStringInfoDatum(chaos,(unsigned char *) filename);
00474 ConcatenateStringInfo(entropy,chaos);
00475 filename=DestroyString(filename);
00476 }
00477 #endif
00478 #if defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
00479 {
00480 double
00481 seconds;
00482
00483 LARGE_INTEGER
00484 nanoseconds;
00485
00486 WizardBooleanType
00487 status;
00488
00489
00490
00491
00492 seconds=NTElapsedTime()+NTUserTime();
00493 SetStringInfoLength(chaos,sizeof(seconds));
00494 SetStringInfoDatum(chaos,(unsigned char *) &seconds);
00495 ConcatenateStringInfo(entropy,chaos);
00496 if (QueryPerformanceCounter(&nanoseconds) != 0)
00497 {
00498 SetStringInfoLength(chaos,sizeof(nanoseconds));
00499 SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
00500 ConcatenateStringInfo(entropy,chaos);
00501 }
00502
00503
00504
00505 SetStringInfoLength(chaos,MaxEntropyExtent);
00506 status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
00507 if (status == WizardFalse)
00508 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00509 "unable to gather random data: %s",strerror(errno));
00510 ConcatenateStringInfo(entropy,chaos);
00511 }
00512 #else
00513 {
00514 char
00515 *filename;
00516
00517 int
00518 file;
00519
00520 ssize_t
00521 count;
00522
00523 StringInfo
00524 *device;
00525
00526
00527
00528
00529 if (environ != (char **) NULL)
00530 {
00531 register ssize_t
00532 i;
00533
00534
00535
00536
00537 for (i=0; environ[i] != (char *) NULL; i++)
00538 {
00539 SetStringInfoLength(chaos,strlen(environ[i]));
00540 SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
00541 ConcatenateStringInfo(entropy,chaos);
00542 }
00543 }
00544 filename=AcquireString("/dev/urandom");
00545 device=StringToStringInfo(filename);
00546 if (GetStringInfoCRC(device) != (WizardSizeType) 0xf9f0014228f2264fll)
00547 ThrowFatalException(RandomFatalError,"random device error `%s'");
00548 device=DestroyStringInfo(device);
00549 file=open(filename,O_RDONLY | O_BINARY);
00550 filename=DestroyString(filename);
00551 if (file != -1)
00552 {
00553 SetStringInfoLength(chaos,MaxEntropyExtent);
00554 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
00555 if (close(file) == -1)
00556 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00557 "unable to close file `%s': %s",filename,strerror(errno));
00558 SetStringInfoLength(chaos,(size_t) count);
00559 ConcatenateStringInfo(entropy,chaos);
00560 }
00561 if (gather_true_random != WizardFalse)
00562 {
00563
00564
00565
00566 filename=AcquireString("/dev/random");
00567 device=StringToStringInfo(filename);
00568 if (GetStringInfoCRC(device) != (WizardSizeType) 0xc36e1cc17bf25fd4ll)
00569 ThrowFatalException(RandomFatalError,"random device error `%s'");
00570 device=DestroyStringInfo(device);
00571 file=open(filename,O_RDONLY | O_BINARY);
00572 filename=DestroyString(filename);
00573 if (file == -1)
00574 {
00575 filename=AcquireString("/dev/srandom");
00576 device=StringToStringInfo(filename);
00577 if (GetStringInfoCRC(device) != (WizardSizeType)
00578 0xf9f0014228f223efll)
00579 ThrowFatalException(RandomFatalError,"random device error `%s'");
00580 device=DestroyStringInfo(device);
00581 file=open(filename,O_RDONLY | O_BINARY);
00582 }
00583 if (file != -1)
00584 {
00585 SetStringInfoLength(chaos,MaxEntropyExtent);
00586 count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
00587 if (close(file) == -1)
00588 (void) ThrowWizardException(exception,GetWizardModule(),
00589 RandomError,"unable to close file `%s': %s",filename,
00590 strerror(errno));
00591 SetStringInfoLength(chaos,(size_t) count);
00592 ConcatenateStringInfo(entropy,chaos);
00593 }
00594 }
00595 }
00596 #endif
00597 chaos=DestroyStringInfo(chaos);
00598 {
00599 const StringInfo
00600 *chaos;
00601
00602 EntropyInfo
00603 *entropy_info;
00604
00605
00606
00607
00608 entropy_info=AcquireEntropyInfo(ZIPEntropy,RandomEntropyLevel);
00609 (void) IncreaseEntropy(entropy_info,entropy,exception);
00610 chaos=GetEntropyChaos(entropy_info);
00611 if (GetStringInfoLength(entropy) < (GetStringInfoLength(chaos)/2))
00612 ThrowFatalException(RandomFatalError,"not enough entropy to continue "
00613 "`%s'");
00614 entropy_info=DestroyEntropyInfo(entropy_info);
00615 }
00616 UnlockSemaphoreInfo(random_info->semaphore);
00617 return(entropy);
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 static StringInfo *GetEntropyFromReservoir(RandomInfo *random_info,
00646 ExceptionInfo *exception)
00647 {
00648 FileInfo
00649 *file_info;
00650
00651 WizardStatusType
00652 status;
00653
00654 StringInfo
00655 *entropy,
00656 *filetype,
00657 *magick,
00658 *target;
00659
00660 size_t
00661 length;
00662
00663 WizardSizeType
00664 crc;
00665
00666 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00667 WizardAssert(CipherDomain,random_info != (RandomInfo *) NULL);
00668 WizardAssert(CipherDomain,random_info->signature == WizardSignature);
00669 WizardAssert(CipherDomain,exception != (ExceptionInfo *) NULL);
00670 LockSemaphoreInfo(random_info->semaphore);
00671 file_info=AcquireFileInfo((const char *) NULL,RandomFilename,ReadFileMode,
00672 exception);
00673 if (file_info == (FileInfo *) NULL)
00674 {
00675 UnlockSemaphoreInfo(random_info->semaphore);
00676 return((StringInfo *) NULL);
00677 }
00678 magick=GetWizardMagick(WizardMagick,sizeof(WizardMagick));
00679 target=CloneStringInfo(magick);
00680 status=ReadFileChunk(file_info,GetStringInfoDatum(target),
00681 GetStringInfoLength(target));
00682 if ((status == WizardFalse) || (CompareStringInfo(target,magick) != 0))
00683 {
00684 file_info=DestroyFileInfo(file_info,exception);
00685 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00686 "corrupt random reservoir file `%s'",GetFilePath(file_info));
00687 UnlockSemaphoreInfo(random_info->semaphore);
00688 return((StringInfo *) NULL);
00689 }
00690 magick=DestroyStringInfo(magick);
00691 target=DestroyStringInfo(target);
00692 filetype=GetWizardMagick((unsigned char *) RandomFiletype,strlen(
00693 RandomFiletype));
00694 target=CloneStringInfo(filetype);
00695 status|=ReadFileChunk(file_info,GetStringInfoDatum(target),
00696 GetStringInfoLength(target));
00697 if ((status == WizardFalse) || (CompareStringInfo(target,filetype) != 0))
00698 {
00699 filetype=DestroyStringInfo(filetype);
00700 target=DestroyStringInfo(target);
00701 file_info=DestroyFileInfo(file_info,exception);
00702 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00703 "corrupt random reservoir file `%s'",GetFilePath(file_info));
00704 UnlockSemaphoreInfo(random_info->semaphore);
00705 return((StringInfo *) NULL);
00706 }
00707 filetype=DestroyStringInfo(filetype);
00708 target=DestroyStringInfo(target);
00709 status|=ReadFile16Bits(file_info,&random_info->protocol_major);
00710 status|=ReadFile16Bits(file_info,&random_info->protocol_minor);
00711 if ((random_info->protocol_major != 1) || (random_info->protocol_minor != 0))
00712 {
00713 WizardSizeType
00714 timestamp;
00715
00716 status|=ReadFile64Bits(file_info,×tamp);
00717 random_info->timestamp=(time_t) timestamp;
00718 }
00719 status|=ReadFile32Bits(file_info,&length);
00720 if (status == WizardFalse)
00721 {
00722 file_info=DestroyFileInfo(file_info,exception);
00723 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00724 "corrupt random reservoir file `%s'",GetFilePath(file_info));
00725 UnlockSemaphoreInfo(random_info->semaphore);
00726 return((StringInfo *) NULL);
00727 }
00728 entropy=AcquireStringInfo(length);
00729 status|=ReadFileChunk(file_info,GetStringInfoDatum(entropy),
00730 GetStringInfoLength(entropy));
00731 crc=0;
00732 status|=ReadFile64Bits(file_info,&crc);
00733 if ((status == WizardFalse) || (crc != GetStringInfoCRC(entropy)))
00734 {
00735 entropy=DestroyStringInfo(entropy);
00736 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00737 "corrupt random reservoir file `%s'",GetFilePath(file_info));
00738 file_info=DestroyFileInfo(file_info,exception);
00739 UnlockSemaphoreInfo(random_info->semaphore);
00740 return((StringInfo *) NULL);
00741 }
00742 file_info=DestroyFileInfo(file_info,exception);
00743 UnlockSemaphoreInfo(random_info->semaphore);
00744 return(entropy);
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 WizardExport double GetPseudoRandomValue(RandomInfo *random_info)
00771 {
00772 register size_t
00773 *seed;
00774
00775 size_t
00776 alpha;
00777
00778 seed=random_info->seed;
00779 do
00780 {
00781 alpha=(size_t) (seed[1] ^ (seed[1] << 11));
00782 seed[1]=seed[2];
00783 seed[2]=seed[3];
00784 seed[3]=seed[0];
00785 seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
00786 } while (seed[0] == ~0UL);
00787 return(random_info->normalize*seed[0]);
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814 WizardExport StringInfo *GetRandomKey(RandomInfo *random_info,
00815 const size_t length)
00816 {
00817 StringInfo
00818 *key;
00819
00820 WizardAssert(CipherDomain,random_info != (RandomInfo *) NULL);
00821 key=AcquireStringInfo(length);
00822 SetRandomKey(random_info,length,GetStringInfoDatum(key));
00823 return(key);
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846 WizardExport double GetRandomValue(RandomInfo *random_info)
00847 {
00848 size_t
00849 key,
00850 range;
00851
00852 range=(~0UL);
00853 do
00854 {
00855 SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
00856 } while (key == range);
00857 return((double) key/range);
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 WizardExport WizardBooleanType RandomComponentGenesis(void)
00879 {
00880 AcquireSemaphoreInfo(&random_semaphore);
00881 return(WizardTrue);
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 WizardExport void RandomComponentTerminus(void)
00903 {
00904 if (random_semaphore == (SemaphoreInfo *) NULL)
00905 AcquireSemaphoreInfo(&random_semaphore);
00906 DestroySemaphoreInfo(&random_semaphore);
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934 static WizardBooleanType SaveEntropyToReservoir(RandomInfo *random_info,
00935 ExceptionInfo *exception)
00936 {
00937 FileInfo
00938 *file_info;
00939
00940 WizardStatusType
00941 status;
00942
00943 size_t
00944 length;
00945
00946 StringInfo
00947 *filetype,
00948 *magick;
00949
00950 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00951 WizardAssert(CipherDomain,random_info != (RandomInfo *) NULL);
00952 WizardAssert(CipherDomain,random_info->signature == WizardSignature);
00953 WizardAssert(CipherDomain,exception != (ExceptionInfo *) NULL);
00954 LockSemaphoreInfo(random_info->semaphore);
00955 file_info=AcquireFileInfo((const char *) NULL,RandomFilename,WriteFileMode,
00956 exception);
00957 if (file_info == (FileInfo *) NULL)
00958 {
00959 UnlockSemaphoreInfo(random_info->semaphore);
00960 return(WizardFalse);
00961 }
00962 magick=GetWizardMagick(WizardMagick,sizeof(WizardMagick));
00963 status=WriteFileChunk(file_info,GetStringInfoDatum(magick),
00964 GetStringInfoLength(magick));
00965 magick=DestroyStringInfo(magick);
00966 filetype=GetWizardMagick((unsigned char *) RandomFiletype,strlen(
00967 RandomFiletype));
00968 status|=WriteFileChunk(file_info,GetStringInfoDatum(filetype),
00969 GetStringInfoLength(filetype));
00970 filetype=DestroyStringInfo(filetype);
00971 status|=WriteFile16Bits(file_info,random_info->protocol_major);
00972 status|=WriteFile16Bits(file_info,random_info->protocol_minor);
00973 status|=WriteFile64Bits(file_info,(WizardSizeType) random_info->timestamp);
00974 length=GetStringInfoLength(GetHMACDigest(random_info->hmac_info));
00975 status|=WriteFile32Bits(file_info,length);
00976 status|=WriteFileChunk(file_info,GetStringInfoDatum(GetHMACDigest(
00977 random_info->hmac_info)),length);
00978 status|=WriteFile64Bits(file_info,GetStringInfoCRC(GetHMACDigest(
00979 random_info->hmac_info)));
00980 if (status == WizardFalse)
00981 (void) ThrowWizardException(exception,GetWizardModule(),RandomError,
00982 "unable to write random reservior `%s': %s",GetFilePath(file_info),
00983 strerror(errno));
00984 file_info=DestroyFileInfo(file_info,exception);
00985 UnlockSemaphoreInfo(random_info->semaphore);
00986 return(WizardTrue);
00987 }
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012 WizardExport void SeedPseudoRandomGenerator(const size_t seed)
01013 {
01014 random_seed=seed;
01015 }
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045 static inline void IncrementRandomNonce(StringInfo *nonce)
01046 {
01047 register ssize_t
01048 i;
01049
01050 unsigned char
01051 *datum;
01052
01053 datum=GetStringInfoDatum(nonce);
01054 for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
01055 {
01056 datum[i]++;
01057 if (datum[i] != 0)
01058 return;
01059 }
01060 ThrowFatalException(RandomFatalError,"Sequence wrap error `%s'");
01061 }
01062
01063 WizardExport void SetRandomKey(RandomInfo *random_info,const size_t length,
01064 unsigned char *key)
01065 {
01066 HMACInfo
01067 *hmac_info;
01068
01069 register size_t
01070 i;
01071
01072 register unsigned char
01073 *p;
01074
01075 unsigned char
01076 *datum;
01077
01078 WizardAssert(CipherDomain,random_info != (RandomInfo *) NULL);
01079 if (length == 0)
01080 return;
01081 LockSemaphoreInfo(random_info->semaphore);
01082 i=length;
01083 hmac_info=random_info->hmac_info;
01084 datum=GetStringInfoDatum(random_info->reservoir);
01085 for (p=key; (i != 0) && (random_info->i != 0); i--)
01086 {
01087 *p++=datum[random_info->i];
01088 random_info->i++;
01089 if (random_info->i == GetHMACDigestsize(hmac_info))
01090 random_info->i=0;
01091 }
01092 while (i >= GetHMACDigestsize(hmac_info))
01093 {
01094 ResetHMAC(hmac_info);
01095 UpdateHMAC(hmac_info,random_info->nonce);
01096 FinalizeHMAC(hmac_info);
01097 IncrementRandomNonce(random_info->nonce);
01098 (void) CopyWizardMemory(p,GetStringInfoDatum(GetHMACDigest(hmac_info)),
01099 GetHMACDigestsize(hmac_info));
01100 p+=GetHMACDigestsize(hmac_info);
01101 i-=GetHMACDigestsize(hmac_info);
01102 }
01103 if (i != 0)
01104 {
01105 ResetHMAC(hmac_info);
01106 UpdateHMAC(hmac_info,random_info->nonce);
01107 FinalizeHMAC(hmac_info);
01108 IncrementRandomNonce(random_info->nonce);
01109 SetStringInfo(random_info->reservoir,GetHMACDigest(hmac_info));
01110 random_info->i=i;
01111 datum=GetStringInfoDatum(random_info->reservoir);
01112 while (i-- != 0)
01113 p[i]=datum[i];
01114 }
01115 UnlockSemaphoreInfo(random_info->semaphore);
01116 }
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142 WizardExport void SetRandomTrueRandom(const WizardBooleanType true_random)
01143 {
01144 gather_true_random=true_random;
01145 }