1// osrng.cpp - written and placed in the public domain by Wei Dai 2 3// Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool. 4 5#include "pch.h" 6 7#ifndef CRYPTOPP_IMPORTS 8 9#include "osrng.h" 10 11#ifdef OS_RNG_AVAILABLE 12 13#include "rng.h" 14 15#ifdef CRYPTOPP_WIN32_AVAILABLE 16#ifndef _WIN32_WINNT 17#define _WIN32_WINNT 0x0400 18#endif 19#include <windows.h> 20#include <wincrypt.h> 21#endif 22 23#ifdef CRYPTOPP_UNIX_AVAILABLE 24#include <errno.h> 25#include <fcntl.h> 26#include <unistd.h> 27#endif 28 29NAMESPACE_BEGIN(CryptoPP) 30 31#if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE) 32OS_RNG_Err::OS_RNG_Err(const std::string &operation) 33 : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " + 34#ifdef CRYPTOPP_WIN32_AVAILABLE 35 "0x" + IntToString(GetLastError(), 16) 36#else 37 IntToString(errno) 38#endif 39 ) 40{ 41} 42#endif 43 44#ifdef NONBLOCKING_RNG_AVAILABLE 45 46#ifdef CRYPTOPP_WIN32_AVAILABLE 47 48MicrosoftCryptoProvider::MicrosoftCryptoProvider() 49{ 50 if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 51 throw OS_RNG_Err("CryptAcquireContext"); 52} 53 54MicrosoftCryptoProvider::~MicrosoftCryptoProvider() 55{ 56 CryptReleaseContext(m_hProvider, 0); 57} 58 59#endif 60 61NonblockingRng::NonblockingRng() 62{ 63#ifndef CRYPTOPP_WIN32_AVAILABLE 64 m_fd = open("/dev/urandom",O_RDONLY); 65 if (m_fd == -1) 66 throw OS_RNG_Err("open /dev/urandom"); 67#endif 68} 69 70NonblockingRng::~NonblockingRng() 71{ 72#ifndef CRYPTOPP_WIN32_AVAILABLE 73 close(m_fd); 74#endif 75} 76 77void NonblockingRng::GenerateBlock(byte *output, size_t size) 78{ 79#ifdef CRYPTOPP_WIN32_AVAILABLE 80# ifdef WORKAROUND_MS_BUG_Q258000 81 const MicrosoftCryptoProvider &m_Provider = Singleton<MicrosoftCryptoProvider>().Ref(); 82# endif 83 if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output)) 84 throw OS_RNG_Err("CryptGenRandom"); 85#else 86 if (read(m_fd, output, size) != size) 87 throw OS_RNG_Err("read /dev/urandom"); 88#endif 89} 90 91#endif 92 93// ************************************************************* 94 95#ifdef BLOCKING_RNG_AVAILABLE 96 97#ifndef CRYPTOPP_BLOCKING_RNG_FILENAME 98#ifdef __OpenBSD__ 99#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom" 100#else 101#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random" 102#endif 103#endif 104 105BlockingRng::BlockingRng() 106{ 107 m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY); 108 if (m_fd == -1) 109 throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME); 110} 111 112BlockingRng::~BlockingRng() 113{ 114 close(m_fd); 115} 116 117void BlockingRng::GenerateBlock(byte *output, size_t size) 118{ 119 while (size) 120 { 121 // on some systems /dev/random will block until all bytes 122 // are available, on others it will returns immediately 123 ssize_t len = read(m_fd, output, size); 124 if (len < 0) 125 throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME); 126 size -= len; 127 output += len; 128 if (size) 129 sleep(1); 130 } 131} 132 133#endif 134 135// ************************************************************* 136 137void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size) 138{ 139#ifdef NONBLOCKING_RNG_AVAILABLE 140 if (blocking) 141#endif 142 { 143#ifdef BLOCKING_RNG_AVAILABLE 144 BlockingRng rng; 145 rng.GenerateBlock(output, size); 146#endif 147 } 148 149#ifdef BLOCKING_RNG_AVAILABLE 150 if (!blocking) 151#endif 152 { 153#ifdef NONBLOCKING_RNG_AVAILABLE 154 NonblockingRng rng; 155 rng.GenerateBlock(output, size); 156#endif 157 } 158} 159 160void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize) 161{ 162 SecByteBlock seed(seedSize); 163 OS_GenerateRandomBlock(blocking, seed, seedSize); 164 IncorporateEntropy(seed, seedSize); 165} 166 167NAMESPACE_END 168 169#endif 170 171#endif 172