]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
auth: add CryptoRandom wrapper for random impl
authorCasey Bodley <cbodley@redhat.com>
Tue, 3 Oct 2017 19:58:10 +0000 (15:58 -0400)
committerCasey Bodley <cbodley@redhat.com>
Mon, 9 Oct 2017 14:42:25 +0000 (10:42 -0400)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/auth/Crypto.cc
src/auth/Crypto.h
src/auth/cephx/CephxKeyServer.cc
src/test/crypto.cc

index 0186b7b2255d670a218a8883751472164be403b9..22a53509d89e847fdc98dd9b111ef29ee78f4982 100644 (file)
 #include "common/debug.h"
 #include <errno.h>
 
-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 <unistd.h>
+
+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;
index 1c47f6efad195c1bc46b1ae0842110a4c07d55d0..318a4bd3a27313ea45294ea3c6a153cdcb016f3f 100644 (file)
@@ -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
index e06de6602eba2a38ad16cbdaaf786df422ba86fe..db73266b8c96a325ca0badecd48b221252e2b134 100644 (file)
@@ -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());
index df09b7d5dfcf431691d74194404a665893127219..3e459ea01d483bab9e9d47e0b5e3e0abff012f42 100644 (file)
@@ -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();