diff options
author | don bright <hugh.m.bright@gmail.com> | 2013-01-06 05:31:41 (GMT) |
---|---|---|
committer | don bright <hugh.m.bright@gmail.com> | 2013-01-06 05:31:41 (GMT) |
commit | 84c6d45eaac2d04d4e855dddb88bb208e531451e (patch) | |
tree | 7113384f7192686c38f1ebb67eea6e6f9ba6efad /src | |
parent | f40b6a672aa4c0a3df2165ffaaac49b9a8d935e7 (diff) |
experimental workaround for boost linker problems w random_device
Diffstat (limited to 'src')
-rw-r--r-- | src/random_device.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/random_device.cpp b/src/random_device.cpp new file mode 100644 index 0000000..699a880 --- /dev/null +++ b/src/random_device.cpp @@ -0,0 +1,217 @@ +/* boost random_device.cpp implementation + * + * Copyright Jens Maurer 2000 + * Copyright Steven Watanabe 2010-2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: random_device.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#define BOOST_RANDOM_SOURCE + +#include <boost/random/random_device.hpp> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <string> + +#if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) +// A definition is required even for integral static constants +const bool boost::random::random_device::has_fixed_range; +#endif + + +#if defined(BOOST_WINDOWS) + +#include <windows.h> +#include <wincrypt.h> +#include <stdexcept> // std::invalid_argument + +#define BOOST_AUTO_LINK_NOMANGLE +#define BOOST_LIB_NAME "Advapi32" +#include <boost/config/auto_link.hpp> + +#ifdef __MINGW32__ + +extern "C" { + +// mingw's wincrypt.h appears to be missing some things +WINADVAPI +BOOL +WINAPI +CryptEnumProvidersA( + DWORD dwIndex, + DWORD *pdwReserved, + DWORD dwFlags, + DWORD *pdwProvType, + LPSTR szProvName, + DWORD *pcbProvName + ); + +} + +#endif + +namespace { + +const char * const default_token = MS_DEF_PROV_A; + +} + +class boost::random::random_device::impl +{ +public: + impl(const std::string & token) : provider(token) { + char buffer[80]; + DWORD type; + DWORD len; + + // Find the type of the provider + for(DWORD i = 0; ; ++i) { + len = sizeof(buffer); + if(!CryptEnumProvidersA(i, NULL, 0, &type, buffer, &len)) { + error("Could not find provider name"); + } + if(buffer == provider) { + break; + } + } + + if(!CryptAcquireContextA(&hProv, NULL, provider.c_str(), type, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + error("Could not acquire CSP context"); + } + } + + ~impl() { + if(!CryptReleaseContext(hProv, 0)) error("Could not release CSP context"); + } + + unsigned int next() { + unsigned int result; + + if(!CryptGenRandom(hProv, sizeof(result), + static_cast<BYTE*>(static_cast<void*>(&result)))) { + error("error while reading"); + } + + return result; + } + +private: + void error(const std::string & msg) { + char buf[80]; + DWORD num = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, + buf, + sizeof(buf), + NULL); + + throw std::invalid_argument("boost::random_device: " + msg + + " Cryptopraphic Service Provider " + provider + + ": " + std::string(&buf[0], &buf[0] + num)); + } + const std::string provider; + HCRYPTPROV hProv; +}; + +#else + +namespace { +// the default is the unlimited capacity device, using some secure hash +// try "/dev/random" for blocking when the entropy pool has drained +const char * const default_token = "/dev/urandom"; +} + +/* + * This uses the POSIX interface for unbuffered reading. + * Using buffered std::istream would consume entropy which may + * not actually be used. Entropy is a precious good we avoid + * wasting. + */ + +#if defined(__GNUC__) && defined(_CXXRT_STD_NAME) +// I have severe difficulty to get the POSIX includes to work with +// -fhonor-std and Dietmar Kuhl's standard C++ library. Hack around that +// problem for now. +extern "C" { +static const int O_RDONLY = 0; +extern int open(const char *__file, int __oflag, ...); +extern int read(int __fd, __ptr_t __buf, size_t __nbytes); +extern int close(int __fd); +} +#else +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> // open +#include <unistd.h> // read, close +#endif + +#include <errno.h> // errno +#include <string.h> // strerror +#include <stdexcept> // std::invalid_argument + + +class boost::random::random_device::impl +{ +public: + impl(const std::string & token) : path(token) { + fd = open(token.c_str(), O_RDONLY); + if(fd < 0) + error("cannot open"); + } + + ~impl() { if(close(fd) < 0) error("could not close"); } + + unsigned int next() { + unsigned int result; + long sz = read(fd, reinterpret_cast<char *>(&result), sizeof(result)); + if(sz == -1) + error("error while reading"); + else if(sz != sizeof(result)) { + errno = 0; + error("EOF while reading"); + } + return result; + } + +private: + void error(const std::string & msg) { + throw std::invalid_argument("boost::random_device: " + msg + + " random-number pseudo-device " + path + + ": " + strerror(errno)); + } + const std::string path; + int fd; +}; + +#endif // BOOST_WINDOWS + +BOOST_RANDOM_DECL boost::random::random_device::random_device() + : pimpl(new impl(default_token)) +{} + +BOOST_RANDOM_DECL boost::random::random_device::random_device(const std::string& token) + : pimpl(new impl(token)) +{} + +BOOST_RANDOM_DECL boost::random_device::~random_device() +{ + delete pimpl; +} + +BOOST_RANDOM_DECL double boost::random_device::entropy() const +{ + return 10; +} + +BOOST_RANDOM_DECL unsigned int boost::random_device::operator()() +{ + return pimpl->next(); +} |