Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

# 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 #else
    00022 #include <errno.h>
    00023 #include <fcntl.h>
    00024 #include <unistd.h>
    00025 #endif
    00026
    00027 NAMESPACE_BEGIN(CryptoPP)
    00028
    00029 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
    00030 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
    00031         : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
    00032 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00033                 "0x" + IntToString(GetLastError(), 16)
    00034 #else
    00035                 IntToString(errno)
    00036 #endif
    00037                 )
    00038 {
    00039 }
    00040 #endif
    00041
    00042 #ifdef NONBLOCKING_RNG_AVAILABLE
    00043
    00044 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00045
    00046 MicrosoftCryptoProvider::MicrosoftCryptoProvider()
    00047 {
    00048         if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    00049                 throw OS_RNG_Err("CryptAcquireContext");
    00050 }
    00051
    00052 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
    00053 {
    00054         CryptReleaseContext(m_hProvider, 0);
    00055 }
    00056
    00057 #endif
    00058
    00059 NonblockingRng::NonblockingRng()
    00060 {
    00061 #ifndef CRYPTOPP_WIN32_AVAILABLE
    00062         m_fd = open("/dev/urandom",O_RDONLY);
    00063         if (m_fd == -1)
    00064                 throw OS_RNG_Err("open /dev/urandom");
    00065 #endif
    00066 }
    00067
    00068 NonblockingRng::~NonblockingRng()
    00069 {
    00070 #ifndef CRYPTOPP_WIN32_AVAILABLE
    00071         close(m_fd);
    00072 #endif
    00073 }
    00074
    00075 byte NonblockingRng::GenerateByte()
    00076 {
    00077         byte b;
    00078         GenerateBlock(&b, 1);
    00079         return b;
    00080 }
    00081
    00082 void NonblockingRng::GenerateBlock(byte *output, unsigned int size)
    00083 {
    00084 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00085 #       ifdef WORKAROUND_MS_BUG_Q258000
    00086                 static MicrosoftCryptoProvider m_Provider;
    00087 #       endif
    00088         if (!CryptGenRandom(m_Provider.GetProviderHandle(), size, output))
    00089                 throw OS_RNG_Err("CryptGenRandom");
    00090 #else
    00091         if (read(m_fd, output, size) != size)
    00092                 throw OS_RNG_Err("read /dev/urandom");
    00093 #endif
    00094 }
    00095
    00096 #endif
    00097
    00098 // *************************************************************
    00099
    00100 #ifdef BLOCKING_RNG_AVAILABLE
    00101
    00102 BlockingRng::BlockingRng()
    00103 {
    00104         m_fd = open("/dev/random",O_RDONLY);
    00105         if (m_fd == -1)
    00106                 throw OS_RNG_Err("open /dev/random");
    00107 }
    00108
    00109 BlockingRng::~BlockingRng()
    00110 {
    00111         close(m_fd);
    00112 }
    00113
    00114 byte BlockingRng::GenerateByte()
    00115 {
    00116         byte b;
    00117         GenerateBlock(&b, 1);
    00118         return b;
    00119 }
    00120
    00121 void BlockingRng::GenerateBlock(byte *output, unsigned int size)
    00122 {
    00123         while (size)
    00124         {
    00125                 // on some systems /dev/random will block until all bytes
    00126                 // are available, on others it will returns immediately
    00127                 int len = read(m_fd, output, STDMIN(size, (unsigned int)INT_MAX));
    00128                 if (len == -1)
    00129                         throw OS_RNG_Err("read /dev/random");
    00130                 size -= len;
    00131                 output += len;
    00132                 if (size)
    00133                         sleep(1);
    00134         }
    00135 }
    00136
    00137 #endif
    00138
    00139 // *************************************************************
    00140
    00141 void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size)
    00142 {
    00143 #ifdef NONBLOCKING_RNG_AVAILABLE
    00144         if (blocking)
    00145 #endif
    00146         {
    00147 #ifdef BLOCKING_RNG_AVAILABLE
    00148                 BlockingRng rng;
    00149                 rng.GenerateBlock(output, size);
    00150 #endif
    00151         }
    00152
    00153 #ifdef BLOCKING_RNG_AVAILABLE
    00154         if (!blocking)
    00155 #endif
    00156         {
    00157 #ifdef NONBLOCKING_RNG_AVAILABLE
    00158                 NonblockingRng rng;
    00159                 rng.GenerateBlock(output, size);
    00160 #endif
    00161         }
    00162 }
    00163
    00164 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
    00165 {
    00166         SecByteBlock seed(seedSize);
    00167         OS_GenerateRandomBlock(blocking, seed, seedSize);
    00168         Put(seed, seedSize);
    00169 }
    00170
    00171 NAMESPACE_END
    00172
    00173 #endif
    00174
    00175 #endif