]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Always hash crypto_strongest_rand() along with some prng
authorNick Mathewson <nickm@torproject.org>
Tue, 8 Dec 2015 15:54:42 +0000 (10:54 -0500)
committerNick Mathewson <nickm@torproject.org>
Tue, 8 Dec 2015 15:54:42 +0000 (10:54 -0500)
(before using it for anything besides feeding the PRNG)

Part of #17694

changes/bug17694_strongest [new file with mode: 0644]
src/common/crypto.c
src/common/crypto.h
src/common/crypto_curve25519.c
src/common/crypto_ed25519.c
src/ext/ed25519/donna/ed25519_tor.c
src/ext/ed25519/ref10/randombytes.h

diff --git a/changes/bug17694_strongest b/changes/bug17694_strongest
new file mode 100644 (file)
index 0000000..0a8954a
--- /dev/null
@@ -0,0 +1,6 @@
+  o Minor features (security):
+    - Never use the system entropy output directly for anything besides
+      seeding the PRNG.  When we want to generate important keys, instead
+      of using system entropy directly, hash it with the PRNG stream.
+      This may help resist certain attacks based on broken OS entropy
+      implementations. Closes part of ticket 17694.
\ No newline at end of file
index 9669493a83e260d8ae33d89f000d51919e61e389..675fe7a8f07d873543e16834523aefd83cbaa90f 100644 (file)
@@ -2280,10 +2280,13 @@ crypto_seed_weak_rng(tor_weak_rng_t *rng)
 }
 
 /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
- * storing it into <b>out</b>.
+ * storing it into <b>out</b>.  Return 0 on success, -1 on failure.
+ *
+ * (You should almost never call this directly unless you are seeding a PRNG;
+ * use crypto_strongest_rand() instead.)
  */
-int
-crypto_strongest_rand(uint8_t *out, size_t out_len)
+static int
+crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
 {
 #ifdef _WIN32
   static int provider_set = 0;
@@ -2334,6 +2337,41 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
 #endif
 }
 
+/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * storing it into <b>out</b>.
+ */
+void
+crypto_strongest_rand(uint8_t *out, size_t out_len)
+{
+  const unsigned DLEN = SHA512_DIGEST_LENGTH;
+  uint8_t inp[DLEN*2];
+  uint8_t tmp[DLEN];
+  tor_assert(out);
+  while (out_len) {
+    crypto_rand((char*) inp+DLEN, DLEN);
+    if (crypto_strongest_rand_raw(inp, DLEN) < 0) {
+      log_err(LD_CRYPTO, "Failed to load strong entropy when generating an "
+              "important key. Exiting.");
+      tor_assert(0);
+    }
+    if (out_len >= DLEN) {
+      SHA512(inp, sizeof(inp), out);
+      out += DLEN;
+      out_len -= DLEN;
+    } else {
+      SHA512(inp, sizeof(inp), tmp);
+      memcpy(out, tmp, out_len);
+      out += DLEN;
+      out_len -= DLEN;
+      break;
+    }
+  }
+  memwipe(tmp, 0, sizeof(tmp));
+  memwipe(inp, 0, sizeof(inp));
+
+}
+
+
 /** Seed OpenSSL's random number generator with bytes from the operating
  * system.  <b>startup</b> should be true iff we have just started Tor and
  * have not yet allocated a bunch of fds.  Return 0 on success, -1 on failure.
@@ -2351,7 +2389,7 @@ crypto_seed_rng(void)
   if (rand_poll_ok == 0)
     log_warn(LD_CRYPTO, "RAND_poll() failed.");
 
-  load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
+  load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf));
   if (load_entropy_ok) {
     RAND_seed(buf, sizeof(buf));
   }
index 3b471c295657cf9f1c6ba2b8e3d6862c2fd4d3e1..1e0bbb426f798376efe597235d401b09a6217d3b 100644 (file)
@@ -262,7 +262,7 @@ int crypto_expand_key_material_rfc5869_sha256(
 int crypto_seed_rng(void) ATTR_WUR;
 MOCK_DECL(void,crypto_rand,(char *to, size_t n));
 void crypto_rand_unmocked(char *to, size_t n);
-int crypto_strongest_rand(uint8_t *out, size_t out_len);
+void crypto_strongest_rand(uint8_t *out, size_t out_len);
 int crypto_rand_int(unsigned int max);
 int crypto_rand_int_range(unsigned int min, unsigned int max);
 uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max);
index 00302a2ff0ea7cb92579333033df1ccea1813687..2002483265829a079027e60a056b01ed840eaacb 100644 (file)
@@ -111,18 +111,11 @@ curve25519_public_key_is_ok(const curve25519_public_key_t *key)
 int
 curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong)
 {
-  uint8_t k_tmp[CURVE25519_SECKEY_LEN];
-
-  crypto_rand((char*)out, CURVE25519_SECKEY_LEN);
-  if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) {
-    /* If they asked for extra-strong entropy and we have some, use it as an
-     * HMAC key to improve not-so-good entropy rather than using it directly,
-     * just in case the extra-strong entropy is less amazing than we hoped. */
-    crypto_hmac_sha256((char*) out,
-                       (const char *)k_tmp, sizeof(k_tmp),
-                       (const char *)out, CURVE25519_SECKEY_LEN);
-  }
-  memwipe(k_tmp, 0, sizeof(k_tmp));
+  if (extra_strong)
+    crypto_strongest_rand(out, CURVE25519_SECKEY_LEN);
+  else
+    crypto_rand((char*)out, CURVE25519_SECKEY_LEN);
+
   return 0;
 }
 
index 1749efc34c7adb525680a55a21013a85ecb89fda..41ec486f0a7379ba6fd0f7c27add3d9f9b27a0b7 100644 (file)
@@ -107,7 +107,9 @@ ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out,
 {
   int r;
   uint8_t seed[32];
-  if (! extra_strong || crypto_strongest_rand(seed, sizeof(seed)) < 0)
+  if (extra_strong)
+    crypto_strongest_rand(seed, sizeof(seed));
+ else
     crypto_rand((char*)seed, sizeof(seed));
 
   r = get_ed_impl()->seckey_expand(seckey_out->seckey, seed);
index 12493f7d14103fcb780b585790864ee748e95003..ac726ba04522f0015ba3dbfbdf855278f038bb3d 100644 (file)
@@ -148,8 +148,7 @@ ed25519_donna_seckey(unsigned char *sk)
 {
   ed25519_secret_key seed;
 
-  if (crypto_strongest_rand(seed, 32))
-    return -1;
+  crypto_strongest_rand(seed, 32);
 
   ed25519_extsk(sk, seed);
 
index fc709fcefcfff1e90eb1c75c82ec797d97585df2..8bf31631f08dd1664b4229be18c14320dd1fac14 100644 (file)
@@ -1,4 +1,4 @@
 /* Added for Tor. */
 #include "crypto.h"
 #define randombytes(b, n) \
-  (crypto_strongest_rand((b), (n)))
+  (crypto_strongest_rand((b), (n)), 0)