From 84e618b3f222acb351cd9afddb7ba53d1aa67e8c Mon Sep 17 00:00:00 2001 From: Nik Bougalis Date: Tue, 17 Feb 2015 19:14:01 -0800 Subject: [PATCH] Improve pool seeding during startup: * When starting up, we no longer rely just on the standard system RNG to generate entropy: we attempt to squeeze some from the execution state, and to recover any entropy that we had previously stored. * When shutting down, if sufficient entropy has been accumulated attempt to store it for future use. --- src/ripple/app/main/Application.cpp | 13 ++++++++ src/ripple/app/main/Main.cpp | 42 ++++++++++++++++++++++-- src/ripple/core/Config.h | 3 ++ src/ripple/crypto/RandomNumbers.h | 11 +++++++ src/ripple/crypto/impl/RandomNumbers.cpp | 14 +++++++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 0d28efbd8d..d5110906a6 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -286,6 +287,7 @@ public: std::unique_ptr mValidations; std::unique_ptr m_loadManager; beast::DeadlineTimer m_sweepTimer; + beast::DeadlineTimer m_entropyTimer; std::unique_ptr mRpcDB; std::unique_ptr mTxnDB; @@ -408,6 +410,8 @@ public: , m_sweepTimer (this) + , m_entropyTimer (this) + , m_signals(get_io_service(), SIGINT) , m_resolver (ResolverAsio::New (get_io_service(), m_logs.journal("Resolver"))) @@ -857,6 +861,7 @@ public: m_journal.info << "Application starting. Build is " << gitCommitID(); m_sweepTimer.setExpiration (10); + m_entropyTimer.setRecurringExpiration (300); m_io_latency_sampler.start(); @@ -887,6 +892,8 @@ public: m_sweepTimer.cancel (); + m_entropyTimer.cancel (); + mValidations->flush (); RippleAddress::clearCache (); @@ -952,6 +959,12 @@ public: void onDeadlineTimer (beast::DeadlineTimer& timer) { + if (timer == m_entropyTimer) + { + add_entropy (nullptr, 0); + return; + } + if (timer == m_sweepTimer) { // VFALCO TODO Move all this into doSweep diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 878c82587e..7fea087487 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #if defined(BEAST_LINUX) || defined(BEAST_MAC) || defined(BEAST_BSD) #include @@ -67,6 +68,13 @@ void setupServer () getApp().setup (); } +boost::filesystem::path +getEntropyFile() +{ + return boost::filesystem::path ( + getConfig().legacy("database_path")) / "random.seed"; +} + void startServer () { // @@ -93,7 +101,11 @@ void startServer () } } - getApp().run (); // Blocks till we get a stop RPC. + // Block until we get a stop RPC. + getApp().run (); + + // Try to write out some entropy to use the next time we start. + stir_entropy (getEntropyFile ().string ()); } void printHelp (const po::options_description& desc) @@ -258,8 +270,29 @@ int run (int argc, char** argv) po::positional_options_description p; p.add ("parameters", -1); - // Seed the RNG early - add_entropy (); + { + // We want to seed the RNG early. We acquire a small amount of + // questionable quality entropy from the current time and our + // environment block which will get stirred into the RNG pool + // along with high-quality entropy from the system. + struct entropy_t + { + std::uint64_t timestamp; + std::size_t tid; + std::uintptr_t ptr[4]; + }; + + auto entropy = std::make_unique (); + + entropy->timestamp = beast::Time::currentTimeMillis (); + entropy->tid = std::hash () (std::this_thread::get_id ()); + entropy->ptr[0] = reinterpret_cast(entropy.get ()); + entropy->ptr[1] = reinterpret_cast(&argc); + entropy->ptr[2] = reinterpret_cast(argv); + entropy->ptr[3] = reinterpret_cast(argv[0]); + + add_entropy (entropy.get (), sizeof (entropy_t)); + } if (!iResult) { @@ -346,6 +379,9 @@ int run (int argc, char** argv) getConfig ().RUN_STANDALONE = true; getConfig ().LEDGER_HISTORY = 0; } + + // Use any previously available entropy to stir the pool + stir_entropy (getEntropyFile ().string ()); } if (vm.count ("start")) getConfig ().START_UP = Config::FRESH; diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 1207a1aed5..6f678d8129 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -124,6 +124,9 @@ public: /** Returns the full path and filename of the debug log file. */ boost::filesystem::path getDebugLogFile () const; + /** Returns the full path and filename of the entropy seed file. */ + boost::filesystem::path getEntropyFile () const; + // DEPRECATED boost::filesystem::path CONFIG_FILE; // used by UniqueNodeList private: diff --git a/src/ripple/crypto/RandomNumbers.h b/src/ripple/crypto/RandomNumbers.h index 4c908a0a6e..4940caa257 100644 --- a/src/ripple/crypto/RandomNumbers.h +++ b/src/ripple/crypto/RandomNumbers.h @@ -20,10 +20,21 @@ #ifndef RIPPLE_CRYPTO_RANDOMNUMBERS_H_INCLUDED #define RIPPLE_CRYPTO_RANDOMNUMBERS_H_INCLUDED +#include #include // namespace ripple { +/** Stir the RNG using entropy from stable storage. + + @param file the file from which state is loaded and into + which it is saved. + + @return true if the pool has sufficient entropy; false + otherwise. +*/ +bool stir_entropy (std::string file); + /** Adds entropy to the RNG pool. @param buffer An optional buffer that contains random data. diff --git a/src/ripple/crypto/impl/RandomNumbers.cpp b/src/ripple/crypto/impl/RandomNumbers.cpp index 5f792dd512..a2ab97a466 100644 --- a/src/ripple/crypto/impl/RandomNumbers.cpp +++ b/src/ripple/crypto/impl/RandomNumbers.cpp @@ -26,6 +26,18 @@ namespace ripple { +bool stir_entropy (std::string file) +{ + // First, we attempt to stir any existing saved entropy + // into the pool: no use letting it go to waste. + RAND_load_file (file.c_str (), 1024); + + // And now, we extract some entropy out, and save it for + // the future. If the quality of the entropy isn't great + // then we let the user know. + return RAND_write_file (file.c_str ()) != -1; +} + void add_entropy (void* buffer, int count) { assert (buffer == nullptr || count != 0); @@ -35,7 +47,7 @@ void add_entropy (void* buffer, int count) if (buffer != nullptr && count != 0) RAND_add (buffer, count, count / 4.0); - // Try to add a bit more entropy from the system + // And try to add some entropy from the system unsigned int rdbuf[32]; std::random_device rd;