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-2010 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 
00058 /*
00059   Define declarations.
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   Typedef declarations.
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   External declarations.
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   Global declarations.
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   Forward declarations.
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 %   A c q u i r e R a n d o m I n f o                                         %
00142 %                                                                             %
00143 %                                                                             %
00144 %                                                                             %
00145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00146 %
00147 %  AcquireRandomInfo() allocates the RandomInfo structure.
00148 %
00149 %  The format of the AcquireRandomInfo method is:
00150 %
00151 %      RandomInfo *AcquireRandomInfo(const RandomType hash)
00152 %
00153 %  A description of each parameter follows:
00154 %
00155 %    o hash: the hash type.
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     Seed random nonce.
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     Seed random reservoir with entropic data.
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     Seed pseudo random number generator.
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 +   D e s t r o y R a n d o m I n f o                                         %
00266 %                                                                             %
00267 %                                                                             %
00268 %                                                                             %
00269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00270 %
00271 %  DestroyRandomInfo() deallocates memory associated with the random
00272 %  reservoir.
00273 %
00274 %  The format of the DestroyRandomInfo method is:
00275 %
00276 %      RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
00277 %
00278 %  A description of each parameter follows:
00279 %
00280 %    o random_info: the random info.
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 +   G e n e r a t e E n t r o p i c C h a o s                                 %
00309 %                                                                             %
00310 %                                                                             %
00311 %                                                                             %
00312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00313 %
00314 %  GenerateEntropicChaos() generate entropic chaos used to initialize the
00315 %  random reservoir.
00316 %
00317 %  The format of the GenerateEntropicChaos method is:
00318 %
00319 %      StringInfo *GenerateEntropicChaos(RandomInfo *random_info,
00320 %        ExceptionInfo *exception)
00321 %
00322 %  A description of each parameter follows:
00323 %
00324 %    o random_info: the random info.
00325 %
00326 %    o exception: Return any errors or warnings in this structure.
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     Initialize random reservoir.
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       Not crytographically strong but better than nothing.
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       Our best hope for true entropy.
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       Not crytographically strong but better than nothing.
00528     */
00529     if (environ != (char **) NULL)
00530       {
00531         register ssize_t
00532           i;
00533 
00534         /*
00535           Squeeze some entropy from the sometimes unpredicatble environment.
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           Our best hope for true entropy.
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       Estimate entropy.
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 %   G e t E n t r o p y F r o m R e s e r v i o r                             %
00626 %                                                                             %
00627 %                                                                             %
00628 %                                                                             %
00629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00630 %
00631 %  GetEntropyFromReservoir() gets entropy from the random reservoir on disk.
00632 %
00633 %  The format of the GetEntropyFromReservoir method is:
00634 %
00635 %      StringInfo *GetEntropyFromReservoir(RandomInfo *random_info,
00636 %        ExceptionInfo *exception)
00637 %
00638 %  A description of each parameter follows:
00639 %
00640 %    o random_info: the random reservoir info.
00641 %
00642 %    o exception: Return any errors or warnings in this structure.
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,&timestamp);
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 %   G e t P s e u d o R a n d o m V a l u e                                   %
00753 %                                                                             %
00754 %                                                                             %
00755 %                                                                             %
00756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00757 %
00758 %  GetPseudoRandomValue() return a non-negative size_t value uniformly
00759 %  distributed over the interval [0.0, 1.0) with a 2 to the 128th-1 period.
00760 %
00761 %  The format of the GetPseudoRandomValue method is:
00762 %
00763 %      double GetPseudoRandomValue(RandomInfo *randon_info)
00764 %
00765 %  A description of each parameter follows:
00766 %
00767 %    o random_info: the random info.
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 %   G e t R a n d o m K e y                                                   %
00796 %                                                                             %
00797 %                                                                             %
00798 %                                                                             %
00799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00800 %
00801 %  GetRandomKey() gets a random key from the reservoir.
00802 %
00803 %  The format of the GetRandomKey method is:
00804 %
00805 %      StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
00806 %
00807 %  A description of each parameter follows:
00808 %
00809 %    o random_info: the random info.
00810 %
00811 %    o length: the key length.
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 %   G e t R a n d o m V a l u e                                               %
00832 %                                                                             %
00833 %                                                                             %
00834 %                                                                             %
00835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00836 %
00837 %  GetRandomValue() return a non-negative double-precision floating-point
00838 %  value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
00839 %  128th-1 period (not cryptographically strong).
00840 %
00841 %  The format of the GetRandomValue method is:
00842 %
00843 %      double GetRandomValue(void)
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 +   R a n d o m C o m p o n e n t G e n e s i s                               %
00866 %                                                                             %
00867 %                                                                             %
00868 %                                                                             %
00869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00870 %
00871 %  RandomComponentGenesis() instantiates the random component.
00872 %
00873 %  The format of the RandomComponentGenesis method is:
00874 %
00875 %      RandomComponentGenesis(void)
00876 %
00877 */
00878 WizardExport WizardBooleanType RandomComponentGenesis(void)
00879 {
00880   AcquireSemaphoreInfo(&random_semaphore);
00881   return(WizardTrue);
00882 }
00883 
00884 /*
00885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00886 %                                                                             %
00887 %                                                                             %
00888 %                                                                             %
00889 +   R a n d o m C o m p o n e n t T e r m i n u s                             %
00890 %                                                                             %
00891 %                                                                             %
00892 %                                                                             %
00893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00894 %
00895 %  RandomComponentTerminus() destroys the random component.
00896 %
00897 %  The format of the RandomComponentTerminus method is:
00898 %
00899 %      RandomComponentTerminus(void)
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 %   S a v e E n t r o p y T o R e s e r v o i r                               %
00915 %                                                                             %
00916 %                                                                             %
00917 %                                                                             %
00918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00919 %
00920 %  SaveEntropyToReservoir() saves entropy to the reservior on disk.
00921 %
00922 %  The format of the SaveEntropyToReservoir method is:
00923 %
00924 %      WizardBooleanType SaveEntropyToReservoir(RandomInfo *random_info,
00925 %        ExceptionInfo *exception)
00926 %
00927 %  A description of each parameter follows:
00928 %
00929 %    o random_info: the random info.
00930 %
00931 %    o exception: Return any errors or warnings in this structure.
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 %   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                         %
00995 %                                                                             %
00996 %                                                                             %
00997 %                                                                             %
00998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00999 %
01000 %  SeedPseudoRandomGenerator() initializes the pseudo-random number generator
01001 %  with a random seed.
01002 %
01003 %  The format of the SeedPseudoRandomGenerator method is:
01004 %
01005 %      void SeedPseudoRandomGenerator(const size_t seed)
01006 %
01007 %  A description of each parameter follows:
01008 %
01009 %    o seed: the seed.
01010 %
01011 */
01012 WizardExport void SeedPseudoRandomGenerator(const size_t seed)
01013 {
01014   random_seed=seed;
01015 }
01016 
01017 /*
01018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01019 %                                                                             %
01020 %                                                                             %
01021 %                                                                             %
01022 %   S e t R a n d o m K e y                                                   %
01023 %                                                                             %
01024 %                                                                             %
01025 %                                                                             %
01026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01027 %
01028 %  SetRandomKey() sets a random key from the reservoir.
01029 %
01030 %  The format of the SetRandomKey method is:
01031 %
01032 %      void SetRandomKey(RandomInfo *random_info,const size_t length,
01033 %        unsigned char *key)
01034 %
01035 %  A description of each parameter follows:
01036 %
01037 %    o random_info: the random info.
01038 %
01039 %    o length: the key length.
01040 %
01041 %    o key: the key.
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 %   S e t R a n d o m T r u e R a n d o m                                     %
01124 %                                                                             %
01125 %                                                                             %
01126 %                                                                             %
01127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01128 %
01129 %  SetRandomTrueRandom() declares your intentions to use true random numbers.
01130 %  True random numbers are encouraged but may not always be practical because
01131 %  your application may block while entropy is gathered from your environment.
01132 %
01133 %  The format of the SetRandomTrueRandom method is:
01134 %
01135 %      void SetRandomTrueRandom(const WizardBooleanType true_random)
01136 %
01137 %  A description of each parameter follows:
01138 %
01139 %    o true_random: declare your intentions to use true-random number.
01140 %
01141 */
01142 WizardExport void SetRandomTrueRandom(const WizardBooleanType true_random)
01143 {
01144   gather_true_random=true_random;
01145 }
Generated by  doxygen 1.6.2-20100208