فهرست منبع

Better entropy for getRandomBytes

Tatsuhiro Tsujikawa 3 سال پیش
والد
کامیت
ba3396f7bb
4فایلهای تغییر یافته به همراه111 افزوده شده و 11 حذف شده
  1. 1 0
      configure.ac
  2. 38 10
      src/SimpleRandomizer.cc
  3. 2 1
      test/Makefile.am
  4. 70 0
      test/SimpleRandomizerTest.cc

+ 1 - 0
configure.ac

@@ -754,6 +754,7 @@ AC_CHECK_FUNCS([__argz_count \
                 atexit \
                 ftruncate \
                 getcwd \
+                getentropy \
                 gethostbyaddr \
                 gethostbyname \
                 getifaddrs \

+ 38 - 10
src/SimpleRandomizer.cc

@@ -39,6 +39,11 @@
 #include <cstdlib>
 #include <cassert>
 #include <cstring>
+#include <iostream>
+
+#ifdef __APPLE__
+#  include <Security/SecRandom.h>
+#endif // __APPLE__
 
 #include "a2time.h"
 #include "a2functional.h"
@@ -89,17 +94,40 @@ void SimpleRandomizer::getRandomBytes(unsigned char* buf, size_t len)
 {
 #ifdef __MINGW32__
   BOOL r = CryptGenRandom(provider_, len, reinterpret_cast<BYTE*>(buf));
-  assert(r);
-#else  // ! __MINGW32__
-  auto ubuf = reinterpret_cast<result_type*>(buf);
-  size_t q = len / sizeof(result_type);
-  auto dis = std::uniform_int_distribution<result_type>();
-  for (; q > 0; --q, ++ubuf) {
-    *ubuf = dis(gen_);
+  if (!r) {
+    assert(r);
+    abort();
+  }
+#elif defined(__APPLE__)
+  auto rv = SecRandomCopyBytes(kSecRandomDefault, len, buf);
+  assert(errSecSuccess == rv);
+#else  // !__MINGW32__ && !__APPLE__
+  constexpr static size_t blocklen = 256;
+  auto iter = len / blocklen;
+  auto p = buf;
+
+  for (size_t i = 0; i < iter; ++i) {
+    auto rv = getentropy(p, blocklen);
+    if (rv != 0) {
+      std::cerr << "getentropy: " << strerror(errno) << std::endl;
+      assert(0);
+      abort();
+    }
+
+    p += blocklen;
+  }
+
+  auto rem = len - iter * blocklen;
+  if (rem == 0) {
+    return;
+  }
+
+  auto rv = getentropy(p, rem);
+  if (rv != 0) {
+    std::cerr << "getentropy: " << strerror(errno) << std::endl;
+    assert(0);
+    abort();
   }
-  const size_t r = len % sizeof(result_type);
-  auto last = dis(gen_);
-  memcpy(ubuf, &last, r);
 #endif // ! __MINGW32__
 }
 

+ 2 - 1
test/Makefile.am

@@ -89,7 +89,8 @@ aria2c_SOURCES = AllTest.cc\
 	WrDiskCacheTest.cc\
 	WrDiskCacheEntryTest.cc\
 	GroupIdTest.cc\
-	IndexedListTest.cc
+	IndexedListTest.cc \
+	SimpleRandomizerTest.cc
 
 if ENABLE_XML_RPC
 aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc

+ 70 - 0
test/SimpleRandomizerTest.cc

@@ -0,0 +1,70 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2022 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "SimpleRandomizer.h"
+
+#include <set>
+#include <array>
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace aria2 {
+
+class SimpleRandomizerTest : public CppUnit::TestFixture {
+  CPPUNIT_TEST_SUITE(SimpleRandomizerTest);
+  CPPUNIT_TEST(testGetRandomBytes);
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void testGetRandomBytes();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SimpleRandomizerTest);
+
+void SimpleRandomizerTest::testGetRandomBytes()
+{
+  std::set<std::string> set;
+
+  constexpr size_t n = 5000;
+
+  for (size_t i = 0; i < 5000; ++i) {
+    std::array<unsigned char, 257> buf;
+    SimpleRandomizer::getInstance()->getRandomBytes(buf.data(), buf.size());
+    set.emplace(std::begin(buf), std::end(buf));
+  }
+
+  CPPUNIT_ASSERT_EQUAL(n, set.size());
+}
+
+} // namespace aria2