Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class 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 #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 byte NonblockingRng::GenerateByte()
    00078 {
    00079         byte b;
    00080         GenerateBlock(&b, 1);
    00081         return b;
    00082 }
    00083
    00084 void NonblockingRng::GenerateBlock(byte *output, unsigned int size)
    00085 {
    00086 #ifdef CRYPTOPP_WIN32_AVAILABLE
    00087 #       ifdef WORKAROUND_MS_BUG_Q258000
    00088                 static MicrosoftCryptoProvider m_Provider;
    00089 #       endif
    00090         if (!CryptGenRandom(m_Provider.GetProviderHandle(), size, output))
    00091                 throw OS_RNG_Err("CryptGenRandom");
    00092 #else
    00093         if (read(m_fd, output, size) != size)
    00094                 throw OS_RNG_Err("read /dev/urandom");
    00095 #endif
    00096 }
    00097
    00098 #endif
    00099
    00100 // *************************************************************
    00101
    00102 #ifdef BLOCKING_RNG_AVAILABLE
    00103
    00104 BlockingRng::BlockingRng()
    00105 {
    00106         m_fd = open("/dev/random",O_RDONLY);
    00107         if (m_fd == -1)
    00108                 throw OS_RNG_Err("open /dev/random");
    00109 }
    00110
    00111 BlockingRng::~BlockingRng()
    00112 {
    00113         close(m_fd);
    00114 }
    00115
    00116 byte BlockingRng::GenerateByte()
    00117 {
    00118         byte b;
    00119         GenerateBlock(&b, 1);
    00120         return b;
    00121 }
    00122
    00123 void BlockingRng::GenerateBlock(byte *output, unsigned int size)
    00124 {
    00125         while (size)
    00126         {
    00127                 // on some systems /dev/random will block until all bytes
    00128                 // are available, on others it will returns immediately
    00129                 int len = read(m_fd, output, STDMIN(size, (unsigned int)INT_MAX));
    00130                 if (len == -1)
    00131                         throw OS_RNG_Err("read /dev/random");
    00132                 size -= len;
    00133                 output += len;
    00134                 if (size)
    00135                         sleep(1);
    00136         }
    00137 }
    00138
    00139 #endif
    00140
    00141 // *************************************************************
    00142
    00143 void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size)
    00144 {
    00145 #ifdef NONBLOCKING_RNG_AVAILABLE
    00146         if (blocking)
    00147 #endif
    00148         {
    00149 #ifdef BLOCKING_RNG_AVAILABLE
    00150                 BlockingRng rng;
    00151                 rng.GenerateBlock(output, size);
    00152 #endif
    00153         }
    00154
    00155 #ifdef BLOCKING_RNG_AVAILABLE
    00156         if (!blocking)
    00157 #endif
    00158         {
    00159 #ifdef NONBLOCKING_RNG_AVAILABLE
    00160                 NonblockingRng rng;
    00161                 rng.GenerateBlock(output, size);
    00162 #endif
    00163         }
    00164 }
    00165
    00166 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
    00167 {
    00168         SecByteBlock seed(seedSize);
    00169         OS_GenerateRandomBlock(blocking, seed, seedSize);
    00170         Put(seed, seedSize);
    00171 }
    00172
    00173 NAMESPACE_END
    00174
    00175 #endif
    00176
    00177 #endif