ext-cryptopp/osrng.cpp

193 lines
3.7 KiB
C++
Raw Normal View History

2002-10-04 17:31:41 +00:00
// osrng.cpp - written and placed in the public domain by Wei Dai
// Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
2002-10-04 17:31:41 +00:00
#include "osrng.h"
#ifdef OS_RNG_AVAILABLE
#include "rng.h"
#ifdef CRYPTOPP_WIN32_AVAILABLE
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <wincrypt.h>
2002-10-04 21:45:04 +00:00
#endif
#ifdef CRYPTOPP_UNIX_AVAILABLE
2002-10-04 17:31:41 +00:00
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#endif
NAMESPACE_BEGIN(CryptoPP)
#if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
OS_RNG_Err::OS_RNG_Err(const std::string &operation)
: Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
#ifdef CRYPTOPP_WIN32_AVAILABLE
"0x" + IntToString(GetLastError(), 16)
#else
IntToString(errno)
#endif
)
{
}
#endif
#ifdef NONBLOCKING_RNG_AVAILABLE
#ifdef CRYPTOPP_WIN32_AVAILABLE
MicrosoftCryptoProvider::MicrosoftCryptoProvider()
{
if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
throw OS_RNG_Err("CryptAcquireContext");
}
MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
{
CryptReleaseContext(m_hProvider, 0);
}
#endif
NonblockingRng::NonblockingRng()
{
#ifndef CRYPTOPP_WIN32_AVAILABLE
m_fd = open("/dev/urandom",O_RDONLY);
if (m_fd == -1)
throw OS_RNG_Err("open /dev/urandom");
#endif
}
NonblockingRng::~NonblockingRng()
{
#ifndef CRYPTOPP_WIN32_AVAILABLE
close(m_fd);
#endif
}
2005-07-12 04:23:32 +00:00
void NonblockingRng::GenerateBlock(byte *output, size_t size)
2002-10-04 17:31:41 +00:00
{
#ifdef CRYPTOPP_WIN32_AVAILABLE
# ifdef WORKAROUND_MS_BUG_Q258000
2007-02-03 13:29:09 +00:00
const MicrosoftCryptoProvider &m_Provider = Singleton<MicrosoftCryptoProvider>().Ref();
2002-10-04 17:31:41 +00:00
# endif
2005-07-12 04:23:32 +00:00
if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
2002-10-04 17:31:41 +00:00
throw OS_RNG_Err("CryptGenRandom");
#else
while (size)
{
ssize_t len = read(m_fd, output, size);
if (len < 0)
{
// /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well)
if (errno != EINTR && errno != EAGAIN)
throw OS_RNG_Err("read /dev/urandom");
continue;
}
output += len;
size -= len;
}
2002-10-04 17:31:41 +00:00
#endif
}
#endif
// *************************************************************
#ifdef BLOCKING_RNG_AVAILABLE
2006-12-13 04:08:09 +00:00
#ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
#ifdef __OpenBSD__
#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
#else
#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
#endif
#endif
2002-10-04 17:31:41 +00:00
BlockingRng::BlockingRng()
{
2006-12-13 04:08:09 +00:00
m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
2002-10-04 17:31:41 +00:00
if (m_fd == -1)
2006-12-13 04:08:09 +00:00
throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
2002-10-04 17:31:41 +00:00
}
BlockingRng::~BlockingRng()
{
close(m_fd);
}
2005-07-12 04:23:32 +00:00
void BlockingRng::GenerateBlock(byte *output, size_t size)
2002-10-04 17:31:41 +00:00
{
while (size)
{
// on some systems /dev/random will block until all bytes
// are available, on others it returns immediately
2005-09-05 21:43:43 +00:00
ssize_t len = read(m_fd, output, size);
if (len < 0)
{
// /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well)
if (errno != EINTR && errno != EAGAIN)
throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
continue;
}
2002-10-04 17:31:41 +00:00
size -= len;
output += len;
if (size)
sleep(1);
}
}
#endif
// *************************************************************
2005-07-12 04:23:32 +00:00
void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
2002-10-04 17:31:41 +00:00
{
#ifdef NONBLOCKING_RNG_AVAILABLE
if (blocking)
#endif
{
#ifdef BLOCKING_RNG_AVAILABLE
BlockingRng rng;
rng.GenerateBlock(output, size);
#endif
}
#ifdef BLOCKING_RNG_AVAILABLE
if (!blocking)
#endif
{
#ifdef NONBLOCKING_RNG_AVAILABLE
NonblockingRng rng;
rng.GenerateBlock(output, size);
#endif
}
}
void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
{
SecByteBlock seed(seedSize);
OS_GenerateRandomBlock(blocking, seed, seedSize);
IncorporateEntropy(seed, seedSize);
2002-10-04 17:31:41 +00:00
}
NAMESPACE_END
#endif
#endif