reSIProcate/rutil  9694
Random.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include <cassert>
00006 #include <stdlib.h>
00007 
00008 #ifdef WIN32
00009 #include "rutil/Socket.hxx"
00010 #include "rutil/DataStream.hxx"
00011 #include "rutil/Data.hxx"
00012 #else
00013 #include <unistd.h>
00014 #include <sys/types.h>
00015 #include <sys/stat.h>
00016 #include <fcntl.h>
00017 #endif
00018 
00019 #include "rutil/Random.hxx"
00020 #include "rutil/Timer.hxx"
00021 #include "rutil/Mutex.hxx"
00022 #include "rutil/Lock.hxx"
00023 #include "rutil/Logger.hxx"
00024 
00025 
00026 #ifdef USE_SSL
00027 #ifdef WIN32
00028 //hack for name collision of OCSP_RESPONSE and wincrypt.h in latest openssl release 0.9.8h
00029 //http://www.google.com/search?q=OCSP%5fRESPONSE+wincrypt%2eh
00030 //continue to watch this issue for a real fix.
00031 #undef OCSP_RESPONSE
00032 #endif
00033 #include "rutil/ssl/OpenSSLInit.hxx"
00034 #  define USE_OPENSSL 1
00035 #else
00036 #  define USE_OPENSSL 0
00037 #endif
00038 
00039 #if ( USE_OPENSSL == 1 )
00040 #  include <openssl/e_os2.h>
00041 #  include <openssl/rand.h>
00042 #  include <openssl/err.h>
00043 #endif
00044 
00045 using namespace resip;
00046 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00047 
00048 Mutex Random::mMutex;
00049 bool Random::mIsInitialized = false;
00050 
00051 #ifdef WIN32
00052 Random::Initializer Random::mInitializer;
00053 #ifdef RESIP_RANDOM_WIN32_RTL
00054 BOOLEAN (APIENTRY *Random::RtlGenRandom)(void*, ULONG) = 0;
00055 #endif
00056 #endif //WIN32
00057 
00058 #ifdef RESIP_RANDOM_THREAD_MUTEX
00059 struct random_data* Random::sRandomState = 0;
00060 #endif
00061 
00062 #ifdef RESIP_RANDOM_THREAD_LOCAL
00063 ThreadIf::TlsKey Random::sRandomStateKey = 0;
00064 #endif
00065 
00066 #define RANDOM_STATE_SIZE 128
00067 
00068 const char*
00069 Random::getImplName()
00070 {
00071 #ifdef WIN32
00072 #if defined(RESIP_RANDOM_WIN32_RTL)
00073    return "win32_rtl";
00074 #else
00075    return "win32_rand";
00076 #endif
00077 #else // WIN32
00078 #if defined(RESIP_RANDOM_THREAD_LOCAL)
00079    return "posix_thread_local";
00080 #elif defined(RESIP_RANDOM_THREAD_MUTEX)
00081    return "posix_thread_mutex";
00082 #else
00083    return "posix_random";
00084 #endif
00085 #endif // not WIN32
00086 }
00087 
00091 unsigned
00092 Random::getSimpleSeed()
00093 {
00094    // !cj! need to find a better way - use pentium random commands?
00095    Data buffer;
00096    {
00097       DataStream strm(buffer);
00098 #ifdef WIN32
00099       strm << GetTickCount() << ":";
00100       strm << GetCurrentProcessId() << ":";
00101       strm << GetCurrentThreadId();
00102 #else
00103       // .kw. previously just used the lower 32bits of getTimeMs()
00104       strm << ResipClock::getTimeMicroSec() << ":";
00105       strm << getpid();
00106 #if defined(RESIP_RANDOM_THREAD_LOCAL)
00107       strm << ":" << ThreadIf::selfId();
00108 #endif
00109 #endif
00110    }
00111    return (unsigned int)buffer.hash();
00112 }
00113 
00114 void
00115 Random::initialize()
00116 {  
00117 #ifdef WIN32
00118 //#if defined(USE_SSL)
00119 #if 0 //!dcm! - this shouldn't be per thread for win32, and this is slow. Going
00120       //to re-work openssl initialization
00121    if ( !Random::mIsInitialized)
00122    {
00123       Lock lock(mMutex);
00124       if (!Random::mIsInitialized)
00125       {
00126          mIsInitialized = true;
00127          RAND_screen ();
00128       }
00129    }
00130 #else      
00131    if (!Random::mInitializer.isInitialized())
00132    {
00133       Lock lock(mMutex);      
00134       if (!Random::mInitializer.isInitialized())
00135       {
00136          Random::mInitializer.setInitialized();
00137 
00138          unsigned seed = getSimpleSeed();
00139          srand(seed);
00140 
00141 #ifdef RESIP_RANDOM_WIN32_RTL
00142          // .jjg. from http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
00143          // srand(..) and rand() have proven to be insufficient sources of randomness,
00144          // leading to transaction id collisions in resip.
00145          // SystemFunction036 maps to RtlGenRandom, which is used by rand_s() (which is available
00146          // only with the VC 8.0 runtime or later) and is the Microsoft-recommended way of getting
00147          // a random number. This code allows that functionality to be accessed even from VC 7.1.
00148          // However, SystemFunction036 only exists in Windows XP and later, so we may need to fallback
00149          // to the old method using rand().
00150          HMODULE hLib = LoadLibrary("ADVAPI32.DLL");
00151          if (hLib)
00152          {
00153             Random::RtlGenRandom =
00154                (BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,"SystemFunction036");
00155 
00156             if (!Random::RtlGenRandom)
00157             {
00158                WarningLog(<< "Using srand(..) and rand() for random numbers");
00159             }
00160          }
00161 #endif   // RESIP_RANDOM_WIN32_RTL
00162 
00163          mIsInitialized = true;
00164 
00165       }
00166    }
00167 #endif  // not dead code
00168 
00169 #else   // WIN32
00170    // ?dcm? -- OpenSSL will transparently initialize PRNG if /dev/urandom is
00171    // present. In any case, will move into OpenSSLInit
00172    if ( !Random::mIsInitialized)
00173    {
00174       Lock lock(mMutex);
00175       if (!Random::mIsInitialized)
00176       {
00177          mIsInitialized = true;
00178          Timer::setupTimeOffsets();
00179 
00180          unsigned seed = getSimpleSeed();
00181 
00182 #if defined(RESIP_RANDOM_THREAD_LOCAL)
00183          ThreadIf::tlsKeyCreate(sRandomStateKey, ::free);
00184 #elif defined(RESIP_RANDOM_THREAD_MUTEX)
00185          struct random_data *buf;
00186          size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE;
00187          buf = (struct random_data*) ::malloc(sz);
00188          memset( buf, 0, sz);      // .kw. strange segfaults without this
00189          initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf);
00190          sRandomState = buf;
00191 #else
00192          srandom(seed);
00193 #endif
00194 
00195 
00196          int fd = open("/dev/urandom", O_RDONLY);
00197          // !ah! blocks on embedded devices -- not enough entropy.
00198          if ( fd != -1 )
00199          {
00200             int s = read( fd,&seed,sizeof(seed) ); 
00201 
00202             if ( s != sizeof(seed) )
00203             {
00204                ErrLog( << "System is short of randomness" ); // !ah! never prints
00205             }
00206          }
00207          else
00208          {
00209             ErrLog( << "Could not open /dev/urandom" );
00210          }
00211 
00212 #if defined(USE_SSL)
00213          if (fd == -1 )
00214          {
00215             // really bad sign - /dev/random does not exist so need to intialize
00216             // OpenSSL some other way
00217 
00218             // !cj! need to fix         assert(0);
00219          }
00220          else
00221          {
00222             char buf[1024/8]; // size is number byes used for OpenSSL init 
00223 
00224             int s = read( fd,&buf,sizeof(buf) );
00225 
00226             if ( s != sizeof(buf) )
00227             {
00228                ErrLog( << "System is short of randomness" );
00229             }
00230          
00231             RAND_add(buf,sizeof(buf),double(s*8));
00232          }
00233 #endif   // SSL
00234          if (fd != -1 )
00235          {
00236             ::close(fd);
00237          }
00238       }
00239    }
00240 #endif  // not WIN32
00241 }
00242 
00243 int
00244 Random::getRandom()
00245 {
00246    initialize();
00247 
00248 #ifdef WIN32
00249 
00250    int ret = 0;
00251 
00252 #ifdef RESIP_RANDOM_WIN32_RTL
00253    // see comment in initialize()
00254    if (Random::RtlGenRandom)
00255    {
00256       unsigned long buff[1];
00257       ULONG ulCbBuff = sizeof(buff);
00258       if (Random::RtlGenRandom(buff,ulCbBuff))
00259       {
00260          // .kw. all other impls here return positive number, so do the same...
00261          ret = buff[0] & (~(1<<31));
00262          return ret;
00263       }
00264    }
00265    // fallback to using rand() if this is a Windows version previous to XP
00266 #endif  // RESIP_RANDOM_WIN32_RTL
00267    {
00268       // rand() returns [0,RAND_MAX], which on Windows is 15 bits and positive
00269       // code below gets 30bits of randomness; with bit31 and bit15
00270       // always zero; result is always positive
00271       assert( RAND_MAX == 0x7fff );
00272       // WATCHOUT: on Linux, rand() returns 31bits, and assert above will fail
00273       int r1 = rand();
00274       int r2 = rand();
00275       ret = (r1<<16) + r2;
00276    }
00277 
00278    return ret;
00279 #else   // WIN32
00280 
00281 #if defined(RESIP_RANDOM_THREAD_LOCAL)
00282    struct random_data *buf = (struct random_data*) ThreadIf::tlsGetValue(sRandomStateKey);
00283    if ( buf==NULL ) {
00284       size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE;
00285       buf = (struct random_data*) ::malloc(sz);
00286       memset( buf, 0, sz);      // .kw. strange segfaults without this
00287       unsigned seed = getSimpleSeed();
00288       initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf);
00289       ThreadIf::tlsSetValue(sRandomStateKey, buf);
00290    }
00291    int32_t ret;
00292    random_r(buf, &ret);
00293    return ret;
00294 #elif defined(RESIP_RANDOM_THREAD_MUTEX)
00295    int32_t ret;
00296    {
00297       Lock statelock(mMutex);
00298       random_r(sRandomState, &ret);
00299    }
00300    return ret;
00301 #else
00302    // random returns [0,RAN_MAX]. On Linux, this is 31 bits and positive.
00303    // On some platforms it might be on 15 bits, and will need to do something.
00304    // assert( RAND_MAX == ((1<<31)-1) );  // ?slg? commented out assert since, RAND_MAX is not used in random(), it applies to rand() only
00305    return random(); 
00306 #endif  // THREAD_LOCAL
00307 #endif // WIN32
00308 }
00309 
00310 int
00311 Random::getCryptoRandom()
00312 {
00313    initialize();
00314 
00315 #if USE_OPENSSL
00316    int ret;
00317    int e = RAND_bytes( (unsigned char*)&ret , sizeof(ret) );
00318    if ( e < 0 )
00319    {
00320       // error of some type - likely not enough rendomness to dod this 
00321       long err = ERR_get_error();
00322       
00323       char buf[1024];
00324       ERR_error_string_n(err,buf,sizeof(buf));
00325       
00326       ErrLog( << buf );
00327       assert(0);
00328    }
00329    return ret;
00330 #else
00331    return getRandom();
00332 #endif
00333 }
00334 
00335 Data 
00336 Random::getRandom(unsigned int len)
00337 {
00338    initialize();
00339    assert(len < Random::maxLength+1);
00340    
00341    union 
00342    {
00343          char cbuf[Random::maxLength+1];
00344          unsigned int  ibuf[(Random::maxLength+1)/sizeof(int)];
00345    };
00346    
00347    for (unsigned int count=0; count<(len+sizeof(int)-1)/sizeof(int); ++count)
00348    {
00349       ibuf[count] = Random::getRandom();
00350    }
00351    return Data(cbuf, len);
00352 }
00353 
00354 Data 
00355 Random::getCryptoRandom(unsigned int len)
00356 {
00357    unsigned char* buf = new unsigned char[len];
00358    getCryptoRandom(buf, len); // USE_SSL check is in here
00359    return Data(Data::Take, (char*)buf, len);
00360 }
00361 
00362 Data 
00363 Random::getRandomHex(unsigned int numBytes)
00364 {
00365    return Random::getRandom(numBytes).hex();
00366 }
00367 
00368 Data 
00369 Random::getRandomBase64(unsigned int numBytes)
00370 {
00371    return Random::getRandom(numBytes).base64encode();
00372 }
00373 
00374 Data 
00375 Random::getCryptoRandomHex(unsigned int numBytes)
00376 {
00377    return Random::getCryptoRandom(numBytes).hex();
00378 }
00379 
00380 Data 
00381 Random::getCryptoRandomBase64(unsigned int numBytes)
00382 {
00383    return Random::getCryptoRandom(numBytes).base64encode();
00384 }
00385 
00386 /*
00387    [From RFC 4122]
00388 
00389    The version 4 UUID is meant for generating UUIDs from truly-random or
00390    pseudo-random numbers.
00391 
00392    The algorithm is as follows:
00393 
00394    o  Set the two most significant bits (bits 6 and 7) of the
00395       clock_seq_hi_and_reserved to zero and one, respectively.
00396 
00397    o  Set the four most significant bits (bits 12 through 15) of the
00398       time_hi_and_version field to the 4-bit version number from
00399       Section 4.1.3. (0 1 0 0)
00400 
00401    o  Set all the other bits to randomly (or pseudo-randomly) chosen
00402       values.
00403 
00404       UUID                   = time-low "-" time-mid "-"
00405                                time-high-and-version "-"
00406                                clock-seq-and-reserved
00407                                clock-seq-low "-" node
00408       time-low               = 4hexOctet
00409       time-mid               = 2hexOctet
00410       time-high-and-version  = 2hexOctet
00411       clock-seq-and-reserved = hexOctet
00412       clock-seq-low          = hexOctet
00413       node                   = 6hexOctet
00414       hexOctet               = hexDigit hexDigit
00415 */
00416 Data 
00417 Random::getVersion4UuidUrn()
00418 {
00419   Data urn ("urn:uuid:");
00420   urn += getCryptoRandomHex(4); // time-low
00421   urn += "-";
00422   urn += getCryptoRandomHex(2); // time-mid
00423   urn += "-";
00424 
00425   Data time_hi_and_version = Random::getCryptoRandom(2);
00426   time_hi_and_version[0] &= 0x0f;
00427   time_hi_and_version[0] |= 0x40;
00428   urn += time_hi_and_version.hex();
00429 
00430   urn += "-";
00431 
00432   Data clock_seq_hi_and_reserved = Random::getCryptoRandom(1);
00433   clock_seq_hi_and_reserved[0] &= 0x3f;
00434   clock_seq_hi_and_reserved[0] |= 0x40;
00435   urn += clock_seq_hi_and_reserved.hex();
00436 
00437   urn += getCryptoRandomHex(1); // clock-seq-low
00438   urn += "-";
00439   urn += getCryptoRandomHex(6); // node
00440   return urn;
00441 }
00442 
00443 void 
00444 Random::getCryptoRandom(unsigned char* buf, unsigned int numBytes)
00445 {
00446    assert(numBytes < Random::maxLength+1);
00447 
00448 #if USE_OPENSSL
00449    initialize();
00450    int e = RAND_bytes( (unsigned char*)buf , numBytes );
00451    if ( e < 0 )
00452    {
00453       // error of some type - likely not enough rendomness to dod this 
00454       long err = ERR_get_error();
00455       
00456       char buf[1024];
00457       ERR_error_string_n(err,buf,sizeof(buf));
00458       
00459       ErrLog( << buf );
00460       assert(0);
00461    }
00462 #else
00463    // !bwc! Should optimize this.
00464    Data temp=Random::getRandom(numBytes);
00465    memcpy(buf, temp.data(), numBytes);
00466 #endif
00467 }
00468 
00469 #ifdef WIN32
00470 Random::Initializer::Initializer()  : mThreadStorage(::TlsAlloc())
00471 { 
00472    assert(mThreadStorage != TLS_OUT_OF_INDEXES);
00473 }
00474 
00475 Random::Initializer::~Initializer() 
00476 { 
00477    ::TlsFree(mThreadStorage); 
00478 }
00479 
00480 void 
00481 Random::Initializer::setInitialized() 
00482 { 
00483    ::TlsSetValue(mThreadStorage, (LPVOID) TRUE);
00484 }
00485 
00486 bool 
00487 Random::Initializer::isInitialized() 
00488 { 
00489    // Note:  if value is not set yet then 0 (false) is returned
00490    return (BOOL) ::TlsGetValue(mThreadStorage) == TRUE; 
00491 }
00492 #endif
00493 
00494 
00495 /* ====================================================================
00496  * The Vovida Software License, Version 1.0 
00497  * 
00498  * Copyright (c) 2005.   All rights reserved.
00499  * 
00500  * Redistribution and use in source and binary forms, with or without
00501  * modification, are permitted provided that the following conditions
00502  * are met:
00503  * 
00504  * 1. Redistributions of source code must retain the above copyright
00505  *    notice, this list of conditions and the following disclaimer.
00506  * 
00507  * 2. Redistributions in binary form must reproduce the above copyright
00508  *    notice, this list of conditions and the following disclaimer in
00509  *    the documentation and/or other materials provided with the
00510  *    distribution.
00511  * 
00512  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00513  *    and "Vovida Open Communication Application Library (VOCAL)" must
00514  *    not be used to endorse or promote products derived from this
00515  *    software without prior written permission. For written
00516  *    permission, please contact vocal@vovida.org.
00517  *
00518  * 4. Products derived from this software may not be called "VOCAL", nor
00519  *    may "VOCAL" appear in their name, without prior written
00520  *    permission of Vovida Networks, Inc.
00521  * 
00522  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00523  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00524  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00525  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00526  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00527  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00528  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00529  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00530  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00531  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00532  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00533  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00534  * DAMAGE.
00535  * 
00536  * ====================================================================
00537  * 
00538  * This software consists of voluntary contributions made by Vovida
00539  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00540  * Inc.  For more information on Vovida Networks, Inc., please see
00541  * <http://www.vovida.org/>.
00542  *
00543  * vi: set shiftwidth=3 expandtab:
00544  */