- Main Page
- Namespaces
- Classes
- Files

# osrng.cpp

    00001 // osrng.cpp - written and placed in the public domain by Wei Dai
    00002
    00003 // Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.
    00004
    00005 #include "pch.h"
    00006
    00007 #ifndef CRYPTOPP_IMPORTS
    00008
    00009 #include "osrng.h"
    00010
    00011 #ifdef OS_RNG_AVAILABLE
    00012
    00013 #include "rng.h"
    00014
    00015 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00016 #ifndef _WIN32_WINNT
    00017 #define _WIN32_WINNT 0x0400
    00018 #endif
    00019 #include <windows.h>
    00020 #include <wincrypt.h>
    00021 #endif
    00022
    00023 #ifdef CRYPTOPP_UNIX_AVAILABLE
    00024 #include <errno.h>
    00025 #include <fcntl.h>
    00026 #include <unistd.h>
    00027 #endif
    00028
    00029 NAMESPACE_BEGIN(CryptoPP)
    00030
    00031 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
    00032 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
    00033         : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
    00034 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00035                 "0x" + IntToString(GetLastError(), 16)
    00036 #else
    00037                 IntToString(errno)
    00038 #endif
    00039                 )
    00040 {
    00041 }
    00042 #endif
    00043
    00044 #ifdef NONBLOCKING_RNG_AVAILABLE
    00045
    00046 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00047
    00048 MicrosoftCryptoProvider::MicrosoftCryptoProvider()
    00049 {
    00050         if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    00051                 throw OS_RNG_Err("CryptAcquireContext");
    00052 }
    00053
    00054 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
    00055 {
    00056         CryptReleaseContext(m_hProvider, 0);
    00057 }
    00058
    00059 #endif
    00060
    00061 NonblockingRng::NonblockingRng()
    00062 {
    00063 #ifndef CRYPTOPP_WIN32_AVAILABLE
    00064         m_fd = open("/dev/urandom",O_RDONLY);
    00065         if (m_fd == -1)
    00066                 throw OS_RNG_Err("open /dev/urandom");
    00067 #endif
    00068 }
    00069
    00070 NonblockingRng::~NonblockingRng()
    00071 {
    00072 #ifndef CRYPTOPP_WIN32_AVAILABLE
    00073         close(m_fd);
    00074 #endif
    00075 }
    00076
    00077 void NonblockingRng::GenerateBlock(byte *output, size_t size)
    00078 {
    00079 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00080 #       ifdef WORKAROUND_MS_BUG_Q258000
    00081                 const MicrosoftCryptoProvider &m_Provider = Singleton<MicrosoftCryptoProvider>().Ref();
    00082 #       endif
    00083         if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
    00084                 throw OS_RNG_Err("CryptGenRandom");
    00085 #else
    00086         if (read(m_fd, output, size) != size)
    00087                 throw OS_RNG_Err("read /dev/urandom");
    00088 #endif
    00089 }
    00090
    00091 #endif
    00092
    00093 // *************************************************************
    00094
    00095 #ifdef BLOCKING_RNG_AVAILABLE
    00096
    00097 #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
    00098 #ifdef __OpenBSD__
    00099 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
    00100 #else
    00101 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
    00102 #endif
    00103 #endif
    00104
    00105 BlockingRng::BlockingRng()
    00106 {
    00107         m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
    00108         if (m_fd == -1)
    00109                 throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
    00110 }
    00111
    00112 BlockingRng::~BlockingRng()
    00113 {
    00114         close(m_fd);
    00115 }
    00116
    00117 void BlockingRng::GenerateBlock(byte *output, size_t size)
    00118 {
    00119         while (size)
    00120         {
    00121                 // on some systems /dev/random will block until all bytes
    00122                 // are available, on others it will returns immediately
    00123                 ssize_t len = read(m_fd, output, size);
    00124                 if (len < 0)
    00125                         throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
    00126                 size -= len;
    00127                 output += len;
    00128                 if (size)
    00129                         sleep(1);
    00130         }
    00131 }
    00132
    00133 #endif
    00134
    00135 // *************************************************************
    00136
    00137 void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
    00138 {
    00139 #ifdef NONBLOCKING_RNG_AVAILABLE
    00140         if (blocking)
    00141 #endif
    00142         {
    00143 #ifdef BLOCKING_RNG_AVAILABLE
    00144                 BlockingRng rng;
    00145                 rng.GenerateBlock(output, size);
    00146 #endif
    00147         }
    00148
    00149 #ifdef BLOCKING_RNG_AVAILABLE
    00150         if (!blocking)
    00151 #endif
    00152         {
    00153 #ifdef NONBLOCKING_RNG_AVAILABLE
    00154                 NonblockingRng rng;
    00155                 rng.GenerateBlock(output, size);
    00156 #endif
    00157         }
    00158 }
    00159
    00160 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
    00161 {
    00162         SecByteBlock seed(seedSize);
    00163         OS_GenerateRandomBlock(blocking, seed, seedSize);
    00164         IncorporateEntropy(seed, seedSize);
    00165 }
    00166
    00167 NAMESPACE_END
    00168
    00169 #endif
    00170
    00171 #endif