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

Generated on Sat Nov 22 23:45:17 2008 for MagickCore by  doxygen 1.5.7.1