summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordon bright <hugh.m.bright@gmail.com>2013-01-06 05:31:41 (GMT)
committerdon bright <hugh.m.bright@gmail.com>2013-01-06 05:31:41 (GMT)
commit84c6d45eaac2d04d4e855dddb88bb208e531451e (patch)
tree7113384f7192686c38f1ebb67eea6e6f9ba6efad /src
parentf40b6a672aa4c0a3df2165ffaaac49b9a8d935e7 (diff)
experimental workaround for boost linker problems w random_device
Diffstat (limited to 'src')
-rw-r--r--src/random_device.cpp217
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();
+}
contact: Jan Huwald // Impressum