WizardsToolkit  1.0.7
random.c
Go to the documentation of this file.
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,&timestamp);
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 }