From 583a7b5c74239aa9e645ea5b604e4504b323271f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 23 Feb 2017 23:18:10 +0000 Subject: [PATCH] core: protect precomputed block hashes with SHA256 --- src/common/util.cpp | 12 ++++++++++++ src/common/util.h | 1 + src/cryptonote_core/blockchain.cpp | 29 ++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/common/util.cpp b/src/common/util.cpp index cc2b5b8ff..046961b06 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -587,6 +587,18 @@ std::string get_nix_version_display_string() return 0; } + bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash) + { + SHA256_CTX ctx; + if (!SHA256_Init(&ctx)) + return false; + if (!SHA256_Update(&ctx, data, len)) + return false; + if (!SHA256_Final((unsigned char*)hash.data, &ctx)) + return false; + return true; + } + bool sha256sum(const std::string &filename, crypto::hash &hash) { if (!epee::file_io_utils::is_file_exist(filename)) diff --git a/src/common/util.h b/src/common/util.h index 1d4b3a153..4291d7e18 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -185,5 +185,6 @@ namespace tools bool is_local_address(const std::string &address); int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate + bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash); bool sha256sum(const std::string &filename, crypto::hash &hash); } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 6ccd61f94..a65af3317 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3995,10 +3995,37 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) +static const char expected_block_hashes_hash[] = "23d8a8c73de7b2383c72a016d9a6034e69d62dd48077d1c414e064ceab6daa94"; void Blockchain::load_compiled_in_block_hashes() { if (m_fast_sync && get_blocks_dat_start(m_testnet) != nullptr) { + MINFO("Loading precomputed blocks (" << get_blocks_dat_size(m_testnet) << " bytes)"); + + if (!m_testnet) + { + // first check hash + crypto::hash hash; + if (!tools::sha256sum(get_blocks_dat_start(m_testnet), get_blocks_dat_size(m_testnet), hash)) + { + MERROR("Failed to hash precomputed blocks data"); + return; + } + MINFO("precomputed blocks hash: " << hash << ", expected " << expected_block_hashes_hash); + cryptonote::blobdata expected_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(expected_block_hashes_hash), expected_hash_data) || expected_hash_data.size() != sizeof(crypto::hash)) + { + MERROR("Failed to parse expected block hashes hash"); + return; + } + const crypto::hash expected_hash = *reinterpret_cast(expected_hash_data.data()); + if (hash != expected_hash) + { + MERROR("Block hash data does not match expected hash"); + return; + } + } + if (get_blocks_dat_size(m_testnet) > 4) { const unsigned char *p = get_blocks_dat_start(m_testnet); @@ -4006,7 +4033,6 @@ void Blockchain::load_compiled_in_block_hashes() const size_t size_needed = 4 + nblocks * sizeof(crypto::hash); if(nblocks > 0 && nblocks > m_db->height() && get_blocks_dat_size(m_testnet) >= size_needed) { - MINFO("Loading precomputed blocks: " << nblocks); p += sizeof(uint32_t); for (uint32_t i = 0; i < nblocks; i++) { @@ -4015,6 +4041,7 @@ void Blockchain::load_compiled_in_block_hashes() p += sizeof(hash.data); m_blocks_hash_check.push_back(hash); } + MINFO(nblocks << " block hashes loaded"); // FIXME: clear tx_pool because the process might have been // terminated and caused it to store txs kept by blocks.