Commit 9e742d30 authored by Francis Dupont's avatar Francis Dupont
Browse files

[29-cryptolink-random-generator] Added RNG support

parent 110214b5
......@@ -11,6 +11,7 @@ lib_LTLIBRARIES = libkea-cryptolink.la
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
......
......@@ -9,9 +9,11 @@
#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 {
......@@ -23,19 +25,55 @@ private:
};
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
......
......@@ -9,9 +9,11 @@
#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 {
......@@ -25,16 +27,53 @@ CryptoLink::~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
......
// 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
// 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
......@@ -41,6 +41,11 @@ CryptoLink::createHMAC(const void* secret, size_t secret_len,
return (new HMAC(secret, secret_len, hash_algorithm));
}
RNGPtr&
CryptoLink::getRNG() {
return (rng_);
}
} // namespace cryptolink
} // namespace isc
......@@ -12,7 +12,7 @@
#include <exceptions/exceptions.h>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
......@@ -42,6 +42,10 @@ class Hash;
// 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 {
......@@ -84,8 +88,9 @@ public:
CryptoLinkError(file, line, what) {}
};
/// Forward declaration for pimpl
/// Forward declarations for pimpl
class CryptoLinkImpl;
class RNGImpl;
/// \brief Singleton entry point and factory class
///
......@@ -209,6 +214,14 @@ public:
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
......@@ -220,6 +233,8 @@ 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
......@@ -7,27 +7,49 @@
#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) {
......@@ -40,6 +62,19 @@ CryptoLink::initialize() {
"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
......@@ -49,4 +84,3 @@ CryptoLink::getVersion() {
} // namespace cryptolink
} // namespace isc
......@@ -11,7 +11,9 @@
#include <util/encode/hex.h>
#include <cryptolink/cryptolink.h>
#include <cryptolink/crypto_rng.h>
using namespace std;
using namespace isc::cryptolink;
// Test get version
......@@ -25,3 +27,29 @@ TEST(CryptoLinkTest, Singleton) {
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()));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment