libkea_cryptolink_la_SOURCES = cryptolink.h cryptolink.cc
libkea_cryptolink_la_SOURCES += crypto_hash.h crypto_hash.cc
libkea_cryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
+libkea_cryptolink_la_SOURCES += crypto_rng.h crypto_rng.cc
if HAVE_BOTAN1
libkea_cryptolink_la_SOURCES += botan1_link.cc
libkea_cryptolink_la_SOURCES += botan_common.h
#include <cryptolink/cryptolink.h>
#include <cryptolink/crypto_hash.h>
#include <cryptolink/crypto_hmac.h>
+#include <cryptolink/crypto_rng.h>
#include <botan/botan.h>
#include <botan/init.h>
+#include <botan/auto_rng.h>
namespace isc {
namespace cryptolink {
};
CryptoLink::~CryptoLink() {
+ rng_.reset();
delete impl_;
}
+/// \brief Botan implementation of RNG.
+class RNGImpl : public RNG {
+public:
+ RNGImpl() {
+ rng.reset(new Botan::AutoSeeded_RNG());
+ }
+
+ ~RNGImpl() {
+ }
+
+private:
+ std::vector<uint8_t> random(size_t len) {
+ std::vector<uint8_t> data;
+ if (len > 0) {
+ data.resize(len);
+ try {
+ rng->randomize(&data[0], len);
+ } catch (const Botan::Exception& ex) {
+ isc_throw(isc::cryptolink::LibraryError,
+ "Botan error: " << ex.what());
+ }
+ }
+ return (data);
+ }
+
+ boost::shared_ptr<Botan::RandomNumberGenerator> rng;
+};
+
void
CryptoLink::initialize() {
CryptoLink& c = getCryptoLinkInternal();
- if (c.impl_ == NULL) {
+ if (!c.impl_) {
try {
c.impl_ = new CryptoLinkImpl();
} catch (const Botan::Exception& ex) {
isc_throw(InitializationError, "Botan error: " << ex.what());
}
}
+ if (!c.rng_) {
+ try {
+ c.rng_.reset(new RNGImpl());
+ } catch (const Botan::Exception& ex) {
+ isc_throw(InitializationError, "Botan error: " << ex.what());
+ }
+ }
}
std::string
#include <cryptolink/cryptolink.h>
#include <cryptolink/crypto_hash.h>
#include <cryptolink/crypto_hmac.h>
+#include <cryptolink/crypto_rng.h>
#include <botan/exceptn.h>
#include <botan/version.h>
+#include <botan/auto_rng.h>
namespace isc {
namespace cryptolink {
delete impl_;
}
+/// \brief Botan implementation of RNG.
+class RNGImpl : public RNG {
+public:
+ RNGImpl() {
+ rng.reset(new Botan::AutoSeeded_RNG());
+ }
+
+ ~RNGImpl() {
+ }
+
+private:
+ std::vector<uint8_t> random(size_t len) {
+ std::vector<uint8_t> data;
+ if (len > 0) {
+ data.resize(len);
+ try {
+ rng->randomize(&data[0], len);
+ } catch (const Botan::Exception& ex) {
+ isc_throw(isc::cryptolink::LibraryError,
+ "Botan error: " << ex.what());
+ }
+ }
+ return (data);
+ }
+
+ boost::shared_ptr<Botan::RandomNumberGenerator> rng;
+};
+
void
CryptoLink::initialize() {
CryptoLink& c = getCryptoLinkInternal();
- if (c.impl_ == NULL) {
+ if (!c.impl_) {
try {
c.impl_ = new CryptoLinkImpl();
} catch (const Botan::Exception& ex) {
isc_throw(InitializationError, "Botan error: " << ex.what());
}
}
+ if (!c.rng_) {
+ try {
+ c.rng_.reset(new RNGImpl());
+ } catch (const Botan::Exception& ex) {
+ isc_throw(InitializationError, "Botan error: " << ex.what());
+ }
+ }
+ // A not yet fixed bug makes RNG to be destroyed after memory pool...
+ atexit([]{ getCryptoLink().getRNG().reset(); });
}
std::string
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_rng.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <cstring>
+
+namespace isc {
+namespace cryptolink {
+
+RNG::RNG() {
+}
+
+RNG::~RNG() {
+}
+
+std::vector<uint8_t>
+random(size_t len)
+{
+ RNGPtr rng(CryptoLink::getCryptoLink().getRNG());
+ return (rng->random(len));
+}
+
+} // namespace cryptolink
+} // namespace isc
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/cryptolink.h>
+
+#ifndef ISC_CRYPTO_RNG_H
+#define ISC_CRYPTO_RNG_H
+
+namespace isc {
+namespace cryptolink {
+
+/// \brief RNG support
+///
+/// This class is used to get the RNG.
+/// The global instance can be get with CryptoLink::getRNG()
+///
+class RNG : private boost::noncopyable {
+public:
+ /// \brief Constructor from a Random Number Generator
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ RNG();
+
+ /// \brief Destructor
+ virtual ~RNG();
+
+ /// \brief Generate random value.
+ ///
+ /// The result will be returned as a std::vector<uint8_t>
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param len The number of bytes from the result to generate.
+ /// \return a vector containing random value.
+ virtual std::vector<uint8_t> random(size_t len) = 0;
+
+private:
+ friend RNGPtr& CryptoLink::getRNG();
+};
+
+/// \brief Generate random value.
+///
+/// This is a convenience function that generate random data
+/// given a fixed amount of data. Internally it does the same as
+/// creating an RNG object and generating the resulting value.
+///
+/// \exception LibraryError if there was any unexpected exception
+/// in the underlying library
+///
+/// \param len The length of the data
+std::vector<uint8_t> random(size_t len);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // ISC_CRYPTO_RNG_H
+
return (new HMAC(secret, secret_len, hash_algorithm));
}
+RNGPtr&
+CryptoLink::getRNG() {
+ return (rng_);
+}
+
} // namespace cryptolink
} // namespace isc
#include <exceptions/exceptions.h>
#include <boost/noncopyable.hpp>
-#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
#include <memory>
// Forward declaration for createHMAC()
class HMAC;
+// Forward declaration for getRNG()
+class RNG;
+typedef boost::shared_ptr<RNG> RNGPtr;
+
/// General exception class that is the base for all crypto-related
/// exceptions
class CryptoLinkError : public Exception {
CryptoLinkError(file, line, what) {}
};
-/// Forward declaration for pimpl
+/// Forward declarations for pimpl
class CryptoLinkImpl;
+class RNGImpl;
/// \brief Singleton entry point and factory class
///
HMAC* createHMAC(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm);
+ /// \brief Get the global RNG
+ ///
+ /// \exception NotImplemented if the method was not implemented
+ /// in a derived class
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ virtual RNGPtr& getRNG();
+
private:
// To enable us to use an optional explicit initialization call,
// the 'real' instance getter is private
~CryptoLink();
CryptoLinkImpl* impl_;
+
+ RNGPtr rng_;
};
} // namespace cryptolink
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <config.h>
#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_rng.h>
#include <cryptolink/crypto_hash.h>
#include <cryptolink/crypto_hmac.h>
#include <openssl/crypto.h>
+#include <openssl/rand.h>
namespace isc {
namespace cryptolink {
// For OpenSSL, we use the CryptoLink class object in RAII style
class CryptoLinkImpl {
- // empty class
};
CryptoLink::~CryptoLink() {
delete impl_;
}
+/// \brief OpenSSL implementation of RNG.
+class RNGImpl : public RNG {
+public:
+ RNGImpl() { }
+
+ ~RNGImpl() { }
+
+private:
+ std::vector<uint8_t> random(size_t len) {
+ std::vector<uint8_t> data;
+ if (len > 0) {
+ data.resize(len);
+ if (RAND_bytes(&data[0], len) != 1) {
+ isc_throw(isc::cryptolink::LibraryError,
+ "OpenSSL RAND_bytes() failed");
+ }
+ }
+ return (data);
+ }
+};
+
void
CryptoLink::initialize() {
CryptoLink& c = getCryptoLinkInternal();
- if (c.impl_ == NULL) {
+ if (!c.impl_) {
try {
c.impl_ = new CryptoLinkImpl();
} catch (const std::exception &ex) {
"Error during OpenSSL initialization");
}
}
+ if (!c.rng_) {
+ try {
+ c.rng_.reset(new RNGImpl());
+ } catch (const std::exception &ex) {
+ // Should never happen
+ isc_throw(InitializationError,
+ "Error during OpenSSL RNG initialization:" << ex.what());
+ } catch (...) {
+ // Should never happen
+ isc_throw(InitializationError,
+ "Error during OpenSSL RNG initialization");
+ }
+ }
}
std::string
} // namespace cryptolink
} // namespace isc
-
#include <util/encode/hex.h>
#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_rng.h>
+using namespace std;
using namespace isc::cryptolink;
// Test get version
const CryptoLink& c2 = CryptoLink::getCryptoLink();
ASSERT_EQ(&c1, &c2);
}
+
+// Tests whether getRNG() returns a global value
+TEST(CryptoLinkTest, GlobalRNG) {
+ CryptoLink& c = CryptoLink::getCryptoLink();
+ RNGPtr rng1 = c.getRNG();
+ RNGPtr rng2 = c.getRNG();
+ ASSERT_EQ(rng1, rng2);
+}
+
+// Tests whether RNG works
+TEST(CryptoLinkTest, RNG) {
+ RNGPtr rng = CryptoLink::getCryptoLink().getRNG();
+ vector<uint8_t> data;
+ ASSERT_NO_THROW(data = rng->random(16));
+ ASSERT_EQ(16, data.size());
+ vector<uint8_t> zero;
+ zero.resize(16);
+ EXPECT_NE(0, memcmp(&zero[0], &data[0], zero.size()));
+
+ // Retry with the function (vs method)
+ vector<uint8_t> dataf;
+ ASSERT_NO_THROW(dataf = random(16));
+ ASSERT_EQ(16, dataf.size());
+ EXPECT_NE(0, memcmp(&zero[0], &dataf[0], zero.size()));
+ EXPECT_NE(0, memcmp(&data[0], &dataf[0], zero.size()));
+}