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