From b605b5033b01f817fe37b2daa2e9e20ea8491092 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Tue, 3 Oct 2017 15:58:10 -0400 Subject: [PATCH] auth: add CryptoRandom wrapper for random impl Signed-off-by: Casey Bodley --- src/auth/Crypto.cc | 67 +++++++++++++++++++------------- src/auth/Crypto.h | 16 ++++++-- src/auth/cephx/CephxKeyServer.cc | 2 +- src/test/crypto.cc | 27 ++++++------- 4 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/auth/Crypto.cc b/src/auth/Crypto.cc index 0186b7b2255d6..22a53509d89e8 100644 --- a/src/auth/Crypto.cc +++ b/src/auth/Crypto.cc @@ -35,32 +35,49 @@ #include "common/debug.h" #include -int get_random_bytes(char *buf, int len) +// use getentropy() if available. it uses the same source of randomness +// as /dev/urandom without the filesystem overhead +#ifdef HAVE_GETENTROPY + +#include + +CryptoRandom::CryptoRandom() : fd(0) {} +CryptoRandom::~CryptoRandom() = default; + +void CryptoRandom::get_bytes(char *buf, int len) { - int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY)); - if (fd < 0) - return -errno; - int ret = safe_read_exact(fd, buf, len); - VOID_TEMP_FAILURE_RETRY(::close(fd)); - return ret; + auto ret = TEMP_FAILURE_RETRY(::getentropy(buf, len)); + if (ret < 0) { + throw std::system_error(errno, std::system_category()); + } } -static int get_random_bytes(int len, bufferlist& bl) +#else // !HAVE_GETENTROPY + +// open /dev/urandom once on construction and reuse the fd for all reads +CryptoRandom::CryptoRandom() + : fd(TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY))) { - char buf[len]; - get_random_bytes(buf, len); - bl.append(buf, len); - return 0; + if (fd < 0) { + throw std::system_error(errno, std::system_category()); + } } -uint64_t get_random(uint64_t min_val, uint64_t max_val) +CryptoRandom::~CryptoRandom() { - uint64_t r; - get_random_bytes((char *)&r, sizeof(r)); - r = min_val + r % (max_val - min_val + 1); - return r; + VOID_TEMP_FAILURE_RETRY(::close(fd)); } +void CryptoRandom::get_bytes(char *buf, int len) +{ + auto ret = safe_read_exact(fd, buf, len); + if (ret < 0) { + throw std::system_error(-ret, std::system_category()); + } +} + +#endif + // --------------------------------------------------- @@ -85,7 +102,7 @@ public: int get_type() const override { return CEPH_CRYPTO_NONE; } - int create(bufferptr& secret) override { + int create(CryptoRandom *random, bufferptr& secret) override { return 0; } int validate_secret(const bufferptr& secret) override { @@ -107,7 +124,7 @@ public: int get_type() const override { return CEPH_CRYPTO_AES; } - int create(bufferptr& secret) override; + int create(CryptoRandom *random, bufferptr& secret) override; int validate_secret(const bufferptr& secret) override; CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override; }; @@ -329,13 +346,11 @@ public: // ------------------------------------------------------------ -int CryptoAES::create(bufferptr& secret) +int CryptoAES::create(CryptoRandom *random, bufferptr& secret) { - bufferlist bl; - int r = get_random_bytes(AES_KEY_LEN, bl); - if (r < 0) - return r; - secret = buffer::ptr(bl.c_str(), bl.length()); + bufferptr buf(AES_KEY_LEN); + random->get_bytes(buf.c_str(), buf.length()); + secret = std::move(buf); return 0; } @@ -438,7 +453,7 @@ int CryptoKey::create(CephContext *cct, int t) return -EOPNOTSUPP; } bufferptr s; - int r = ch->create(s); + int r = ch->create(nullptr, s); // fixme delete ch; if (r < 0) return r; diff --git a/src/auth/Crypto.h b/src/auth/Crypto.h index 1c47f6efad195..318a4bd3a2731 100644 --- a/src/auth/Crypto.h +++ b/src/auth/Crypto.h @@ -26,6 +26,18 @@ class CephContext; class CryptoKeyContext; namespace ceph { class Formatter; } +/* + * Random byte stream generator suitable for cryptographic use + */ +class CryptoRandom { + const int fd; + public: + CryptoRandom(); // throws on failure + ~CryptoRandom(); + + /// copy up to 256 random bytes into the given buffer. throws on failure + void get_bytes(char *buf, int len); +}; /* * some per-key context that is specific to a particular crypto backend @@ -136,7 +148,7 @@ class CryptoHandler { public: virtual ~CryptoHandler() {} virtual int get_type() const = 0; - virtual int create(bufferptr& secret) = 0; + virtual int create(CryptoRandom *random, bufferptr& secret) = 0; virtual int validate_secret(const bufferptr& secret) = 0; virtual CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) = 0; @@ -144,7 +156,5 @@ public: static CryptoHandler *create(int type); }; -extern int get_random_bytes(char *buf, int len); -extern uint64_t get_random(uint64_t min_val, uint64_t max_val); #endif diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc index e06de6602eba2..db73266b8c96a 100644 --- a/src/auth/cephx/CephxKeyServer.cc +++ b/src/auth/cephx/CephxKeyServer.cc @@ -264,7 +264,7 @@ bool KeyServer::generate_secret(CryptoKey& secret) if (!crypto) return false; - if (crypto->create(bp) < 0) + if (crypto->create(nullptr, bp) < 0) // fixme return false; secret.set_secret(CEPH_CRYPTO_AES, bp, ceph_clock_now()); diff --git a/src/test/crypto.cc b/src/test/crypto.cc index df09b7d5dfcf4..3e459ea01d483 100644 --- a/src/test/crypto.cc +++ b/src/test/crypto.cc @@ -116,19 +116,16 @@ TEST(AES, Decrypt) { } TEST(AES, Loop) { - int err; + CryptoRandom random; - char secret_s[16]; - err = get_random_bytes(secret_s, sizeof(secret_s)); - ASSERT_EQ(0, err); - bufferptr secret(secret_s, sizeof(secret_s)); + bufferptr secret(16); + random.get_bytes(secret.c_str(), secret.length()); - char orig_plaintext_s[1024]; - err = get_random_bytes(orig_plaintext_s, sizeof(orig_plaintext_s)); - ASSERT_EQ(0, err); + bufferptr orig_plaintext(1024); + random.get_bytes(orig_plaintext.c_str(), orig_plaintext.length()); bufferlist plaintext; - plaintext.append(orig_plaintext_s, sizeof(orig_plaintext_s)); + plaintext.append(orig_plaintext.c_str(), orig_plaintext.length()); for (int i=0; i<10000; i++) { bufferlist cipher; @@ -157,20 +154,20 @@ TEST(AES, Loop) { } } - char plaintext_s[sizeof(orig_plaintext_s)]; - plaintext.copy(0, sizeof(plaintext_s), &plaintext_s[0]); - err = memcmp(plaintext_s, orig_plaintext_s, sizeof(orig_plaintext_s)); - ASSERT_EQ(0, err); + bufferlist orig; + orig.append(orig_plaintext); + ASSERT_EQ(orig, plaintext); } TEST(AES, LoopKey) { + CryptoRandom random; bufferptr k(16); - get_random_bytes(k.c_str(), k.length()); + random.get_bytes(k.c_str(), k.length()); CryptoKey key(CEPH_CRYPTO_AES, ceph_clock_now(), k); bufferlist data; bufferptr r(128); - get_random_bytes(r.c_str(), r.length()); + random.get_bytes(r.c_str(), r.length()); data.append(r); utime_t start = ceph_clock_now(); -- 2.39.5