From 49e02b5a997b2c8253372ea8a866b59b989fc5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Jul 2015 08:41:27 +0200 Subject: [PATCH 01/53] Build EVM JIT by default. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d92ee90a..5b9187d79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ option(TOOLS "Build the tools components" ON) option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(NOBOOST "No use of boost macros in test functions" OFF) -option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) +option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" ON) option(ETHASHCL "Build in support for GPU mining via OpenCL" ON) option(JSCONSOLE "Build in javascript console" ON) From 2728436eb7660fc4568cffa3b15dc354f5516bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Jul 2015 09:00:57 +0200 Subject: [PATCH 02/53] Set default value of LLVM_DIR on OSX --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b9187d79..601a05ed3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,9 +355,14 @@ else() endif() if (EVMJIT) - if (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND NOT DEFINED LLVM_DIR) - set(LLVM_DIR "${CMAKE_SOURCE_DIR}/extdep/install/windows/x64/share/llvm/cmake") + if (NOT DEFINED LLVM_DIR) + if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(LLVM_DIR "${CMAKE_SOURCE_DIR}/extdep/install/windows/x64/share/llvm/cmake") + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(LLVM_DIR "/usr/local/opt/llvm/share/llvm/cmake") + endif() endif() + set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") From 49a826397b1411dcbb433bcf5a9f21c67538b98c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 03/53] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. --- alethzero/MainWin.cpp | 8 +++++--- ethminer/CMakeLists.txt | 1 + libdevcore/Common.h | 10 ++++++++++ libdevcore/FixedHash.h | 2 ++ libdevcore/vector_ref.h | 20 ++++++++++++++++++++ libdevcrypto/Common.cpp | 14 +++++++------- libdevcrypto/Common.h | 12 ++++++++++-- libdevcrypto/CryptoPP.cpp | 2 +- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 4 ++-- libethcore/CMakeLists.txt | 4 +--- libethcore/Common.cpp | 2 +- libethereum/BlockChain.cpp | 7 ++----- libethereum/BlockChain.h | 13 +++++++++++-- libethereum/CanonBlockChain.cpp | 1 + libethereum/CanonBlockChain.h | 5 ++++- libethereumx/Ethereum.cpp | 4 ++-- libethereumx/Ethereum.h | 4 ++-- libweb3jsonrpc/JsonHelper.cpp | 2 +- libweb3jsonrpc/JsonHelper.h | 2 +- libwhisper/CMakeLists.txt | 4 ++-- libwhisper/Interface.h | 4 ++-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 4 ++-- mix/ClientModel.h | 2 +- test/libdevcrypto/crypto.cpp | 4 ++-- test/libethereum/stateOriginal.cpp | 4 ++-- 29 files changed, 100 insertions(+), 49 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 181a77467..eea7b0960 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -349,8 +349,8 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret _id = jsToSecret(_ids.toStdString()); - KeyPair kp(_id); + Secret const& id = jsToSecret(_ids.toStdString()); + KeyPair kp(id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); @@ -1327,7 +1327,9 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - for (auto const& i: ethereum()->addresses()) + auto as = ethereum()->addresses(); + sort(as.begin(), as.end()); + for (auto const& i: as) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 8b79afd72..cda6aa8b8 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -30,6 +30,7 @@ endif() target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} devcrypto) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 612b7c685..0d632a550 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -79,6 +79,16 @@ using bytes = std::vector; using bytesRef = vector_ref; using bytesConstRef = vector_ref; +template +class secure_vector: public std::vector +{ +public: + template secure_vector(Args&& ... _args): std::vector(_args ...) {} + ~secure_vector() { vector_ref(this).cleanse(); } +}; + +using bytesSec = secure_vector; + // Numeric types. using bigint = boost::multiprecision::number>; using u64 = boost::multiprecision::number>; diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 3127b349a..98d457da3 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -214,6 +214,8 @@ public: return ret; } + void clear() { m_data.fill(0); } + private: std::array m_data; ///< The binary data. }; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b05342f71..6f2bff5bd 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,8 @@ namespace dev { +static unsigned char s_cleanseCounter = 0; + /** * A modifiable reference to an existing object or vector in memory. */ @@ -65,6 +67,24 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + uint8_t* p = (uint8_t*)begin(); + size_t len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 7cc16bd03..b64535f51 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -272,6 +272,13 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin return ret; } +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (s_secp256k1pp.verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) @@ -283,13 +290,6 @@ KeyPair KeyPair::create() return KeyPair(); } -KeyPair::KeyPair(h256 _sec): - m_secret(_sec) -{ - if (s_secp256k1pp.verifySecret(m_secret, m_public)) - m_address = toAddress(m_public); -} - KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { return KeyPair(sha3(aesDecrypt(_seed, _password))); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9aeb85a4c..44d1c8155 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -34,7 +34,13 @@ namespace dev /// A secret key: 32 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. -using Secret = h256; +class Secret: public h256 +{ +public: + template Secret(Args&& ... _args): h256(_args ...) {} + Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} + ~Secret() { ref().cleanse(); } +}; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -151,7 +157,7 @@ public: KeyPair() {} /// Normal constructor - populates object from the given secret key. - KeyPair(Secret _k); + KeyPair(Secret const& _k) { populateFromSecret(_k); } /// Create a new, randomly generated object. static KeyPair create(); @@ -174,6 +180,8 @@ public: bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } private: + void populateFromSecret(Secret const& _k); + Secret m_secret; Public m_public; Address m_address; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 8beb8e495..693952d5f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -33,7 +33,7 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1PP::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) { auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); // SEC/ISO/Shoup specify counter size SHOULD be equivalent diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 6a0453330..fca094242 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -87,7 +87,7 @@ public: bool decryptECIES(Secret const& _k, bytes& io_text); /// Key derivation function used by encryptECIES and decryptECIES. - bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256); + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); /// @returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index d3c9ae325..6d4a68203 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -40,7 +40,7 @@ class Alias { friend class ECDHEKeyExchange; // todo: remove public: - Alias(Secret _s): m_secret(_s) {}; + Alias(Secret const& _s): m_secret(_s) {}; AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 55c944e8e..b823ba02f 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -91,13 +91,13 @@ SecretStore::SecretStore(string const& _path): m_path(_path) load(); } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const +bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - bytes key; + bytesSec key; if (it != m_keys.end()) { key = decrypt(it->second.encryptedKey, _pass()); diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 029630b4e..ea08a48b2 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -52,7 +52,7 @@ public: /// @returns the secret key stored by the given @a _uuid. /// @param _pass function that returns the password for the key. /// @param _useCache if true, allow previously decrypted keys to be returned directly. - bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + bytesSec secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in @@ -107,7 +107,7 @@ private: static bytes decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. - mutable std::unordered_map m_cached; + mutable std::unordered_map m_cached; /// Stores encrypted keys together with the file they were loaded from by uuid. std::unordered_map m_keys; diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 73ea75c8c..d740da2a2 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -23,13 +23,11 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) - if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) endif () - +target_link_libraries(${EXECUTABLE} devcrypto) if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index b95564b9b..85121c4f0 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -65,7 +65,7 @@ Network resetNetwork(Network _n) c_gasLimitBoundDivisor = 1024; c_minimumDifficulty = 131072; c_difficultyBoundDivisor = 2048; - c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12; + c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); return _n; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bd96f6607..9f596a5ba 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -152,7 +152,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -165,9 +165,6 @@ void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); /// Open the database. - unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust); + unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); + /// Open the database, rebuilding if necessary. + void openDatabase(std::string const& _path, WithExisting _we, ProgressCallback const& _pc) + { + if (openDatabase(_path, _we) != c_minorProtocolVersion || _we == WithExisting::Verify) + rebuild(_path, _pc); + } + template T queryExtras(K const& _h, std::unordered_map& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const { { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 2a7408437..b921d67e4 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -47,6 +47,7 @@ bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) { + BlockChain::openDatabase(_path, _we, _pc); } void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d09108b38..0ff9c6521 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -52,7 +52,10 @@ class CanonBlockChain: public FullBlockChain public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): - FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) + { + BlockChain::openDatabase(_path, _we, _pc); + } ~CanonBlockChain() {} /// @returns the genesis block as its RLP-encoded byte array. diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 8ab4243a1..675614c1a 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes con return bytes(); } -Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 0e81b8e0c..1e24b396c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index c074525b9..9ccad947d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -482,7 +482,7 @@ shh::Message toMessage(Json::Value const& _json) return ret; } -shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret const& _from) { unsigned ttl = 50; unsigned workToProve = 50; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 11219fc55..9be59bcab 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -89,7 +89,7 @@ namespace shh Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); Message toMessage(Json::Value const& _json); -Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret const& _from); std::pair toWatch(Json::Value const& _json); } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 5af43d0b2..05bf2ae20 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -21,10 +21,10 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} p2p) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index f53cb17a7..21a1355f8 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -76,8 +76,8 @@ public: void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index dd72ff734..bf18835b6 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { AbridgedTopics topics = abridge(_fullTopics); Envelope ret(time(0) + _ttl, _ttl, topics); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 4d8b34548..1ec28ae01 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -118,11 +118,11 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret const& _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } + Envelope sealTo(Secret const& _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bf88ad66a..cff767dad 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -55,7 +55,7 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret const& _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index b70eae36e..c94cc4e8f 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eA.agree(eBAck, ess); ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); @@ -581,7 +581,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eB.agree(eAAuth, ess); // s_secp256k1.agree(eB.seckey(), eAAuth, ess); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 163c89e50..9a806c7c4 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(Complex) cnote << "Testing State..."; - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); + KeyPair me = Secret(sha3("Gav Wood")); + KeyPair myMiner = Secret(sha3("Gav's Miner")); // KeyPair you = sha3("123"); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); From aa97d7b0b4e92233a818176b2de1804c1cdebae4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:53:14 +0200 Subject: [PATCH 04/53] Hold address-sorting back. --- alethzero/MainWin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index eea7b0960..91cc4c0fe 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1327,9 +1327,7 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - auto as = ethereum()->addresses(); - sort(as.begin(), as.end()); - for (auto const& i: as) + for (auto const& i: ethereum()->addresses()) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) From 7e7ea437759059e3a2f8a72a9bac2a5b053dcf04 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 21:31:06 +0200 Subject: [PATCH 05/53] SHA3 gas calc should use bigint to avoid overflow. Fixes #2582. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f95481c54..9d89ce497 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -103,7 +103,7 @@ void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::SHA3: - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + runGas = c_sha3Gas + ((bigint)m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: From c3a334cc2156d04a5e3926abd6ca32dac98e35fb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 06/53] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. --- alethzero/MainWin.cpp | 4 ++-- ethminer/CMakeLists.txt | 1 + libdevcore/Common.h | 10 ++++++++++ libdevcore/FixedHash.h | 2 ++ libdevcore/vector_ref.h | 20 ++++++++++++++++++++ libdevcrypto/Common.cpp | 14 +++++++------- libdevcrypto/Common.h | 12 ++++++++++-- libdevcrypto/CryptoPP.cpp | 2 +- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 4 ++-- libethcore/CMakeLists.txt | 4 +--- libethcore/Common.cpp | 2 +- libethereum/BlockChain.cpp | 7 ++----- libethereum/BlockChain.h | 13 +++++++++++-- libethereum/CanonBlockChain.cpp | 1 + libethereum/CanonBlockChain.h | 5 ++++- libethereumx/Ethereum.cpp | 4 ++-- libethereumx/Ethereum.h | 4 ++-- libweb3jsonrpc/JsonHelper.cpp | 2 +- libweb3jsonrpc/JsonHelper.h | 2 +- libwhisper/CMakeLists.txt | 4 ++-- libwhisper/Interface.h | 4 ++-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 4 ++-- mix/ClientModel.h | 2 +- test/libdevcrypto/crypto.cpp | 4 ++-- test/libethereum/stateOriginal.cpp | 4 ++-- 29 files changed, 97 insertions(+), 48 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3502171c5..eea7b0960 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -349,8 +349,8 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret _id = jsToSecret(_ids.toStdString()); - KeyPair kp(_id); + Secret const& id = jsToSecret(_ids.toStdString()); + KeyPair kp(id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 8b79afd72..cda6aa8b8 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -30,6 +30,7 @@ endif() target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} devcrypto) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 612b7c685..0d632a550 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -79,6 +79,16 @@ using bytes = std::vector; using bytesRef = vector_ref; using bytesConstRef = vector_ref; +template +class secure_vector: public std::vector +{ +public: + template secure_vector(Args&& ... _args): std::vector(_args ...) {} + ~secure_vector() { vector_ref(this).cleanse(); } +}; + +using bytesSec = secure_vector; + // Numeric types. using bigint = boost::multiprecision::number>; using u64 = boost::multiprecision::number>; diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 3127b349a..98d457da3 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -214,6 +214,8 @@ public: return ret; } + void clear() { m_data.fill(0); } + private: std::array m_data; ///< The binary data. }; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b05342f71..6f2bff5bd 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,8 @@ namespace dev { +static unsigned char s_cleanseCounter = 0; + /** * A modifiable reference to an existing object or vector in memory. */ @@ -65,6 +67,24 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + uint8_t* p = (uint8_t*)begin(); + size_t len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 7cc16bd03..b64535f51 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -272,6 +272,13 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin return ret; } +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (s_secp256k1pp.verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) @@ -283,13 +290,6 @@ KeyPair KeyPair::create() return KeyPair(); } -KeyPair::KeyPair(h256 _sec): - m_secret(_sec) -{ - if (s_secp256k1pp.verifySecret(m_secret, m_public)) - m_address = toAddress(m_public); -} - KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { return KeyPair(sha3(aesDecrypt(_seed, _password))); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9aeb85a4c..44d1c8155 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -34,7 +34,13 @@ namespace dev /// A secret key: 32 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. -using Secret = h256; +class Secret: public h256 +{ +public: + template Secret(Args&& ... _args): h256(_args ...) {} + Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} + ~Secret() { ref().cleanse(); } +}; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -151,7 +157,7 @@ public: KeyPair() {} /// Normal constructor - populates object from the given secret key. - KeyPair(Secret _k); + KeyPair(Secret const& _k) { populateFromSecret(_k); } /// Create a new, randomly generated object. static KeyPair create(); @@ -174,6 +180,8 @@ public: bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } private: + void populateFromSecret(Secret const& _k); + Secret m_secret; Public m_public; Address m_address; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 8beb8e495..693952d5f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -33,7 +33,7 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1PP::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) { auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); // SEC/ISO/Shoup specify counter size SHOULD be equivalent diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 6a0453330..fca094242 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -87,7 +87,7 @@ public: bool decryptECIES(Secret const& _k, bytes& io_text); /// Key derivation function used by encryptECIES and decryptECIES. - bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256); + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); /// @returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index d3c9ae325..6d4a68203 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -40,7 +40,7 @@ class Alias { friend class ECDHEKeyExchange; // todo: remove public: - Alias(Secret _s): m_secret(_s) {}; + Alias(Secret const& _s): m_secret(_s) {}; AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 55c944e8e..b823ba02f 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -91,13 +91,13 @@ SecretStore::SecretStore(string const& _path): m_path(_path) load(); } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const +bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - bytes key; + bytesSec key; if (it != m_keys.end()) { key = decrypt(it->second.encryptedKey, _pass()); diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 029630b4e..ea08a48b2 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -52,7 +52,7 @@ public: /// @returns the secret key stored by the given @a _uuid. /// @param _pass function that returns the password for the key. /// @param _useCache if true, allow previously decrypted keys to be returned directly. - bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + bytesSec secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in @@ -107,7 +107,7 @@ private: static bytes decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. - mutable std::unordered_map m_cached; + mutable std::unordered_map m_cached; /// Stores encrypted keys together with the file they were loaded from by uuid. std::unordered_map m_keys; diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 73ea75c8c..d740da2a2 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -23,13 +23,11 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) - if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) endif () - +target_link_libraries(${EXECUTABLE} devcrypto) if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index b95564b9b..85121c4f0 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -65,7 +65,7 @@ Network resetNetwork(Network _n) c_gasLimitBoundDivisor = 1024; c_minimumDifficulty = 131072; c_difficultyBoundDivisor = 2048; - c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12; + c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); return _n; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bd96f6607..9f596a5ba 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -152,7 +152,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -165,9 +165,6 @@ void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); /// Open the database. - unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust); + unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); + /// Open the database, rebuilding if necessary. + void openDatabase(std::string const& _path, WithExisting _we, ProgressCallback const& _pc) + { + if (openDatabase(_path, _we) != c_minorProtocolVersion || _we == WithExisting::Verify) + rebuild(_path, _pc); + } + template T queryExtras(K const& _h, std::unordered_map& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const { { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 2a7408437..b921d67e4 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -47,6 +47,7 @@ bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) { + BlockChain::openDatabase(_path, _we, _pc); } void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d09108b38..0ff9c6521 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -52,7 +52,10 @@ class CanonBlockChain: public FullBlockChain public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): - FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) + { + BlockChain::openDatabase(_path, _we, _pc); + } ~CanonBlockChain() {} /// @returns the genesis block as its RLP-encoded byte array. diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 8ab4243a1..675614c1a 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes con return bytes(); } -Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 0e81b8e0c..1e24b396c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index c074525b9..9ccad947d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -482,7 +482,7 @@ shh::Message toMessage(Json::Value const& _json) return ret; } -shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret const& _from) { unsigned ttl = 50; unsigned workToProve = 50; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 11219fc55..9be59bcab 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -89,7 +89,7 @@ namespace shh Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); Message toMessage(Json::Value const& _json); -Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret const& _from); std::pair toWatch(Json::Value const& _json); } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 5af43d0b2..05bf2ae20 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -21,10 +21,10 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} p2p) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index f53cb17a7..21a1355f8 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -76,8 +76,8 @@ public: void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index dd72ff734..bf18835b6 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { AbridgedTopics topics = abridge(_fullTopics); Envelope ret(time(0) + _ttl, _ttl, topics); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 4d8b34548..1ec28ae01 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -118,11 +118,11 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret const& _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } + Envelope sealTo(Secret const& _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bf88ad66a..cff767dad 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -55,7 +55,7 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret const& _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index b70eae36e..c94cc4e8f 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eA.agree(eBAck, ess); ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); @@ -581,7 +581,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eB.agree(eAAuth, ess); // s_secp256k1.agree(eB.seckey(), eAAuth, ess); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 163c89e50..9a806c7c4 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(Complex) cnote << "Testing State..."; - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); + KeyPair me = Secret(sha3("Gav Wood")); + KeyPair myMiner = Secret(sha3("Gav's Miner")); // KeyPair you = sha3("123"); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); From 58358b48c3193b17483b6957485255dfa346085f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:53:14 +0200 Subject: [PATCH 07/53] Hold address-sorting back. --- alethzero/MainWin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index eea7b0960..91cc4c0fe 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1327,9 +1327,7 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - auto as = ethereum()->addresses(); - sort(as.begin(), as.end()); - for (auto const& i: as) + for (auto const& i: ethereum()->addresses()) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) From ded1a739a9d0f5d2d7317156401ba17f100f7544 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 21:31:06 +0200 Subject: [PATCH 08/53] SHA3 gas calc should use bigint to avoid overflow. Fixes #2582. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f95481c54..9d89ce497 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -103,7 +103,7 @@ void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::SHA3: - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + runGas = c_sha3Gas + ((bigint)m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: From 0c0adcda59eef8bf7e41d832cdedad054b2ca0fe Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 22:13:49 +0200 Subject: [PATCH 09/53] Fix const& where it should have been value. --- alethzero/MainWin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 91cc4c0fe..7e73edc3b 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -349,8 +349,7 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret const& id = jsToSecret(_ids.toStdString()); - KeyPair kp(id); + KeyPair kp(jsToSecret(_ids.toStdString())); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); From e2203bb585eb9e31cc0566923454d4acb0e0aaea Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 10/53] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. --- alethzero/MainWin.cpp | 4 ++-- ethminer/CMakeLists.txt | 1 + libdevcore/Common.h | 10 ++++++++++ libdevcore/FixedHash.h | 2 ++ libdevcore/vector_ref.h | 20 ++++++++++++++++++++ libdevcrypto/Common.cpp | 14 +++++++------- libdevcrypto/Common.h | 12 ++++++++++-- libdevcrypto/CryptoPP.cpp | 2 +- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 4 ++-- libethcore/CMakeLists.txt | 4 +--- libethcore/Common.cpp | 2 +- libethereum/BlockChain.cpp | 7 ++----- libethereum/BlockChain.h | 13 +++++++++++-- libethereum/CanonBlockChain.cpp | 1 + libethereum/CanonBlockChain.h | 5 ++++- libethereumx/Ethereum.cpp | 4 ++-- libethereumx/Ethereum.h | 4 ++-- libweb3jsonrpc/JsonHelper.cpp | 2 +- libweb3jsonrpc/JsonHelper.h | 2 +- libwhisper/CMakeLists.txt | 4 ++-- libwhisper/Interface.h | 4 ++-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 4 ++-- mix/ClientModel.h | 2 +- test/libdevcrypto/crypto.cpp | 4 ++-- test/libethereum/stateOriginal.cpp | 4 ++-- 29 files changed, 97 insertions(+), 48 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3502171c5..eea7b0960 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -349,8 +349,8 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret _id = jsToSecret(_ids.toStdString()); - KeyPair kp(_id); + Secret const& id = jsToSecret(_ids.toStdString()); + KeyPair kp(id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 8b79afd72..cda6aa8b8 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -30,6 +30,7 @@ endif() target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} devcrypto) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 612b7c685..0d632a550 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -79,6 +79,16 @@ using bytes = std::vector; using bytesRef = vector_ref; using bytesConstRef = vector_ref; +template +class secure_vector: public std::vector +{ +public: + template secure_vector(Args&& ... _args): std::vector(_args ...) {} + ~secure_vector() { vector_ref(this).cleanse(); } +}; + +using bytesSec = secure_vector; + // Numeric types. using bigint = boost::multiprecision::number>; using u64 = boost::multiprecision::number>; diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 3127b349a..98d457da3 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -214,6 +214,8 @@ public: return ret; } + void clear() { m_data.fill(0); } + private: std::array m_data; ///< The binary data. }; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b05342f71..6f2bff5bd 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,8 @@ namespace dev { +static unsigned char s_cleanseCounter = 0; + /** * A modifiable reference to an existing object or vector in memory. */ @@ -65,6 +67,24 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + uint8_t* p = (uint8_t*)begin(); + size_t len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 7cc16bd03..b64535f51 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -272,6 +272,13 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin return ret; } +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (s_secp256k1pp.verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) @@ -283,13 +290,6 @@ KeyPair KeyPair::create() return KeyPair(); } -KeyPair::KeyPair(h256 _sec): - m_secret(_sec) -{ - if (s_secp256k1pp.verifySecret(m_secret, m_public)) - m_address = toAddress(m_public); -} - KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { return KeyPair(sha3(aesDecrypt(_seed, _password))); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9aeb85a4c..44d1c8155 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -34,7 +34,13 @@ namespace dev /// A secret key: 32 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. -using Secret = h256; +class Secret: public h256 +{ +public: + template Secret(Args&& ... _args): h256(_args ...) {} + Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} + ~Secret() { ref().cleanse(); } +}; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -151,7 +157,7 @@ public: KeyPair() {} /// Normal constructor - populates object from the given secret key. - KeyPair(Secret _k); + KeyPair(Secret const& _k) { populateFromSecret(_k); } /// Create a new, randomly generated object. static KeyPair create(); @@ -174,6 +180,8 @@ public: bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } private: + void populateFromSecret(Secret const& _k); + Secret m_secret; Public m_public; Address m_address; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 8beb8e495..693952d5f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -33,7 +33,7 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1PP::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) { auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); // SEC/ISO/Shoup specify counter size SHOULD be equivalent diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 6a0453330..fca094242 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -87,7 +87,7 @@ public: bool decryptECIES(Secret const& _k, bytes& io_text); /// Key derivation function used by encryptECIES and decryptECIES. - bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256); + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); /// @returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index d3c9ae325..6d4a68203 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -40,7 +40,7 @@ class Alias { friend class ECDHEKeyExchange; // todo: remove public: - Alias(Secret _s): m_secret(_s) {}; + Alias(Secret const& _s): m_secret(_s) {}; AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 55c944e8e..b823ba02f 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -91,13 +91,13 @@ SecretStore::SecretStore(string const& _path): m_path(_path) load(); } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const +bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - bytes key; + bytesSec key; if (it != m_keys.end()) { key = decrypt(it->second.encryptedKey, _pass()); diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 029630b4e..ea08a48b2 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -52,7 +52,7 @@ public: /// @returns the secret key stored by the given @a _uuid. /// @param _pass function that returns the password for the key. /// @param _useCache if true, allow previously decrypted keys to be returned directly. - bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + bytesSec secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in @@ -107,7 +107,7 @@ private: static bytes decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. - mutable std::unordered_map m_cached; + mutable std::unordered_map m_cached; /// Stores encrypted keys together with the file they were loaded from by uuid. std::unordered_map m_keys; diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 73ea75c8c..d740da2a2 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -23,13 +23,11 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) - if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) endif () - +target_link_libraries(${EXECUTABLE} devcrypto) if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index b95564b9b..85121c4f0 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -65,7 +65,7 @@ Network resetNetwork(Network _n) c_gasLimitBoundDivisor = 1024; c_minimumDifficulty = 131072; c_difficultyBoundDivisor = 2048; - c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12; + c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); return _n; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bd96f6607..9f596a5ba 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -152,7 +152,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -165,9 +165,6 @@ void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); /// Open the database. - unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust); + unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); + /// Open the database, rebuilding if necessary. + void openDatabase(std::string const& _path, WithExisting _we, ProgressCallback const& _pc) + { + if (openDatabase(_path, _we) != c_minorProtocolVersion || _we == WithExisting::Verify) + rebuild(_path, _pc); + } + template T queryExtras(K const& _h, std::unordered_map& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const { { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 2a7408437..b921d67e4 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -47,6 +47,7 @@ bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) { + BlockChain::openDatabase(_path, _we, _pc); } void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d09108b38..0ff9c6521 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -52,7 +52,10 @@ class CanonBlockChain: public FullBlockChain public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): - FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) + { + BlockChain::openDatabase(_path, _we, _pc); + } ~CanonBlockChain() {} /// @returns the genesis block as its RLP-encoded byte array. diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 8ab4243a1..675614c1a 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes con return bytes(); } -Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 0e81b8e0c..1e24b396c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index c074525b9..9ccad947d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -482,7 +482,7 @@ shh::Message toMessage(Json::Value const& _json) return ret; } -shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret const& _from) { unsigned ttl = 50; unsigned workToProve = 50; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 11219fc55..9be59bcab 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -89,7 +89,7 @@ namespace shh Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); Message toMessage(Json::Value const& _json); -Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret const& _from); std::pair toWatch(Json::Value const& _json); } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 5af43d0b2..05bf2ae20 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -21,10 +21,10 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} p2p) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index f53cb17a7..21a1355f8 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -76,8 +76,8 @@ public: void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index dd72ff734..bf18835b6 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { AbridgedTopics topics = abridge(_fullTopics); Envelope ret(time(0) + _ttl, _ttl, topics); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 4d8b34548..1ec28ae01 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -118,11 +118,11 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret const& _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } + Envelope sealTo(Secret const& _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bf88ad66a..cff767dad 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -55,7 +55,7 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret const& _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index b70eae36e..c94cc4e8f 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eA.agree(eBAck, ess); ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); @@ -581,7 +581,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eB.agree(eAAuth, ess); // s_secp256k1.agree(eB.seckey(), eAAuth, ess); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 163c89e50..9a806c7c4 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(Complex) cnote << "Testing State..."; - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); + KeyPair me = Secret(sha3("Gav Wood")); + KeyPair myMiner = Secret(sha3("Gav's Miner")); // KeyPair you = sha3("123"); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); From ec8f89a23f82a4e2d73fefe6d5a22819dbd36ae5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:53:14 +0200 Subject: [PATCH 11/53] Hold address-sorting back. --- alethzero/MainWin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index eea7b0960..91cc4c0fe 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1327,9 +1327,7 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - auto as = ethereum()->addresses(); - sort(as.begin(), as.end()); - for (auto const& i: as) + for (auto const& i: ethereum()->addresses()) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) From 101ea84b8d459dc899aeebb0af0b308446a62bad Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 21:31:06 +0200 Subject: [PATCH 12/53] SHA3 gas calc should use bigint to avoid overflow. Fixes #2582. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f95481c54..9d89ce497 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -103,7 +103,7 @@ void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::SHA3: - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + runGas = c_sha3Gas + ((bigint)m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: From b872015ced25ba7c19c42b00008a395f2180744a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 22:13:49 +0200 Subject: [PATCH 13/53] Fix const& where it should have been value. --- alethzero/MainWin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 91cc4c0fe..7e73edc3b 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -349,8 +349,7 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret const& id = jsToSecret(_ids.toStdString()); - KeyPair kp(id); + KeyPair kp(jsToSecret(_ids.toStdString())); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); From 0c6e0b55dec8b9a0b296fe8e1f9509d75fd656a4 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 27 Jul 2015 12:24:01 +0200 Subject: [PATCH 14/53] extdep/getstuff.bat downloads only x64 libs on windows --- extdep/getstuff.bat | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extdep/getstuff.bat b/extdep/getstuff.bat index 072aacfe6..fad616b54 100644 --- a/extdep/getstuff.bat +++ b/extdep/getstuff.bat @@ -27,13 +27,13 @@ set eth_version=%2 cd download -if not exist %eth_name%-%eth_version%.tar.gz ( - for /f "tokens=2 delims={}" %%g in ('bitsadmin /create %eth_name%-%eth_version%.tar.gz') do ( - bitsadmin /transfer {%%g} /download /priority normal %eth_server%/%eth_name%-%eth_version%.tar.gz %cd%\%eth_name%-%eth_version%.tar.gz +if not exist %eth_name%-%eth_version%-x64.tar.gz ( + for /f "tokens=2 delims={}" %%g in ('bitsadmin /create %eth_name%-%eth_version%-x64.tar.gz') do ( + bitsadmin /transfer {%%g} /download /priority normal %eth_server%/%eth_name%-%eth_version%-x64.tar.gz %cd%\%eth_name%-%eth_version%-x64.tar.gz bitsadmin /cancel {%%g} ) ) -if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%.tar.gz +if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%-x64.tar.gz cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows cd .. From a83fecbe98977b9b92267a764fa2a6ca954043a2 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Jul 2015 11:24:53 -0400 Subject: [PATCH 15/53] CLI flag to enable Whisper --- eth/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 379e61f81..830a79163 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -204,6 +204,10 @@ void help() << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl << " -V,--version Show the version and exit." << endl << " -h,--help Show this help message and exit." << endl + << endl + << "Experimental / Proof of Concept:" << endl + << " --shh Enable Whisper" << endl + << endl ; exit(0); } @@ -1138,6 +1142,9 @@ int main(int argc, char** argv) /// Wallet password stuff string masterPassword; + + /// Whisper + bool useWhisper = false; string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); @@ -1484,6 +1491,8 @@ int main(int argc, char** argv) } } #endif + else if (arg == "--shh") + useWhisper = true; else if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") @@ -1564,11 +1573,12 @@ int main(int argc, char** argv) netPrefs.pin = pinning || !privateChain.empty(); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); + auto caps = useWhisper ? set{"eth", "shh"} : set{"eth"}; dev::WebThreeDirect web3( WebThreeDirect::composeClientVersion("++eth", clientName), dbPath, withExisting, - nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), + nodeMode == NodeMode::Full ? caps : set(), netPrefs, &nodesState); web3.ethereum()->setMineOnBadChain(mineOnWrongChain); From 3181f51eb14fcf685e41adfa72cfa73d79330056 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 27 Jul 2015 17:37:13 +0200 Subject: [PATCH 16/53] fixed invariant on block queue clear --- libethereum/BlockQueue.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 97352fbf1..b0ebf8547 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -76,6 +76,7 @@ void BlockQueue::clear() m_drainingSet.clear(); m_verified.clear(); m_unverified.clear(); + m_verifying.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); From d9e7276c4bcbb4012066b51105b1051865651686 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 27 Jul 2015 21:21:45 +0200 Subject: [PATCH 17/53] fix EXTCODECOPY bug --- libevm/VM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f95481c54..9e1c4b866 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -392,6 +392,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) auto a = asAddress(m_stack.back()); m_stack.pop_back(); copyDataToMemory(&_ext.codeAt(a), m_stack, m_temp); + break; } case Instruction::GASPRICE: m_stack.push_back(_ext.gasPrice); From 0c6cef4026ea4b575dd50dabff006e35be158369 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 01:30:18 +0200 Subject: [PATCH 18/53] allow genesis stuff to be specified with --genesis like geth. add "default" bundle. --- CMakeLists.txt | 25 +++++++++++++++++++++---- eth/main.cpp | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43cb31d8c..004f919c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,9 @@ if (GUI) set(JSONRPC ON) endif() +# Default CMAKE_BUILD_TYPE to "Release". +set(CMAKE_BUILD_TYPE CACHE STRING "Release") + # note: The value "default" which provides the defaults is just a fake value # which lets us keep the default values of all build options and is set at # the beginning of this file. @@ -292,8 +295,23 @@ elseif (BUNDLE STREQUAL "miner") set(ETHKEY OFF) set(MINER ON) set(ETHASHCL ON) -elseif (BUNDLE STREQUAL "release") - set(SERPENT OFF) +elseif (BUNDLE STREQUAL "default") # development builds + set(SERPENT ${DECENT_PLATFORM}) + set(SOLIDITY ON) + set(USENPM OFF) + set(GUI ON) + set(TOOLS ON) + set(TESTS ON) + set(FATDB ON) + set(ETHASHCL ON) + set(EVMJIT ON) + set(JSCONSOLE ON) + set(JSONRPC ON) + if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x") + set(CMAKE_BUILD_TYPE "RelWithDebInfo") + endif () +elseif (BUNDLE STREQUAL "release") # release builds + set(SERPENT ${DECENT_PLATFORM}) set(SOLIDITY ON) set(USENPM OFF) set(GUI ON) @@ -304,10 +322,9 @@ elseif (BUNDLE STREQUAL "release") set(EVMJIT ON) set(JSCONSOLE ON) set(JSONRPC ON) + set(FRONTIER ON) endif () -# Default CMAKE_BUILD_TYPE to "Release". -set(CMAKE_BUILD_TYPE CACHE STRING "Release") if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x") set(CMAKE_BUILD_TYPE "Release") endif () diff --git a/eth/main.cpp b/eth/main.cpp index 379e61f81..f85e7096f 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1324,7 +1324,7 @@ int main(int argc, char** argv) } else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) dbPath = argv[++i]; - else if (arg == "--genesis-json" && i + 1 < argc) + else if ((arg == "--genesis-json" || arg == "--genesis") && i + 1 < argc) { try { From 25c6e5ec4c780e10174c8db943b538b76fb01cc3 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 08:35:42 +0200 Subject: [PATCH 19/53] add extcodecopy stack test --- .../stSystemOperationsTestFiller.json | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json index 3c8d8e08f..242896f36 100644 --- a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json @@ -2832,5 +2832,48 @@ "to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "10" } - } + }, + "extcodecopy" : { + "env" : { + "currentCoinbase" : "4401fcaf7d64d53fb1cfc5c9045c32aa919a8c82", + "currentDifficulty" : "0x7fb7d889155ce8c6", + "currentGasLimit" : "0x58272e28", + "currentNumber" : "0x7608d138", + "currentTimestamp" : "0xa4befad141d51c4f", + "previousHash" : "d30f77155de00f207ad60109897e790f73e9f3431be25717bf3651d91949f041" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x05c81eb0", + "code" : "0x7f15688566a82f5f946c68028bf626b349e495daa43e33529a76437ac416cd1b7d6e7dae7454bb193b1c28e64a6a935bc373cea0c5cc171fa61277e5604a3bc8aef4de3d38820658600b80797ada6e82e95f6520383f95f5c7dae56b4dc13b6f22ecabfce07c3cff51", + "nonce" : "0xfe", + "storage" : { + } + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "0x4d6769f8", + "code" : "0x5a60106017601160116018601c600f601b601d5f60026013600f601a8d5a5b7679177b5dd41a23db52998c4dcd14e88390dcc9f3ed5783601660145f6013600d601f60016011600e600c600d601f60138c7a58f20fd882eb51408a52e569ce80e93270ab53ae9de3fec5498a5c72ce1fcd11bb1553736959df779a616b738c1f407c12459490afe302da311a673488d09e71041d0761dee4829e3c38e0b1b1787810f2e11e2289983c1ab47cf5ebd38c12f1719232b5f3a7b27a9ea8858a071c4169392ec725646311235cbd9534e5d7cd8cb5e2287738a43f803384f4e62fe6629ea2e609a71759edab5c3a58b87e94c95f710aa6059b0663c9f374ce6ea0a000c5d594c41252d4a74d64896a987cc57c24df2ce8ffb85adcc27dce2d19f7006fbc1c5a7b79a319418fd6c27ddebcf170192262d82c1053333f6115c8b258b81e2e84d723c98dbd4535de7f922723a15827bbcfd07f9e2c5027c7736ed68c61b332059d7ec1bae1c1fd41a361d35b996d9740a588b6abf3293236afb927717328c014846148ce67eaf2b33d90672366dafeaae0714eb39e7fd5076a831d8eb4a3546288a3e1a0087aebe80b6bbfa4041330b05d094a697236fe7654d8a7ce630f83a832620125d781666e898f7fdcfd0031", + "nonce" : "0xdd", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x4f6ca7b90ceb5fd4", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } + }, + "transaction" : { + "data" : "0x6e27b0577f2549e5fa01e3db96e7b03a62e489115538620295677faf15040c1c1796bad130e2462a8b8d6bbe0fa35bf12087047ef4ff4e66df8772196b4401998ff7f4219c013a0d927b22d8d3fdf625809abb182507d180e687b666f4f1e4f3b8172e87760f436c701264b89739f3d7c50ec524f16b1a4f91397b760a5209b9b7710544694ecf2729643b3ca545c7", + "gasLimit" : "0x3bd760dd", + "gasPrice" : "0x1cd49878", + "nonce" : "0x00", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0x24a39757" + } + } + } From 1853931035df65efd64064d65019e4517b477055 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 09:00:17 +0200 Subject: [PATCH 20/53] add documentation --- test/libethereum/gaspricer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index 810e00e65..fc1c082b8 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -17,6 +17,7 @@ /** @file gasPricer.cpp * @author Christoph Jentzsch * @date 2015 + * Gas pricer tests */ #include From 2f1986185859e81e6085f783f1ae17dbf8b9f098 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 21/53] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. --- alethzero/DappLoader.cpp | 5 +- alethzero/MainWin.cpp | 22 ++------- eth/main.cpp | 18 +++---- ethkey/KeyAux.h | 24 +++++----- libdevcore/Common.h | 29 ++++++++++-- libdevcore/CommonJS.h | 11 ++++- libdevcore/FixedHash.h | 79 +++++++++++++++++++++++++++++++ libdevcore/SHA3.cpp | 9 ++-- libdevcore/SHA3.h | 19 ++++++-- libdevcore/vector_ref.h | 12 +++++ libdevcrypto/AES.h | 2 +- libdevcrypto/Common.cpp | 32 ++++++------- libdevcrypto/Common.h | 32 +++++-------- libdevcrypto/CryptoPP.cpp | 16 +++---- libdevcrypto/CryptoPP.h | 4 +- libdevcrypto/ECDHE.cpp | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 59 +++++++++++++---------- libdevcrypto/SecretStore.h | 7 +-- libethcore/BasicAuthority.cpp | 2 +- libethcore/CommonJS.h | 2 +- libethcore/KeyManager.cpp | 16 +++---- libethcore/KeyManager.h | 6 +-- libp2p/Host.cpp | 2 +- libp2p/RLPxHandshake.cpp | 4 +- libwhisper/Message.cpp | 10 ++-- libwhisper/Message.h | 2 +- mix/FileIo.cpp | 2 +- test/libdevcrypto/AES.cpp | 6 +-- test/libdevcrypto/SecretStore.cpp | 32 ++++++------- test/libdevcrypto/crypto.cpp | 39 +++++++-------- test/libethcore/commonjs.cpp | 14 +++--- 32 files changed, 320 insertions(+), 201 deletions(-) diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index a91531f89..3da3e8c35 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -130,14 +130,14 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) h256 expected = m_uriHashes[requestUrl]; bytes package(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); Secp256k1PP dec; - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); h256 got = sha3(package); if (got != expected) { //try base64 data = QByteArray::fromBase64(data); package = bytes(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); got = sha3(package); if (got != expected) throw dev::Exception() << errinfo_comment("Dapp content hash does not match"); @@ -145,6 +145,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) RLP rlp(package); loadDapp(rlp); + bytesRef(&package).cleanse(); // TODO: replace with bytesSec once the crypto API is up to it. } catch (...) { diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 7e73edc3b..efe5301bb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -833,29 +833,15 @@ void Main::readSettings(bool _skipGeometry) restoreGeometry(s.value("geometry").toByteArray()); restoreState(s.value("windowState").toByteArray()); - { - QByteArray b = s.value("address").toByteArray(); - if (!b.isEmpty()) - { - h256 k; - for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) - { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!m_keyManager.hasAccount(KeyPair(k).address())) - m_keyManager.import(k, "Imported (UNSAFE) key."); - } - } - } - { m_myIdentities.clear(); QByteArray b = s.value("identities").toByteArray(); if (!b.isEmpty()) { - h256 k; + Secret k; for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + memcpy(k.writable().data(), b.data() + i * sizeof(Secret), sizeof(Secret)); if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) m_myIdentities.append(KeyPair(k)); } @@ -947,7 +933,7 @@ void Main::on_importKey_triggered() bytes b = fromHex(s.toStdString()); if (b.size() == 32) { - auto k = KeyPair(h256(b)); + auto k = KeyPair(Secret(bytesConstRef(&b))); if (!m_keyManager.hasAccount(k.address())) { QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); @@ -1054,7 +1040,7 @@ void Main::on_exportKey_triggered() auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); Secret s = retrieveSecret(h); - QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex())); + QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.makeInsecure().hex())); } } diff --git a/eth/main.cpp b/eth/main.cpp index b50729197..590e3f372 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -522,7 +522,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice); } @@ -590,7 +590,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce); } @@ -650,7 +650,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; } catch (BadHexCharacter& _e) @@ -1143,13 +1143,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - if (config[0].size() == 32) // secret key - import and forget. - { - Secret s = config[0].toHash(); - toImport.push_back(s); - } - else // new format - just use it as an address. - signingKey = config[0].toHash
(); + signingKey = config[0].toHash
(); beneficiary = config[1].toHash
(); } @@ -1296,13 +1290,13 @@ int main(int argc, char** argv) else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); signingKey = toAddress(s); } else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); sessionKey = toAddress(s); } else if ((arg == "--sign-key") && i + 1 < argc) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index af7d8e048..3505d5528 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -192,7 +192,7 @@ public: { KeyPair k(Secret::random()); while (m_icap && k.address()[0]) - k = KeyPair(sha3(k.secret())); + k = KeyPair(Secret(sha3(k.secret().ref()))); return k; } @@ -352,7 +352,7 @@ public: if (m_lock.empty()) m_lock = createPassword("Enter a password with which to secure this account: "); auto k = makeKey(); - h128 u = store.importSecret(k.secret().asBytes(), m_lock); + h128 u = store.importSecret(k.secret().ref(), m_lock); cout << "Created key " << toUUID(u) << endl; cout << " Address: " << k.address().hex() << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl; @@ -362,12 +362,12 @@ public: for (string const& input: m_inputs) { h128 u; - bytes b; - b = fromHex(input); + bytesSec b; + b.writable() = fromHex(input); if (b.size() != 32) { std::string s = contentsString(input); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = store.importKey(input); } @@ -386,18 +386,18 @@ public: if (!contents(i).empty()) { h128 u = store.readKey(i, false); - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); cout << "Key " << i << ":" << endl; cout << " UUID: " << toUUID(u) << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else if (h128 u = fromUUID(i)) { - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); cout << "Key " << i << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else cerr << "Couldn't inspect " << i << "; not found." << endl; @@ -454,12 +454,12 @@ public: { string const& i = m_inputs[0]; h128 u; - bytes b; - b = fromHex(i); + bytesSec b; + b.writable() = fromHex(i); if (b.size() != 32) { std::string s = contentsString(i); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = wallet.store().importKey(i); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 0d632a550..b7eca90f6 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -80,11 +80,34 @@ using bytesRef = vector_ref; using bytesConstRef = vector_ref; template -class secure_vector: public std::vector +class secure_vector { public: - template secure_vector(Args&& ... _args): std::vector(_args ...) {} - ~secure_vector() { vector_ref(this).cleanse(); } + secure_vector() {} + secure_vector(secure_vector const& _c) = default; + explicit secure_vector(unsigned _size): m_data(_size) {} + explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {} + explicit secure_vector(std::vector const& _c): m_data(_c) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + ~secure_vector() { ref().cleanse(); } + + secure_vector& operator=(secure_vector const& _c) { ref().cleanse(); m_data = _c.m_data; return *this; } + std::vector& writable() { clear(); return m_data; } + std::vector const& makeInsecure() const { return m_data; } + + void clear() { ref().cleanse(); } + + vector_ref ref() { return vector_ref(&m_data); } + vector_ref ref() const { return vector_ref(&m_data); } + + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } + + void swap(secure_vector& io_other) { m_data.swap(io_other.m_data); } + +private: + std::vector m_data; }; using bytesSec = secure_vector; diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h index ade089e16..58938d2b2 100644 --- a/libdevcore/CommonJS.h +++ b/libdevcore/CommonJS.h @@ -51,10 +51,17 @@ inline std::string toJS(bytes const& _n, std::size_t _padding = 0) return "0x" + toHex(n); } -template< typename T >std::string toJS( T const& i ) +template std::string toJS(SecureFixedHash const& _i) { std::stringstream stream; - stream << "0x" << std::hex << i; + stream << "0x" << _i.makeInsecure().hex(); + return stream.str(); +} + +template std::string toJS(T const& _i) +{ + std::stringstream stream; + stream << "0x" << std::hex << _i; return stream.str(); } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 98d457da3..0de2cc825 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -220,6 +220,77 @@ private: std::array m_data; ///< The binary data. }; +template +class SecureFixedHash: private FixedHash +{ +public: + using ConstructFromHashType = typename FixedHash::ConstructFromHashType; + using ConstructFromStringType = typename FixedHash::ConstructFromStringType; + using ConstructFromPointerType = typename FixedHash::ConstructFromPointerType; + SecureFixedHash() = default; + explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b.ref(), _t) {} + template explicit SecureFixedHash(FixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h, _t) {} + template explicit SecureFixedHash(SecureFixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h.makeInsecure(), _t) {} + explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash::FromHex, ConstructFromHashType _ht = FixedHash::FailIfDifferent): FixedHash(_s, _t, _ht) {} + explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash(_d, _t) {} + ~SecureFixedHash() { ref().cleanse(); } + + SecureFixedHash& operator=(SecureFixedHash const& _c) { ref().cleanse(); FixedHash::operator=(static_cast const&>(_c)); return *this; } + + using FixedHash::size; + + bytesSec asBytesSec() const { return bytesSec(ref()); } + + FixedHash const& makeInsecure() const { return static_cast const&>(*this); } + FixedHash& writable() { clear(); return static_cast&>(*this); } + + using FixedHash::operator bool; + + // The obvious comparison operators. + bool operator==(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator==(static_cast const&>(_c)); } + bool operator!=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator!=(static_cast const&>(_c)); } + bool operator<(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<(static_cast const&>(_c)); } + bool operator>=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>=(static_cast const&>(_c)); } + bool operator<=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<=(static_cast const&>(_c)); } + bool operator>(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>(static_cast const&>(_c)); } + + using FixedHash::operator==; + using FixedHash::operator!=; + using FixedHash::operator<; + using FixedHash::operator>=; + using FixedHash::operator<=; + using FixedHash::operator>; + + // The obvious binary operators. + SecureFixedHash& operator^=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator^(FixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator|(FixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator&(FixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + + SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + SecureFixedHash operator~() const { ~static_cast&>(*this); return *this; } + + using FixedHash::abridged; + using FixedHash::abridgedMiddle; + + bytesConstRef ref() const { return FixedHash::ref(); } + byte const* data() const { return FixedHash::data(); } + + static SecureFixedHash random() { SecureFixedHash ret; ret.FixedHash::ref().randomize(); return ret; } + using FixedHash::firstBitSet; + + void clear() { ref().cleanse(); } +}; + /// Fast equality operator for h256. template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const { @@ -246,6 +317,14 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) return _out; } +/// Stream I/O for the SecureFixedHash class. +template +inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash const& _h) +{ + _out << "SecureFixedHash#" << std::hex << typename FixedHash::hash()(_h.makeInsecure()) << std::dec; + return _out; +} + // Common types of FixedHash. using h2048 = FixedHash<256>; using h1024 = FixedHash<128>; diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp index 880f23d6e..ea1f0de22 100644 --- a/libdevcore/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -211,13 +211,14 @@ defsha3(512) } -h256 sha3(bytesConstRef _input) +bool sha3(bytesConstRef _input, bytesRef o_output) { // FIXME: What with unaligned memory? - h256 ret; - keccak::sha3_256(ret.data(), 32, _input.data(), _input.size()); + if (o_output.size() != 32) + return false; + keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); - return ret; + return true; } } diff --git a/libdevcore/SHA3.h b/libdevcore/SHA3.h index c3ef524fe..7be2367e9 100644 --- a/libdevcore/SHA3.h +++ b/libdevcore/SHA3.h @@ -32,20 +32,31 @@ namespace dev // SHA-3 convenience routines. -/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -h256 sha3(bytesConstRef _input); - /// Calculate SHA3-256 hash of the given input and load it into the given output. -inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); } +/// @returns false if o_output.size() != 32. +bool sha3(bytesConstRef _input, bytesRef o_output); + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } +inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().ref()); return ret; } /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } +inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(bytesConstRef(&_input)); } /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(bytesConstRef(_input)); } /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(FixedHash const& _input) { return sha3Secure(_input.ref()); } + +/// Fully secure variants are equivalent for sha3 and sha3Secure. +inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); } +inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 6f2bff5bd..1932a8fda 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -5,11 +5,13 @@ #include #include #include +#include namespace dev { static unsigned char s_cleanseCounter = 0; +static std::random_device s_vectorRefEngine; /** * A modifiable reference to an existing object or vector in memory. @@ -67,6 +69,16 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Populate with random data. + template + void randomize(Engine& _eng) + { + uint8_t* e = (uint8_t*)end(); + for (uint8_t* i = (uint8_t*)begin(); i != e; ++i) + *i = (uint8_t)std::uniform_int_distribution(0, 255)(_eng); + } + /// @returns a random valued object. + void randomize() { randomize(s_vectorRefEngine); } /// Securely overwrite the memory. /// @note adapted from OpenSSL's implementation. void cleanse() diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h index 6aaed6fad..f4f425d88 100644 --- a/libdevcrypto/AES.h +++ b/libdevcrypto/AES.h @@ -71,7 +71,7 @@ class AuthenticatedStream: public Stream public: AuthenticatedStream(StreamType _t, h128 _ckey, h128 _mackey, unsigned _interval): Stream(_t, _ckey), m_macSecret(_mackey) { m_macInterval = _interval; } - AuthenticatedStream(StreamType _t, Secret const& _s, unsigned _interval): Stream(_t, h128(_s)), m_macSecret(FixedHash<16>((byte const*)_s.data()+16,h128::ConstructFromPointer)) { m_macInterval = _interval; } + AuthenticatedStream(StreamType _t, Secret const& _s, unsigned _interval): Stream(_t, h128(_s.makeInsecure())), m_macSecret(FixedHash<16>((byte const*)_s.data() + 16, h128::ConstructFromPointer)) { m_macInterval = _interval; } /// Adjust mac interval. Next mac will be xored with value. void adjustInterval(unsigned _interval) { m_macInterval = _interval; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b64535f51..4e663676b 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -147,7 +147,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) return decrypt(_k, _cipher, o_plain); } -std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) +std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) { h128 iv(Nonce::get()); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); @@ -173,23 +173,23 @@ bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _pl } } -bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) +bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) { if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) - return bytes(); + return bytesSec(); SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); - bytes ret(_cipher.size()); - d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); + bytesSec ret(_cipher.size()); + d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - return bytes(); + return bytesSec(); } } @@ -237,12 +237,12 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) #endif } -bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) +bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (PKCS5_PBKDF2_HMAC().DeriveKey( - ret.data(), - ret.size(), + ret.writable().data(), + _dkLen, 0, reinterpret_cast(_pass.data()), _pass.size(), @@ -254,9 +254,9 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, return ret; } -bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (libscrypt_scrypt( reinterpret_cast(_pass.data()), _pass.size(), @@ -265,8 +265,8 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin _n, _r, _p, - ret.data(), - ret.size() + ret.writable().data(), + _dkLen ) != 0) BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); return ret; @@ -283,7 +283,7 @@ KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) { - KeyPair ret(FixedHash<32>::random()); + KeyPair ret(Secret::random()); if (ret.address()) return ret; } @@ -292,7 +292,7 @@ KeyPair KeyPair::create() KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { - return KeyPair(sha3(aesDecrypt(_seed, _password))); + return KeyPair(Secret(sha3(aesDecrypt(_seed, _password)))); } h256 crypto::kdf(Secret const& _priv, h256 const& _hash) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 44d1c8155..c90481cb4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -32,15 +32,7 @@ namespace dev { -/// A secret key: 32 bytes. -/// @NOTE This is not endian-specific; it's just a bunch of bytes. -class Secret: public h256 -{ -public: - template Secret(Args&& ... _args): h256(_args ...) {} - Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} - ~Secret() { ref().cleanse(); } -}; +using Secret = SecureFixedHash<32>; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -82,7 +74,7 @@ using Addresses = h160s; using AddressHash = std::unordered_set; /// A vector of secrets. -using Secrets = h256s; +using Secrets = std::vector; /// Convert a secret key into the public key equivalent. Public toPublic(Secret const& _secret); @@ -116,21 +108,21 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypts payload with random IV/ctr using AES128-CTR. -std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); +std::pair encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); /// Decrypts payload with specified IV/ctr using AES128-CTR. -bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); +bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); /// Encrypts payload with specified IV/ctr using AES128-CTR. -inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } -inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } /// Decrypts payload with specified IV/ctr using AES128-CTR. -inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } -inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); @@ -142,10 +134,10 @@ Signature sign(Secret const& _k, h256 const& _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash); /// Derive key via PBKDF2. -bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); +bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); /// Derive key via Scrypt. -bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); +bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. @@ -176,8 +168,8 @@ public: /// Retrieve the associated address of the public key. Address const& address() const { return m_address; } - bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; } - bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } + bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } + bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } private: void populateFromSecret(Secret const& _k); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 693952d5f..6366f0da1 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -67,7 +67,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) { // interop w/go ecies implementation auto r = KeyPair::create(); - h256 z; + Secret z; ecdh::agree(r.sec(), _k, z); auto key = eciesKDF(z, bytes(), 32); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); @@ -77,7 +77,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) bytes mKey(32); ctx.Final(mKey.data()); - bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); + bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; @@ -110,8 +110,8 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) // invalid message: length return false; - h256 z; - ecdh::agree(_k, *(Public*)(io_text.data()+1), z); + Secret z; + ecdh::agree(_k, *(Public*)(io_text.data() + 1), z); auto key = eciesKDF(z, bytes(), 64); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); @@ -137,7 +137,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) if (mac[i] != msgMac[i]) return false; - plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); + plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); io_text.resize(plain.size()); io_text.swap(plain); @@ -222,7 +222,7 @@ Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash) Integer kInv = k.InverseMod(m_q); Integer z(_hash.asBytes().data(), 32); - Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; + Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q; if (r == 0 || s == 0) BOOST_THROW_EXCEPTION(InvalidState()); @@ -310,7 +310,7 @@ bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p) return true; } -void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) +void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s) { // TODO: mutex ASN1::secp256k1() singleton // Creating Domain is non-const for m_oid and m_oid is not thread-safe @@ -318,7 +318,7 @@ void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; memcpy(&remote[1], _r.data(), 64); - d.Agree(o_s.data(), _s.data(), remote); + d.Agree(o_s.writable().data(), _s.data(), remote); } void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& o_p) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index fca094242..564d1c5c0 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -107,10 +107,10 @@ public: /// Verifies _s is a valid secret key and returns corresponding public key in o_p. bool verifySecret(Secret const& _s, Public& o_p); - void agree(Secret const& _s, Public const& _r, h256& o_s); + void agree(Secret const& _s, Public const& _r, Secret& o_s); protected: - void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); } + void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); } void exportPublicKey(DL_PublicKey_EC const& _k, Public& o_p); diff --git a/libdevcrypto/ECDHE.cpp b/libdevcrypto/ECDHE.cpp index f9e55f676..2c425fd47 100644 --- a/libdevcrypto/ECDHE.cpp +++ b/libdevcrypto/ECDHE.cpp @@ -29,7 +29,7 @@ using namespace dev::crypto; static Secp256k1PP s_secp256k1; -void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s) +void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) { s_secp256k1.agree(_s, _r, o_s); } diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index 6d4a68203..8f39fe017 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -51,7 +51,7 @@ private: namespace ecdh { -void agree(Secret const& _s, Public const& _r, h256& o_s); +void agree(Secret const& _s, Public const& _r, Secret& o_s); } /** diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index b823ba02f..266f3735a 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -100,17 +100,17 @@ bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bytesSec key; if (it != m_keys.end()) { - key = decrypt(it->second.encryptedKey, _pass()); + key = bytesSec(decrypt(it->second.encryptedKey, _pass())); if (!key.empty()) m_cached[_uuid] = key; } return key; } -h128 SecretStore::importSecret(bytes const& _s, string const& _pass) +h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass) { h128 r; - EncryptedKey key{encrypt(_s, _pass), string()}; + EncryptedKey key{encrypt(_s.ref(), _pass), string()}; r = h128::random(); m_cached[r] = _s; m_keys[r] = move(key); @@ -118,6 +118,17 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass) return r; } +h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass) +{ + h128 r; + EncryptedKey key{encrypt(_s, _pass), string()}; + r = h128::random(); + m_cached[r] = bytesSec(_s); + m_keys[r] = move(key); + save(); + return r; +} + void SecretStore::kill(h128 const& _uuid) { m_cached.erase(_uuid); @@ -188,16 +199,16 @@ h128 SecretStore::readKeyContent(string const& _content, string const& _file) bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function const& _pass, KDF _kdf) { - bytes s = secret(_uuid, _pass, true); + bytesSec s = secret(_uuid, _pass, true); if (s.empty()) return false; m_cached.erase(_uuid); - m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf); + m_keys[_uuid].encryptedKey = encrypt(s.ref(), _newPass, _kdf); save(); return true; } -static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) +static bytesSec deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) { unsigned dklen = 32; unsigned iterations = 1 << 18; @@ -233,16 +244,16 @@ static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) } } -string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) +string SecretStore::encrypt(bytesConstRef _v, string const& _pass, KDF _kdf) { js::mObject ret; - bytes derivedKey = deriveNewKey(_pass, _kdf, ret); + bytesSec derivedKey = deriveNewKey(_pass, _kdf, ret); if (derivedKey.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed.")); ret["cipher"] = "aes-128-ctr"; - h128 key(derivedKey, h128::AlignLeft); + SecureFixedHash<16> key(derivedKey, h128::AlignLeft); h128 iv = h128::random(); { js::mObject params; @@ -251,19 +262,19 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) } // cipher text - bytes cipherText = encryptSymNoAuth(key, iv, &_v); + bytes cipherText = encryptSymNoAuth(key, iv, _v); if (cipherText.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed.")); ret["ciphertext"] = toHex(cipherText); // and mac. - h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); + h256 mac = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); ret["mac"] = toHex(mac.ref()); return js::write_string(js::mValue(ret), true); } -bytes SecretStore::decrypt(string const& _v, string const& _pass) +bytesSec SecretStore::decrypt(string const& _v, string const& _pass) { js::mObject o; { @@ -273,14 +284,14 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) } // derive key - bytes derivedKey; + bytesSec derivedKey; if (o["kdf"].get_str() == "pbkdf2") { auto params = o["kdfparams"].get_obj(); if (params["prf"].get_str() != "hmac-sha256") { cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } unsigned iterations = params["c"].get_int(); bytes salt = fromHex(params["salt"].get_str()); @@ -294,13 +305,13 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) else { cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2")) { cwarn << "Derived key's length too short (<32 bytes)"; - return bytes(); + return bytesSec(); } bytes cipherText = fromHex(o["ciphertext"].get_str()); @@ -311,23 +322,23 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h256 mac(o["mac"].get_str()); h256 macExp; if (o.count("compat") && o["compat"].get_str() == "2") - macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); else - macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else if (o.count("sillymac")) { h256 mac(o["sillymac"].get_str()); - h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else @@ -340,15 +351,15 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h128 iv(params["iv"].get_str()); if (o.count("compat") && o["compat"].get_str() == "2") { - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + SecureFixedHash<16> key(sha3Secure(derivedKey.ref().cropped(derivedKey.size() - 16)), h128::AlignRight); return decryptSymNoAuth(key, iv, &cipherText); } else - return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText); + return decryptSymNoAuth(SecureFixedHash<16>(derivedKey, h128::AlignLeft), iv, &cipherText); } else { cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } } diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index ea08a48b2..fbc4c0bec 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -60,7 +60,8 @@ public: h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } /// Imports the decrypted key given by @a _s and stores it, encrypted with /// (a key derived from) the password @a _pass. - h128 importSecret(bytes const& _s, std::string const& _pass); + h128 importSecret(bytesSec const& _s, std::string const& _pass); + h128 importSecret(bytesConstRef _s, std::string const& _pass); /// Decrypts and re-encrypts the key identified by @a _uuid. bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); /// Removes the key specified by @a _uuid from both memory and disk. @@ -102,9 +103,9 @@ private: void load(std::string const& _keysPath); void load() { load(m_path); } /// Encrypts @a _v with a key derived from @a _pass or the empty string on error. - static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); + static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. - static bytes decrypt(std::string const& _v, std::string const& _pass); + static bytesSec decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. mutable std::unordered_map m_cached; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7ef3dd21e..ca58f65e3 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -101,7 +101,7 @@ private: if (_name == "authorities") BasicAuthority::s_authorities = rlp.toUnorderedSet
(); else if (_name == "authority") - m_secret = rlp.toHash(); + m_secret = Secret(rlp.toHash()); else return false; return true; diff --git a/libethcore/CommonJS.h b/libethcore/CommonJS.h index 0ff21afdf..fdd18d6e5 100644 --- a/libethcore/CommonJS.h +++ b/libethcore/CommonJS.h @@ -40,7 +40,7 @@ Address toAddress(std::string const& _a); inline Public jsToPublic(std::string const& _s) { return jsToFixed(_s); } /// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length. -inline Secret jsToSecret(std::string const& _s) { return jsToFixed(_s); } +inline Secret jsToSecret(std::string const& _s) { h256 d = jsToFixed(_s); Secret ret(d); d.ref().cleanse(); return ret; } /// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length. inline Address jsToAddress(std::string const& _s) { return jsToFixed(_s); } diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 26cf451d0..6d4dab1ce 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -81,9 +81,9 @@ bool KeyManager::load(string const& _pass) { bytes salt = contents(m_keysFile + ".salt"); bytes encKeys = contents(m_keysFile); - m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16)); - bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); - RLP s(bs); + m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); + bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); + RLP s(bs.ref()); unsigned version = unsigned(s[0]); if (version == 1) { @@ -178,7 +178,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con auto passHash = hashPassword(_pass); cachePassword(_pass); m_passwordHint[passHash] = _passwordHint; - auto uuid = m_store.importSecret(_s.asBytes(), _pass); + auto uuid = m_store.importSecret(_s.asBytesSec(), _pass); m_keyInfo[uuid] = KeyInfo{passHash, _accountName}; m_addrLookup[addr] = uuid; write(m_keysFile); @@ -187,7 +187,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint) { - bytes key = m_store.secret(_uuid, [&](){ return _pass; }); + bytesSec key = m_store.secret(_uuid, [&](){ return _pass; }); if (key.empty()) return; Address a = KeyPair(Secret(key)).address(); @@ -258,7 +258,7 @@ string const& KeyManager::passwordHint(Address const& _address) const h256 KeyManager::hashPassword(string const& _pass) const { // TODO SECURITY: store this a bit more securely; Scrypt perhaps? - return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32)); + return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure()); } void KeyManager::cachePassword(string const& _password) const @@ -278,14 +278,14 @@ void KeyManager::write(string const& _pass, string const& _keysFile) const { bytes salt = h256::random().asBytes(); writeFile(_keysFile + ".salt", salt); - auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); cachePassword(_pass); m_master = hashPassword(_pass); write(key, _keysFile); } -void KeyManager::write(h128 const& _key, string const& _keysFile) const +void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const { RLPStream s(4); s << 1; // version diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index a2b5a4e07..0fefc17ee 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -136,8 +136,8 @@ private: // @returns false if wasn't previously loaded ok. bool write() const { return write(m_keysFile); } bool write(std::string const& _keysFile) const; - void write(std::string const& _pass, std::string const& _keysFile) const; - void write(h128 const& _key, std::string const& _keysFile) const; + void write(std::string const& _pass, std::string const& _keysFile) const; // TODO: all passwords should be a secure string. + void write(SecureFixedHash<16> const& _key, std::string const& _keysFile) const; // Ethereum keys. @@ -159,7 +159,7 @@ private: std::string m_defaultPasswordDeprecated; mutable std::string m_keysFile; - mutable h128 m_keysFileKey; + mutable SecureFixedHash<16> m_keysFileKey; mutable h256 m_master; SecretStore m_store; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 46e0efe95..dd9ff53cf 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -809,7 +809,7 @@ bytes Host::saveNetwork() const // else: TODO: use previous configuration if available RLPStream ret(3); - ret << dev::p2p::c_protocolVersion << m_alias.secret(); + ret << dev::p2p::c_protocolVersion << m_alias.secret().ref(); ret.appendList(count); if (!!count) ret.appendRaw(network.out(), count); diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index e0ebd6c2d..4fee9b42b 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -40,7 +40,7 @@ void RLPXHandshake::writeAuth() // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) Secret staticShared; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared); - sign(m_ecdhe.seckey(), staticShared ^ m_nonce).ref().copyTo(sig); + sign(m_ecdhe.seckey(), staticShared.makeInsecure() ^ m_nonce).ref().copyTo(sig); sha3(m_ecdhe.pubkey().ref(), hepubk); m_host->m_alias.pub().ref().copyTo(pubk); m_nonce.ref().copyTo(nonce); @@ -92,7 +92,7 @@ void RLPXHandshake::readAuth() Secret sharedSecret; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret); - m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); + m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret.makeInsecure() ^ m_remoteNonce); if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index bf18835b6..3216cc90b 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -60,7 +60,7 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes for (unsigned i = 0; i < _e.topic().size(); ++i) if (_e.topic()[i] == knownTopic[ti]) { - topicSecret = _fk[ti]; + topicSecret = Secret(_fk[ti]); topicIndex = i; break; } @@ -69,9 +69,9 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes return false; unsigned index = topicIndex * 2; - h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); + Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size)); - h256 key = generateGamma(topicSecret, salt) ^ encryptedKey; + Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure()); bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size()); return decryptSym(key, cipherText, o_b); } @@ -122,10 +122,10 @@ Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned // this message is for broadcast (could be read by anyone who knows at least one of the topics) // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic Secret s = Secret::random(); - for (h256 const& t : _fullTopics) + for (h256 const& t: _fullTopics) { h256 salt = h256::random(); - ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); + ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes(); ret.m_data += salt.asBytes(); } diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 1ec28ae01..c29194e97 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -127,7 +127,7 @@ public: private: bool populate(bytes const& _data); bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); - h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } + Secret generateGamma(Secret const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Public m_from; Public m_to; diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 0a583f2a0..1c9faa896 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -187,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) bytes dapp = rlpStr.out(); dev::h256 dappHash = dev::sha3(dapp); //encrypt - KeyPair key(dappHash); + KeyPair key((Secret(dappHash))); Secp256k1PP enc; enc.encrypt(key.pub(), dapp); diff --git a/test/libdevcrypto/AES.cpp b/test/libdevcrypto/AES.cpp index 06f0515d6..e8a04393c 100644 --- a/test/libdevcrypto/AES.cpp +++ b/test/libdevcrypto/AES.cpp @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(AesDecrypt) { cout << "AesDecrypt" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address()); } @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed) { cout << "AesDecryptWrongSeed" << endl; bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword) { cout << "AesDecryptWrongPassword" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "badtest"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "badtest"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 30bff49d9..bff6e0720 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -61,9 +61,9 @@ BOOST_AUTO_TEST_CASE(basic_tests) SecretStore store(tmpDir.path()); h128 u = store.readKeyContent(js::write_string(o["json"], false)); cdebug << "read uuid" << u; - bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); - cdebug << "got secret" << toHex(s); - BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str()); + bytesSec s = store.secret(u, [&](){ return o["password"].get_str(); }); + cdebug << "got secret" << toHex(s.makeInsecure()); + BOOST_REQUIRE_EQUAL(toHex(s.makeInsecure()), o["priv"].get_str()); } } @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) uuid = store.importKey(importFile); BOOST_CHECK(!!uuid); BOOST_CHECK(contentsString(importFile) == keyData); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } fs::remove(importFile); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } @@ -121,15 +121,15 @@ BOOST_AUTO_TEST_CASE(import_secret) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } } @@ -145,12 +145,12 @@ BOOST_AUTO_TEST_CASE(wrong_password) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); // password will not be queried - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }).makeInsecure())); } { SecretStore store(storeDir.path()); @@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE(recode) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { @@ -182,16 +182,16 @@ BOOST_AUTO_TEST_CASE(recode) BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; })); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); store.clearCache(); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } } diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index c94cc4e8f..a788319a8 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_patch) BOOST_AUTO_TEST_CASE(verify_secert) { - h256 empty; + Secret empty; KeyPair kNot(empty); BOOST_REQUIRE(!kNot.address()); KeyPair k(sha3(empty)); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) bytes e(fromHex("0x01")); e.resize(32); int tests = 2; - while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + while (sha3(&e, &e), secret = sha3(secret), tests--) { KeyPair key(secret); Public pkey = key.pub(); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) Integer r = s_params.ConvertElementToInteger(rp); Integer kInv = kInt.InverseMod(q); - Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; + Integer s = (kInv * (Integer(secret.data(), 32) * r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); Signature sig; @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(ecies_kdf) BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes()); BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes()); - BOOST_REQUIRE((u256)h256(z1) > 0); + BOOST_REQUIRE(!!z1); BOOST_REQUIRE(z1 == z2); BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0); @@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(ecdh) ECDH::Domain dhA(s_curveOID); Secret shared; - BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); + BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.sec().data(), pubb)); BOOST_REQUIRE(shared); } @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA); - sign(eA.seckey(), ssA ^ nonceA).ref().copyTo(sig); + sign(eA.seckey(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig); sha3(eA.pubkey().ref(), hepubk); nodeA.pub().ref().copyTo(pubk); nonceA.ref().copyTo(nonce); @@ -520,21 +520,21 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - aEncryptK = sha3(keyMaterial); + aEncryptK = sha3Secure(keyMaterial); aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - aMacK = sha3(keyMaterial); + aMacK = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceBAck).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - aEgressMac = sha3(keyMaterial); + aEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceA).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - aIngressMac = sha3(keyMaterial); + aIngressMac = sha3Secure(keyMaterial); } @@ -573,7 +573,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) Secret ss; s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss); - eAAuth = recover(sigAuth, ss ^ nonceAAuth); + eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure()); // todo: test when this fails; means remote is bad or packet bits were flipped BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth)); BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey()); @@ -588,22 +588,22 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - bEncryptK = sha3(keyMaterial); + bEncryptK = sha3Secure(keyMaterial); bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - bMacK = sha3(keyMaterial); + bMacK = sha3Secure(keyMaterial); // todo: replace nonceB with decrypted nonceB keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - bEgressMac = sha3(keyMaterial); + bEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceB).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - bIngressMac = sha3(keyMaterial); + bIngressMac = sha3Secure(keyMaterial); } BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK); @@ -617,7 +617,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) { - h128 encryptK(sha3("..."), h128::AlignLeft); + SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft); h256 egressMac(sha3("+++")); // TESTING: send encrypt magic sequence bytes magic {0x22,0x40,0x08,0x91}; @@ -629,16 +629,17 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); - bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); + bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure(); plaintext.resize(magic.size()); + // @alex @subtly TODO: FIX: this check is pointless with the above line. BOOST_REQUIRE(plaintext.size() > 0); BOOST_REQUIRE(magic == plaintext); } BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) { - h128 k(sha3("0xAAAA"), h128::AlignLeft); + SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft); string m = "AAAAAAAAAAAAAAAA"; bytesConstRef msg((byte*)m.data(), m.size()); @@ -646,7 +647,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) h128 iv; tie(ciphertext, iv) = encryptSymNoAuth(k, msg); - bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); + bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure(); BOOST_REQUIRE_EQUAL(asString(plaintext), m); } diff --git a/test/libethcore/commonjs.cpp b/test/libethcore/commonjs.cpp index 72582c540..ca472a6f4 100644 --- a/test/libethcore/commonjs.cpp +++ b/test/libethcore/commonjs.cpp @@ -32,8 +32,8 @@ BOOST_AUTO_TEST_CASE(jsToPublic) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.pub()); - Public pub = dev::jsToPublic(string); + string s = toJS(kp.pub()); + Public pub = dev::jsToPublic(s); BOOST_CHECK_EQUAL(kp.pub(), pub); } @@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(jsToAddress) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.address()); - Address address = dev::jsToAddress(string); + string s = toJS(kp.address()); + Address address = dev::jsToAddress(s); BOOST_CHECK_EQUAL(kp.address(), address); } @@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE(jsToSecret) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.secret()); - Secret secret = dev::jsToSecret(string); - BOOST_CHECK_EQUAL(kp.secret(), secret); + string s = toJS(kp.secret().makeInsecure()); + Secret secret = dev::jsToSecret(s); + BOOST_CHECK_EQUAL(kp.secret().makeInsecure(), secret.makeInsecure()); } BOOST_AUTO_TEST_SUITE_END() From 3a61c2577e8e64812aaef2e3f6e4da712d876602 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 24 Jul 2015 23:23:39 +0200 Subject: [PATCH 22/53] CL: switch to chunks if clEnqueuWriteBuffer fails Probably fixes #2559 even though chunking is not stable at the moment. --- libethash-cl/ethash_cl_miner.cpp | 37 +++++++++++--------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 982e4ec9d..8042888cb 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -361,15 +361,22 @@ bool ethash_cl_miner::init( try { m_dagChunksCount = 1; + ETHCL_LOG("Creating one big buffer for the DAG"); m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); - ETHCL_LOG("Created one big buffer for the DAG"); + ETHCL_LOG("Loading single big chunk kernels"); + m_hashKernel = cl::Kernel(program, "ethash_hash"); + m_searchKernel = cl::Kernel(program, "ethash_search"); + ETHCL_LOG("Mapping one big chunk."); + m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); } catch (cl::Error const& err) { int errCode = err.err(); if (errCode != CL_INVALID_BUFFER_SIZE || errCode != CL_MEM_OBJECT_ALLOCATION_FAILURE) - ETHCL_LOG("Allocating single buffer failed with: " << err.what() << "(" << errCode << ")"); + ETHCL_LOG("Allocating/mapping single buffer failed with: " << err.what() << "(" << errCode << ")"); cl_ulong result; + // if we fail midway on the try above make sure we start clean + m_dagChunks.clear(); device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); ETHCL_LOG( "Failed to allocate 1 big chunk. Max allocateable memory is " @@ -387,32 +394,9 @@ bool ethash_cl_miner::init( (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7 )); } - } - - if (m_dagChunksCount == 1) - { - ETHCL_LOG("Loading single big chunk kernels"); - m_hashKernel = cl::Kernel(program, "ethash_hash"); - m_searchKernel = cl::Kernel(program, "ethash_search"); - } - else - { ETHCL_LOG("Loading chunk kernels"); m_hashKernel = cl::Kernel(program, "ethash_hash_chunks"); m_searchKernel = cl::Kernel(program, "ethash_search_chunks"); - } - - // create buffer for header - ETHCL_LOG("Creating buffer for header."); - m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - - if (m_dagChunksCount == 1) - { - ETHCL_LOG("Mapping one big chunk."); - m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); - } - else - { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation void* dag_ptr[4]; for (unsigned i = 0; i < m_dagChunksCount; i++) @@ -426,6 +410,9 @@ bool ethash_cl_miner::init( m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); } } + // create buffer for header + ETHCL_LOG("Creating buffer for header."); + m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); // create mining buffers for (unsigned i = 0; i != c_bufferCount; ++i) From 2a7c56aef796964bedb27ac7fff1e212b4a98c91 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 23/53] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. --- alethzero/MainWin.cpp | 4 ++-- ethminer/CMakeLists.txt | 1 + libdevcore/Common.h | 10 ++++++++++ libdevcore/FixedHash.h | 2 ++ libdevcore/vector_ref.h | 20 ++++++++++++++++++++ libdevcrypto/Common.cpp | 14 +++++++------- libdevcrypto/Common.h | 12 ++++++++++-- libdevcrypto/CryptoPP.cpp | 2 +- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 4 ++-- libethcore/CMakeLists.txt | 4 +--- libethcore/Common.cpp | 2 +- libethereum/BlockChain.cpp | 7 ++----- libethereum/BlockChain.h | 13 +++++++++++-- libethereum/CanonBlockChain.cpp | 1 + libethereum/CanonBlockChain.h | 5 ++++- libethereumx/Ethereum.cpp | 4 ++-- libethereumx/Ethereum.h | 4 ++-- libweb3jsonrpc/JsonHelper.cpp | 2 +- libweb3jsonrpc/JsonHelper.h | 2 +- libwhisper/CMakeLists.txt | 4 ++-- libwhisper/Interface.h | 4 ++-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 4 ++-- mix/ClientModel.h | 2 +- test/libdevcrypto/crypto.cpp | 4 ++-- test/libethereum/stateOriginal.cpp | 4 ++-- 29 files changed, 97 insertions(+), 48 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 812721b53..b24d89a30 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -360,8 +360,8 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret _id = jsToSecret(_ids.toStdString()); - KeyPair kp(_id); + Secret const& id = jsToSecret(_ids.toStdString()); + KeyPair kp(id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 8b79afd72..cda6aa8b8 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -30,6 +30,7 @@ endif() target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} devcrypto) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 612b7c685..0d632a550 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -79,6 +79,16 @@ using bytes = std::vector; using bytesRef = vector_ref; using bytesConstRef = vector_ref; +template +class secure_vector: public std::vector +{ +public: + template secure_vector(Args&& ... _args): std::vector(_args ...) {} + ~secure_vector() { vector_ref(this).cleanse(); } +}; + +using bytesSec = secure_vector; + // Numeric types. using bigint = boost::multiprecision::number>; using u64 = boost::multiprecision::number>; diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 3127b349a..98d457da3 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -214,6 +214,8 @@ public: return ret; } + void clear() { m_data.fill(0); } + private: std::array m_data; ///< The binary data. }; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b05342f71..6f2bff5bd 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,8 @@ namespace dev { +static unsigned char s_cleanseCounter = 0; + /** * A modifiable reference to an existing object or vector in memory. */ @@ -65,6 +67,24 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + uint8_t* p = (uint8_t*)begin(); + size_t len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 7cc16bd03..b64535f51 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -272,6 +272,13 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin return ret; } +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (s_secp256k1pp.verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) @@ -283,13 +290,6 @@ KeyPair KeyPair::create() return KeyPair(); } -KeyPair::KeyPair(h256 _sec): - m_secret(_sec) -{ - if (s_secp256k1pp.verifySecret(m_secret, m_public)) - m_address = toAddress(m_public); -} - KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { return KeyPair(sha3(aesDecrypt(_seed, _password))); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9aeb85a4c..44d1c8155 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -34,7 +34,13 @@ namespace dev /// A secret key: 32 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. -using Secret = h256; +class Secret: public h256 +{ +public: + template Secret(Args&& ... _args): h256(_args ...) {} + Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} + ~Secret() { ref().cleanse(); } +}; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -151,7 +157,7 @@ public: KeyPair() {} /// Normal constructor - populates object from the given secret key. - KeyPair(Secret _k); + KeyPair(Secret const& _k) { populateFromSecret(_k); } /// Create a new, randomly generated object. static KeyPair create(); @@ -174,6 +180,8 @@ public: bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } private: + void populateFromSecret(Secret const& _k); + Secret m_secret; Public m_public; Address m_address; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 8beb8e495..693952d5f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -33,7 +33,7 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1PP::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) { auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); // SEC/ISO/Shoup specify counter size SHOULD be equivalent diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 6a0453330..fca094242 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -87,7 +87,7 @@ public: bool decryptECIES(Secret const& _k, bytes& io_text); /// Key derivation function used by encryptECIES and decryptECIES. - bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256); + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); /// @returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index 0fd5a8d3f..1a2442727 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -39,7 +39,7 @@ using AliasSession = std::pair; class Alias { public: - Alias(Secret _s): m_secret(_s) {}; + Alias(Secret const& _s): m_secret(_s) {}; AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 55c944e8e..b823ba02f 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -91,13 +91,13 @@ SecretStore::SecretStore(string const& _path): m_path(_path) load(); } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const +bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - bytes key; + bytesSec key; if (it != m_keys.end()) { key = decrypt(it->second.encryptedKey, _pass()); diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 029630b4e..ea08a48b2 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -52,7 +52,7 @@ public: /// @returns the secret key stored by the given @a _uuid. /// @param _pass function that returns the password for the key. /// @param _useCache if true, allow previously decrypted keys to be returned directly. - bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + bytesSec secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in @@ -107,7 +107,7 @@ private: static bytes decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. - mutable std::unordered_map m_cached; + mutable std::unordered_map m_cached; /// Stores encrypted keys together with the file they were loaded from by uuid. std::unordered_map m_keys; diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 73ea75c8c..d740da2a2 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -23,13 +23,11 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) - if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) endif () - +target_link_libraries(${EXECUTABLE} devcrypto) if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index b95564b9b..85121c4f0 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -65,7 +65,7 @@ Network resetNetwork(Network _n) c_gasLimitBoundDivisor = 1024; c_minimumDifficulty = 131072; c_difficultyBoundDivisor = 2048; - c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12; + c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); return _n; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 37fd68673..d639ba428 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -152,7 +152,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -165,9 +165,6 @@ void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); /// Open the database. - unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust); + unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); + /// Open the database, rebuilding if necessary. + void openDatabase(std::string const& _path, WithExisting _we, ProgressCallback const& _pc) + { + if (openDatabase(_path, _we) != c_minorProtocolVersion || _we == WithExisting::Verify) + rebuild(_path, _pc); + } + template T queryExtras(K const& _h, std::unordered_map& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const { { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 2a7408437..b921d67e4 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -47,6 +47,7 @@ bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) { + BlockChain::openDatabase(_path, _we, _pc); } void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d09108b38..0ff9c6521 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -52,7 +52,10 @@ class CanonBlockChain: public FullBlockChain public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): - FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) + { + BlockChain::openDatabase(_path, _we, _pc); + } ~CanonBlockChain() {} /// @returns the genesis block as its RLP-encoded byte array. diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 8ab4243a1..675614c1a 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes con return bytes(); } -Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 0e81b8e0c..1e24b396c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index c074525b9..9ccad947d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -482,7 +482,7 @@ shh::Message toMessage(Json::Value const& _json) return ret; } -shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret const& _from) { unsigned ttl = 50; unsigned workToProve = 50; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 11219fc55..9be59bcab 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -89,7 +89,7 @@ namespace shh Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); Message toMessage(Json::Value const& _json); -Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret const& _from); std::pair toWatch(Json::Value const& _json); } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 5af43d0b2..05bf2ae20 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -21,10 +21,10 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} p2p) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index f53cb17a7..21a1355f8 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -76,8 +76,8 @@ public: void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index dd72ff734..bf18835b6 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { AbridgedTopics topics = abridge(_fullTopics); Envelope ret(time(0) + _ttl, _ttl, topics); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 4d8b34548..1ec28ae01 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -118,11 +118,11 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret const& _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } + Envelope sealTo(Secret const& _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bf88ad66a..cff767dad 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -55,7 +55,7 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret const& _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index b70eae36e..c94cc4e8f 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eA.agree(eBAck, ess); ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); @@ -581,7 +581,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eB.agree(eAAuth, ess); // s_secp256k1.agree(eB.seckey(), eAAuth, ess); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 163c89e50..9a806c7c4 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(Complex) cnote << "Testing State..."; - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); + KeyPair me = Secret(sha3("Gav Wood")); + KeyPair myMiner = Secret(sha3("Gav's Miner")); // KeyPair you = sha3("123"); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); From 195c9614b37343581cbb037c692d637a2a63e46c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:53:14 +0200 Subject: [PATCH 24/53] Hold address-sorting back. --- alethzero/MainWin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b24d89a30..97e2ba032 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1340,9 +1340,7 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - auto as = ethereum()->addresses(); - sort(as.begin(), as.end()); - for (auto const& i: as) + for (auto const& i: ethereum()->addresses()) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) From 5517e44e38c6d6ff738d56d9023701e364135e8d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 21:31:06 +0200 Subject: [PATCH 25/53] SHA3 gas calc should use bigint to avoid overflow. Fixes #2582. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f95481c54..9d89ce497 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -103,7 +103,7 @@ void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::SHA3: - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + runGas = c_sha3Gas + ((bigint)m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: From f9604289410f5a4223472dad8bc82864c023e54f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 22:13:49 +0200 Subject: [PATCH 26/53] Fix const& where it should have been value. --- alethzero/MainWin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 97e2ba032..4d279e649 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -360,8 +360,7 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret const& id = jsToSecret(_ids.toStdString()); - KeyPair kp(id); + KeyPair kp(jsToSecret(_ids.toStdString())); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); From 818fa25bbab9006997d3d13fcca0439018f93efa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 27/53] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. --- alethzero/DappLoader.cpp | 5 +- alethzero/MainWin.cpp | 22 ++------- eth/main.cpp | 18 +++---- ethkey/KeyAux.h | 24 +++++----- libdevcore/Common.h | 29 ++++++++++-- libdevcore/CommonJS.h | 11 ++++- libdevcore/FixedHash.h | 79 +++++++++++++++++++++++++++++++ libdevcore/SHA3.cpp | 9 ++-- libdevcore/SHA3.h | 19 ++++++-- libdevcore/vector_ref.h | 12 +++++ libdevcrypto/AES.h | 2 +- libdevcrypto/Common.cpp | 32 ++++++------- libdevcrypto/Common.h | 32 +++++-------- libdevcrypto/CryptoPP.cpp | 16 +++---- libdevcrypto/CryptoPP.h | 4 +- libdevcrypto/ECDHE.cpp | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 59 +++++++++++++---------- libdevcrypto/SecretStore.h | 7 +-- libethcore/BasicAuthority.cpp | 2 +- libethcore/CommonJS.h | 2 +- libethcore/KeyManager.cpp | 16 +++---- libethcore/KeyManager.h | 6 +-- libp2p/Host.cpp | 2 +- libp2p/RLPxHandshake.cpp | 4 +- libwhisper/Message.cpp | 10 ++-- libwhisper/Message.h | 2 +- mix/FileIo.cpp | 2 +- test/libdevcrypto/AES.cpp | 6 +-- test/libdevcrypto/SecretStore.cpp | 32 ++++++------- test/libdevcrypto/crypto.cpp | 39 +++++++-------- test/libethcore/commonjs.cpp | 14 +++--- 32 files changed, 320 insertions(+), 201 deletions(-) diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index a91531f89..3da3e8c35 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -130,14 +130,14 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) h256 expected = m_uriHashes[requestUrl]; bytes package(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); Secp256k1PP dec; - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); h256 got = sha3(package); if (got != expected) { //try base64 data = QByteArray::fromBase64(data); package = bytes(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); got = sha3(package); if (got != expected) throw dev::Exception() << errinfo_comment("Dapp content hash does not match"); @@ -145,6 +145,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) RLP rlp(package); loadDapp(rlp); + bytesRef(&package).cleanse(); // TODO: replace with bytesSec once the crypto API is up to it. } catch (...) { diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4d279e649..250c746a5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -845,29 +845,15 @@ void Main::readSettings(bool _skipGeometry) restoreGeometry(s.value("geometry").toByteArray()); restoreState(s.value("windowState").toByteArray()); - { - QByteArray b = s.value("address").toByteArray(); - if (!b.isEmpty()) - { - h256 k; - for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) - { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!m_keyManager.hasAccount(KeyPair(k).address())) - m_keyManager.import(k, "Imported (UNSAFE) key."); - } - } - } - { m_myIdentities.clear(); QByteArray b = s.value("identities").toByteArray(); if (!b.isEmpty()) { - h256 k; + Secret k; for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + memcpy(k.writable().data(), b.data() + i * sizeof(Secret), sizeof(Secret)); if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) m_myIdentities.append(KeyPair(k)); } @@ -960,7 +946,7 @@ void Main::on_importKey_triggered() bytes b = fromHex(s.toStdString()); if (b.size() == 32) { - auto k = KeyPair(h256(b)); + auto k = KeyPair(Secret(bytesConstRef(&b))); if (!m_keyManager.hasAccount(k.address())) { QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); @@ -1067,7 +1053,7 @@ void Main::on_exportKey_triggered() auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); Secret s = retrieveSecret(h); - QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex())); + QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.makeInsecure().hex())); } } diff --git a/eth/main.cpp b/eth/main.cpp index 978e8bc44..ebea5266d 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -525,7 +525,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice); } @@ -593,7 +593,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce); } @@ -653,7 +653,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; } catch (BadHexCharacter& _e) @@ -1146,13 +1146,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - if (config[0].size() == 32) // secret key - import and forget. - { - Secret s = config[0].toHash(); - toImport.push_back(s); - } - else // new format - just use it as an address. - signingKey = config[0].toHash
(); + signingKey = config[0].toHash
(); beneficiary = config[1].toHash
(); } @@ -1299,13 +1293,13 @@ int main(int argc, char** argv) else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); signingKey = toAddress(s); } else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); sessionKey = toAddress(s); } else if ((arg == "--sign-key") && i + 1 < argc) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index af7d8e048..3505d5528 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -192,7 +192,7 @@ public: { KeyPair k(Secret::random()); while (m_icap && k.address()[0]) - k = KeyPair(sha3(k.secret())); + k = KeyPair(Secret(sha3(k.secret().ref()))); return k; } @@ -352,7 +352,7 @@ public: if (m_lock.empty()) m_lock = createPassword("Enter a password with which to secure this account: "); auto k = makeKey(); - h128 u = store.importSecret(k.secret().asBytes(), m_lock); + h128 u = store.importSecret(k.secret().ref(), m_lock); cout << "Created key " << toUUID(u) << endl; cout << " Address: " << k.address().hex() << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl; @@ -362,12 +362,12 @@ public: for (string const& input: m_inputs) { h128 u; - bytes b; - b = fromHex(input); + bytesSec b; + b.writable() = fromHex(input); if (b.size() != 32) { std::string s = contentsString(input); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = store.importKey(input); } @@ -386,18 +386,18 @@ public: if (!contents(i).empty()) { h128 u = store.readKey(i, false); - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); cout << "Key " << i << ":" << endl; cout << " UUID: " << toUUID(u) << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else if (h128 u = fromUUID(i)) { - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); cout << "Key " << i << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else cerr << "Couldn't inspect " << i << "; not found." << endl; @@ -454,12 +454,12 @@ public: { string const& i = m_inputs[0]; h128 u; - bytes b; - b = fromHex(i); + bytesSec b; + b.writable() = fromHex(i); if (b.size() != 32) { std::string s = contentsString(i); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = wallet.store().importKey(i); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 0d632a550..b7eca90f6 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -80,11 +80,34 @@ using bytesRef = vector_ref; using bytesConstRef = vector_ref; template -class secure_vector: public std::vector +class secure_vector { public: - template secure_vector(Args&& ... _args): std::vector(_args ...) {} - ~secure_vector() { vector_ref(this).cleanse(); } + secure_vector() {} + secure_vector(secure_vector const& _c) = default; + explicit secure_vector(unsigned _size): m_data(_size) {} + explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {} + explicit secure_vector(std::vector const& _c): m_data(_c) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + ~secure_vector() { ref().cleanse(); } + + secure_vector& operator=(secure_vector const& _c) { ref().cleanse(); m_data = _c.m_data; return *this; } + std::vector& writable() { clear(); return m_data; } + std::vector const& makeInsecure() const { return m_data; } + + void clear() { ref().cleanse(); } + + vector_ref ref() { return vector_ref(&m_data); } + vector_ref ref() const { return vector_ref(&m_data); } + + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } + + void swap(secure_vector& io_other) { m_data.swap(io_other.m_data); } + +private: + std::vector m_data; }; using bytesSec = secure_vector; diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h index ade089e16..58938d2b2 100644 --- a/libdevcore/CommonJS.h +++ b/libdevcore/CommonJS.h @@ -51,10 +51,17 @@ inline std::string toJS(bytes const& _n, std::size_t _padding = 0) return "0x" + toHex(n); } -template< typename T >std::string toJS( T const& i ) +template std::string toJS(SecureFixedHash const& _i) { std::stringstream stream; - stream << "0x" << std::hex << i; + stream << "0x" << _i.makeInsecure().hex(); + return stream.str(); +} + +template std::string toJS(T const& _i) +{ + std::stringstream stream; + stream << "0x" << std::hex << _i; return stream.str(); } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 98d457da3..0de2cc825 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -220,6 +220,77 @@ private: std::array m_data; ///< The binary data. }; +template +class SecureFixedHash: private FixedHash +{ +public: + using ConstructFromHashType = typename FixedHash::ConstructFromHashType; + using ConstructFromStringType = typename FixedHash::ConstructFromStringType; + using ConstructFromPointerType = typename FixedHash::ConstructFromPointerType; + SecureFixedHash() = default; + explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b.ref(), _t) {} + template explicit SecureFixedHash(FixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h, _t) {} + template explicit SecureFixedHash(SecureFixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h.makeInsecure(), _t) {} + explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash::FromHex, ConstructFromHashType _ht = FixedHash::FailIfDifferent): FixedHash(_s, _t, _ht) {} + explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash(_d, _t) {} + ~SecureFixedHash() { ref().cleanse(); } + + SecureFixedHash& operator=(SecureFixedHash const& _c) { ref().cleanse(); FixedHash::operator=(static_cast const&>(_c)); return *this; } + + using FixedHash::size; + + bytesSec asBytesSec() const { return bytesSec(ref()); } + + FixedHash const& makeInsecure() const { return static_cast const&>(*this); } + FixedHash& writable() { clear(); return static_cast&>(*this); } + + using FixedHash::operator bool; + + // The obvious comparison operators. + bool operator==(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator==(static_cast const&>(_c)); } + bool operator!=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator!=(static_cast const&>(_c)); } + bool operator<(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<(static_cast const&>(_c)); } + bool operator>=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>=(static_cast const&>(_c)); } + bool operator<=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<=(static_cast const&>(_c)); } + bool operator>(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>(static_cast const&>(_c)); } + + using FixedHash::operator==; + using FixedHash::operator!=; + using FixedHash::operator<; + using FixedHash::operator>=; + using FixedHash::operator<=; + using FixedHash::operator>; + + // The obvious binary operators. + SecureFixedHash& operator^=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator^(FixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator|(FixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator&(FixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + + SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + SecureFixedHash operator~() const { ~static_cast&>(*this); return *this; } + + using FixedHash::abridged; + using FixedHash::abridgedMiddle; + + bytesConstRef ref() const { return FixedHash::ref(); } + byte const* data() const { return FixedHash::data(); } + + static SecureFixedHash random() { SecureFixedHash ret; ret.FixedHash::ref().randomize(); return ret; } + using FixedHash::firstBitSet; + + void clear() { ref().cleanse(); } +}; + /// Fast equality operator for h256. template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const { @@ -246,6 +317,14 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) return _out; } +/// Stream I/O for the SecureFixedHash class. +template +inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash const& _h) +{ + _out << "SecureFixedHash#" << std::hex << typename FixedHash::hash()(_h.makeInsecure()) << std::dec; + return _out; +} + // Common types of FixedHash. using h2048 = FixedHash<256>; using h1024 = FixedHash<128>; diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp index 880f23d6e..ea1f0de22 100644 --- a/libdevcore/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -211,13 +211,14 @@ defsha3(512) } -h256 sha3(bytesConstRef _input) +bool sha3(bytesConstRef _input, bytesRef o_output) { // FIXME: What with unaligned memory? - h256 ret; - keccak::sha3_256(ret.data(), 32, _input.data(), _input.size()); + if (o_output.size() != 32) + return false; + keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); - return ret; + return true; } } diff --git a/libdevcore/SHA3.h b/libdevcore/SHA3.h index c3ef524fe..7be2367e9 100644 --- a/libdevcore/SHA3.h +++ b/libdevcore/SHA3.h @@ -32,20 +32,31 @@ namespace dev // SHA-3 convenience routines. -/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -h256 sha3(bytesConstRef _input); - /// Calculate SHA3-256 hash of the given input and load it into the given output. -inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); } +/// @returns false if o_output.size() != 32. +bool sha3(bytesConstRef _input, bytesRef o_output); + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } +inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().ref()); return ret; } /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } +inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(bytesConstRef(&_input)); } /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(bytesConstRef(_input)); } /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(FixedHash const& _input) { return sha3Secure(_input.ref()); } + +/// Fully secure variants are equivalent for sha3 and sha3Secure. +inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); } +inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 6f2bff5bd..1932a8fda 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -5,11 +5,13 @@ #include #include #include +#include namespace dev { static unsigned char s_cleanseCounter = 0; +static std::random_device s_vectorRefEngine; /** * A modifiable reference to an existing object or vector in memory. @@ -67,6 +69,16 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Populate with random data. + template + void randomize(Engine& _eng) + { + uint8_t* e = (uint8_t*)end(); + for (uint8_t* i = (uint8_t*)begin(); i != e; ++i) + *i = (uint8_t)std::uniform_int_distribution(0, 255)(_eng); + } + /// @returns a random valued object. + void randomize() { randomize(s_vectorRefEngine); } /// Securely overwrite the memory. /// @note adapted from OpenSSL's implementation. void cleanse() diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h index 60c6afdf6..6f72369f6 100644 --- a/libdevcrypto/AES.h +++ b/libdevcrypto/AES.h @@ -31,4 +31,4 @@ namespace dev bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); -} \ No newline at end of file +} diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b64535f51..4e663676b 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -147,7 +147,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) return decrypt(_k, _cipher, o_plain); } -std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) +std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) { h128 iv(Nonce::get()); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); @@ -173,23 +173,23 @@ bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _pl } } -bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) +bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) { if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) - return bytes(); + return bytesSec(); SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); - bytes ret(_cipher.size()); - d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); + bytesSec ret(_cipher.size()); + d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - return bytes(); + return bytesSec(); } } @@ -237,12 +237,12 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) #endif } -bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) +bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (PKCS5_PBKDF2_HMAC().DeriveKey( - ret.data(), - ret.size(), + ret.writable().data(), + _dkLen, 0, reinterpret_cast(_pass.data()), _pass.size(), @@ -254,9 +254,9 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, return ret; } -bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (libscrypt_scrypt( reinterpret_cast(_pass.data()), _pass.size(), @@ -265,8 +265,8 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin _n, _r, _p, - ret.data(), - ret.size() + ret.writable().data(), + _dkLen ) != 0) BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); return ret; @@ -283,7 +283,7 @@ KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) { - KeyPair ret(FixedHash<32>::random()); + KeyPair ret(Secret::random()); if (ret.address()) return ret; } @@ -292,7 +292,7 @@ KeyPair KeyPair::create() KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { - return KeyPair(sha3(aesDecrypt(_seed, _password))); + return KeyPair(Secret(sha3(aesDecrypt(_seed, _password)))); } h256 crypto::kdf(Secret const& _priv, h256 const& _hash) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 44d1c8155..c90481cb4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -32,15 +32,7 @@ namespace dev { -/// A secret key: 32 bytes. -/// @NOTE This is not endian-specific; it's just a bunch of bytes. -class Secret: public h256 -{ -public: - template Secret(Args&& ... _args): h256(_args ...) {} - Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} - ~Secret() { ref().cleanse(); } -}; +using Secret = SecureFixedHash<32>; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -82,7 +74,7 @@ using Addresses = h160s; using AddressHash = std::unordered_set; /// A vector of secrets. -using Secrets = h256s; +using Secrets = std::vector; /// Convert a secret key into the public key equivalent. Public toPublic(Secret const& _secret); @@ -116,21 +108,21 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypts payload with random IV/ctr using AES128-CTR. -std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); +std::pair encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); /// Decrypts payload with specified IV/ctr using AES128-CTR. -bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); +bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); /// Encrypts payload with specified IV/ctr using AES128-CTR. -inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } -inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } /// Decrypts payload with specified IV/ctr using AES128-CTR. -inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } -inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); @@ -142,10 +134,10 @@ Signature sign(Secret const& _k, h256 const& _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash); /// Derive key via PBKDF2. -bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); +bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); /// Derive key via Scrypt. -bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); +bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. @@ -176,8 +168,8 @@ public: /// Retrieve the associated address of the public key. Address const& address() const { return m_address; } - bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; } - bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } + bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } + bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } private: void populateFromSecret(Secret const& _k); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 693952d5f..6366f0da1 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -67,7 +67,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) { // interop w/go ecies implementation auto r = KeyPair::create(); - h256 z; + Secret z; ecdh::agree(r.sec(), _k, z); auto key = eciesKDF(z, bytes(), 32); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); @@ -77,7 +77,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) bytes mKey(32); ctx.Final(mKey.data()); - bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); + bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; @@ -110,8 +110,8 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) // invalid message: length return false; - h256 z; - ecdh::agree(_k, *(Public*)(io_text.data()+1), z); + Secret z; + ecdh::agree(_k, *(Public*)(io_text.data() + 1), z); auto key = eciesKDF(z, bytes(), 64); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); @@ -137,7 +137,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) if (mac[i] != msgMac[i]) return false; - plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); + plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); io_text.resize(plain.size()); io_text.swap(plain); @@ -222,7 +222,7 @@ Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash) Integer kInv = k.InverseMod(m_q); Integer z(_hash.asBytes().data(), 32); - Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; + Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q; if (r == 0 || s == 0) BOOST_THROW_EXCEPTION(InvalidState()); @@ -310,7 +310,7 @@ bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p) return true; } -void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) +void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s) { // TODO: mutex ASN1::secp256k1() singleton // Creating Domain is non-const for m_oid and m_oid is not thread-safe @@ -318,7 +318,7 @@ void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; memcpy(&remote[1], _r.data(), 64); - d.Agree(o_s.data(), _s.data(), remote); + d.Agree(o_s.writable().data(), _s.data(), remote); } void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& o_p) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index fca094242..564d1c5c0 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -107,10 +107,10 @@ public: /// Verifies _s is a valid secret key and returns corresponding public key in o_p. bool verifySecret(Secret const& _s, Public& o_p); - void agree(Secret const& _s, Public const& _r, h256& o_s); + void agree(Secret const& _s, Public const& _r, Secret& o_s); protected: - void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); } + void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); } void exportPublicKey(DL_PublicKey_EC const& _k, Public& o_p); diff --git a/libdevcrypto/ECDHE.cpp b/libdevcrypto/ECDHE.cpp index 3005d38c1..90b3381f8 100644 --- a/libdevcrypto/ECDHE.cpp +++ b/libdevcrypto/ECDHE.cpp @@ -29,7 +29,7 @@ using namespace dev::crypto; static Secp256k1PP s_secp256k1; -void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s) +void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) { s_secp256k1.agree(_s, _r, o_s); } diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index 1a2442727..3658caf3d 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -50,7 +50,7 @@ private: namespace ecdh { -void agree(Secret const& _s, Public const& _r, h256& o_s); +void agree(Secret const& _s, Public const& _r, Secret& o_s); } /** diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index b823ba02f..266f3735a 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -100,17 +100,17 @@ bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bytesSec key; if (it != m_keys.end()) { - key = decrypt(it->second.encryptedKey, _pass()); + key = bytesSec(decrypt(it->second.encryptedKey, _pass())); if (!key.empty()) m_cached[_uuid] = key; } return key; } -h128 SecretStore::importSecret(bytes const& _s, string const& _pass) +h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass) { h128 r; - EncryptedKey key{encrypt(_s, _pass), string()}; + EncryptedKey key{encrypt(_s.ref(), _pass), string()}; r = h128::random(); m_cached[r] = _s; m_keys[r] = move(key); @@ -118,6 +118,17 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass) return r; } +h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass) +{ + h128 r; + EncryptedKey key{encrypt(_s, _pass), string()}; + r = h128::random(); + m_cached[r] = bytesSec(_s); + m_keys[r] = move(key); + save(); + return r; +} + void SecretStore::kill(h128 const& _uuid) { m_cached.erase(_uuid); @@ -188,16 +199,16 @@ h128 SecretStore::readKeyContent(string const& _content, string const& _file) bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function const& _pass, KDF _kdf) { - bytes s = secret(_uuid, _pass, true); + bytesSec s = secret(_uuid, _pass, true); if (s.empty()) return false; m_cached.erase(_uuid); - m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf); + m_keys[_uuid].encryptedKey = encrypt(s.ref(), _newPass, _kdf); save(); return true; } -static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) +static bytesSec deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) { unsigned dklen = 32; unsigned iterations = 1 << 18; @@ -233,16 +244,16 @@ static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) } } -string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) +string SecretStore::encrypt(bytesConstRef _v, string const& _pass, KDF _kdf) { js::mObject ret; - bytes derivedKey = deriveNewKey(_pass, _kdf, ret); + bytesSec derivedKey = deriveNewKey(_pass, _kdf, ret); if (derivedKey.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed.")); ret["cipher"] = "aes-128-ctr"; - h128 key(derivedKey, h128::AlignLeft); + SecureFixedHash<16> key(derivedKey, h128::AlignLeft); h128 iv = h128::random(); { js::mObject params; @@ -251,19 +262,19 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) } // cipher text - bytes cipherText = encryptSymNoAuth(key, iv, &_v); + bytes cipherText = encryptSymNoAuth(key, iv, _v); if (cipherText.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed.")); ret["ciphertext"] = toHex(cipherText); // and mac. - h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); + h256 mac = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); ret["mac"] = toHex(mac.ref()); return js::write_string(js::mValue(ret), true); } -bytes SecretStore::decrypt(string const& _v, string const& _pass) +bytesSec SecretStore::decrypt(string const& _v, string const& _pass) { js::mObject o; { @@ -273,14 +284,14 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) } // derive key - bytes derivedKey; + bytesSec derivedKey; if (o["kdf"].get_str() == "pbkdf2") { auto params = o["kdfparams"].get_obj(); if (params["prf"].get_str() != "hmac-sha256") { cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } unsigned iterations = params["c"].get_int(); bytes salt = fromHex(params["salt"].get_str()); @@ -294,13 +305,13 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) else { cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2")) { cwarn << "Derived key's length too short (<32 bytes)"; - return bytes(); + return bytesSec(); } bytes cipherText = fromHex(o["ciphertext"].get_str()); @@ -311,23 +322,23 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h256 mac(o["mac"].get_str()); h256 macExp; if (o.count("compat") && o["compat"].get_str() == "2") - macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); else - macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else if (o.count("sillymac")) { h256 mac(o["sillymac"].get_str()); - h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else @@ -340,15 +351,15 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h128 iv(params["iv"].get_str()); if (o.count("compat") && o["compat"].get_str() == "2") { - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + SecureFixedHash<16> key(sha3Secure(derivedKey.ref().cropped(derivedKey.size() - 16)), h128::AlignRight); return decryptSymNoAuth(key, iv, &cipherText); } else - return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText); + return decryptSymNoAuth(SecureFixedHash<16>(derivedKey, h128::AlignLeft), iv, &cipherText); } else { cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } } diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index ea08a48b2..fbc4c0bec 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -60,7 +60,8 @@ public: h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } /// Imports the decrypted key given by @a _s and stores it, encrypted with /// (a key derived from) the password @a _pass. - h128 importSecret(bytes const& _s, std::string const& _pass); + h128 importSecret(bytesSec const& _s, std::string const& _pass); + h128 importSecret(bytesConstRef _s, std::string const& _pass); /// Decrypts and re-encrypts the key identified by @a _uuid. bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); /// Removes the key specified by @a _uuid from both memory and disk. @@ -102,9 +103,9 @@ private: void load(std::string const& _keysPath); void load() { load(m_path); } /// Encrypts @a _v with a key derived from @a _pass or the empty string on error. - static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); + static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. - static bytes decrypt(std::string const& _v, std::string const& _pass); + static bytesSec decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. mutable std::unordered_map m_cached; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7ef3dd21e..ca58f65e3 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -101,7 +101,7 @@ private: if (_name == "authorities") BasicAuthority::s_authorities = rlp.toUnorderedSet
(); else if (_name == "authority") - m_secret = rlp.toHash(); + m_secret = Secret(rlp.toHash()); else return false; return true; diff --git a/libethcore/CommonJS.h b/libethcore/CommonJS.h index 0ff21afdf..fdd18d6e5 100644 --- a/libethcore/CommonJS.h +++ b/libethcore/CommonJS.h @@ -40,7 +40,7 @@ Address toAddress(std::string const& _a); inline Public jsToPublic(std::string const& _s) { return jsToFixed(_s); } /// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length. -inline Secret jsToSecret(std::string const& _s) { return jsToFixed(_s); } +inline Secret jsToSecret(std::string const& _s) { h256 d = jsToFixed(_s); Secret ret(d); d.ref().cleanse(); return ret; } /// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length. inline Address jsToAddress(std::string const& _s) { return jsToFixed(_s); } diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 26cf451d0..6d4dab1ce 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -81,9 +81,9 @@ bool KeyManager::load(string const& _pass) { bytes salt = contents(m_keysFile + ".salt"); bytes encKeys = contents(m_keysFile); - m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16)); - bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); - RLP s(bs); + m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); + bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); + RLP s(bs.ref()); unsigned version = unsigned(s[0]); if (version == 1) { @@ -178,7 +178,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con auto passHash = hashPassword(_pass); cachePassword(_pass); m_passwordHint[passHash] = _passwordHint; - auto uuid = m_store.importSecret(_s.asBytes(), _pass); + auto uuid = m_store.importSecret(_s.asBytesSec(), _pass); m_keyInfo[uuid] = KeyInfo{passHash, _accountName}; m_addrLookup[addr] = uuid; write(m_keysFile); @@ -187,7 +187,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint) { - bytes key = m_store.secret(_uuid, [&](){ return _pass; }); + bytesSec key = m_store.secret(_uuid, [&](){ return _pass; }); if (key.empty()) return; Address a = KeyPair(Secret(key)).address(); @@ -258,7 +258,7 @@ string const& KeyManager::passwordHint(Address const& _address) const h256 KeyManager::hashPassword(string const& _pass) const { // TODO SECURITY: store this a bit more securely; Scrypt perhaps? - return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32)); + return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure()); } void KeyManager::cachePassword(string const& _password) const @@ -278,14 +278,14 @@ void KeyManager::write(string const& _pass, string const& _keysFile) const { bytes salt = h256::random().asBytes(); writeFile(_keysFile + ".salt", salt); - auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); cachePassword(_pass); m_master = hashPassword(_pass); write(key, _keysFile); } -void KeyManager::write(h128 const& _key, string const& _keysFile) const +void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const { RLPStream s(4); s << 1; // version diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index a2b5a4e07..0fefc17ee 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -136,8 +136,8 @@ private: // @returns false if wasn't previously loaded ok. bool write() const { return write(m_keysFile); } bool write(std::string const& _keysFile) const; - void write(std::string const& _pass, std::string const& _keysFile) const; - void write(h128 const& _key, std::string const& _keysFile) const; + void write(std::string const& _pass, std::string const& _keysFile) const; // TODO: all passwords should be a secure string. + void write(SecureFixedHash<16> const& _key, std::string const& _keysFile) const; // Ethereum keys. @@ -159,7 +159,7 @@ private: std::string m_defaultPasswordDeprecated; mutable std::string m_keysFile; - mutable h128 m_keysFileKey; + mutable SecureFixedHash<16> m_keysFileKey; mutable h256 m_master; SecretStore m_store; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 46e0efe95..dd9ff53cf 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -809,7 +809,7 @@ bytes Host::saveNetwork() const // else: TODO: use previous configuration if available RLPStream ret(3); - ret << dev::p2p::c_protocolVersion << m_alias.secret(); + ret << dev::p2p::c_protocolVersion << m_alias.secret().ref(); ret.appendList(count); if (!!count) ret.appendRaw(network.out(), count); diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index e0ebd6c2d..4fee9b42b 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -40,7 +40,7 @@ void RLPXHandshake::writeAuth() // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) Secret staticShared; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared); - sign(m_ecdhe.seckey(), staticShared ^ m_nonce).ref().copyTo(sig); + sign(m_ecdhe.seckey(), staticShared.makeInsecure() ^ m_nonce).ref().copyTo(sig); sha3(m_ecdhe.pubkey().ref(), hepubk); m_host->m_alias.pub().ref().copyTo(pubk); m_nonce.ref().copyTo(nonce); @@ -92,7 +92,7 @@ void RLPXHandshake::readAuth() Secret sharedSecret; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret); - m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); + m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret.makeInsecure() ^ m_remoteNonce); if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index bf18835b6..3216cc90b 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -60,7 +60,7 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes for (unsigned i = 0; i < _e.topic().size(); ++i) if (_e.topic()[i] == knownTopic[ti]) { - topicSecret = _fk[ti]; + topicSecret = Secret(_fk[ti]); topicIndex = i; break; } @@ -69,9 +69,9 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes return false; unsigned index = topicIndex * 2; - h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); + Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size)); - h256 key = generateGamma(topicSecret, salt) ^ encryptedKey; + Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure()); bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size()); return decryptSym(key, cipherText, o_b); } @@ -122,10 +122,10 @@ Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned // this message is for broadcast (could be read by anyone who knows at least one of the topics) // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic Secret s = Secret::random(); - for (h256 const& t : _fullTopics) + for (h256 const& t: _fullTopics) { h256 salt = h256::random(); - ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); + ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes(); ret.m_data += salt.asBytes(); } diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 1ec28ae01..c29194e97 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -127,7 +127,7 @@ public: private: bool populate(bytes const& _data); bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); - h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } + Secret generateGamma(Secret const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Public m_from; Public m_to; diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 0a583f2a0..1c9faa896 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -187,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) bytes dapp = rlpStr.out(); dev::h256 dappHash = dev::sha3(dapp); //encrypt - KeyPair key(dappHash); + KeyPair key((Secret(dappHash))); Secp256k1PP enc; enc.encrypt(key.pub(), dapp); diff --git a/test/libdevcrypto/AES.cpp b/test/libdevcrypto/AES.cpp index a8aeb4cd1..0617033aa 100644 --- a/test/libdevcrypto/AES.cpp +++ b/test/libdevcrypto/AES.cpp @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(AesDecrypt) { cout << "AesDecrypt" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address()); } @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed) { cout << "AesDecryptWrongSeed" << endl; bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword) { cout << "AesDecryptWrongPassword" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "badtest"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "badtest"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 30bff49d9..bff6e0720 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -61,9 +61,9 @@ BOOST_AUTO_TEST_CASE(basic_tests) SecretStore store(tmpDir.path()); h128 u = store.readKeyContent(js::write_string(o["json"], false)); cdebug << "read uuid" << u; - bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); - cdebug << "got secret" << toHex(s); - BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str()); + bytesSec s = store.secret(u, [&](){ return o["password"].get_str(); }); + cdebug << "got secret" << toHex(s.makeInsecure()); + BOOST_REQUIRE_EQUAL(toHex(s.makeInsecure()), o["priv"].get_str()); } } @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) uuid = store.importKey(importFile); BOOST_CHECK(!!uuid); BOOST_CHECK(contentsString(importFile) == keyData); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } fs::remove(importFile); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } @@ -121,15 +121,15 @@ BOOST_AUTO_TEST_CASE(import_secret) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } } @@ -145,12 +145,12 @@ BOOST_AUTO_TEST_CASE(wrong_password) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); // password will not be queried - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }).makeInsecure())); } { SecretStore store(storeDir.path()); @@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE(recode) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { @@ -182,16 +182,16 @@ BOOST_AUTO_TEST_CASE(recode) BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; })); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); store.clearCache(); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } } diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index c94cc4e8f..a788319a8 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_patch) BOOST_AUTO_TEST_CASE(verify_secert) { - h256 empty; + Secret empty; KeyPair kNot(empty); BOOST_REQUIRE(!kNot.address()); KeyPair k(sha3(empty)); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) bytes e(fromHex("0x01")); e.resize(32); int tests = 2; - while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + while (sha3(&e, &e), secret = sha3(secret), tests--) { KeyPair key(secret); Public pkey = key.pub(); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) Integer r = s_params.ConvertElementToInteger(rp); Integer kInv = kInt.InverseMod(q); - Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; + Integer s = (kInv * (Integer(secret.data(), 32) * r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); Signature sig; @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(ecies_kdf) BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes()); BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes()); - BOOST_REQUIRE((u256)h256(z1) > 0); + BOOST_REQUIRE(!!z1); BOOST_REQUIRE(z1 == z2); BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0); @@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(ecdh) ECDH::Domain dhA(s_curveOID); Secret shared; - BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); + BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.sec().data(), pubb)); BOOST_REQUIRE(shared); } @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA); - sign(eA.seckey(), ssA ^ nonceA).ref().copyTo(sig); + sign(eA.seckey(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig); sha3(eA.pubkey().ref(), hepubk); nodeA.pub().ref().copyTo(pubk); nonceA.ref().copyTo(nonce); @@ -520,21 +520,21 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - aEncryptK = sha3(keyMaterial); + aEncryptK = sha3Secure(keyMaterial); aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - aMacK = sha3(keyMaterial); + aMacK = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceBAck).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - aEgressMac = sha3(keyMaterial); + aEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceA).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - aIngressMac = sha3(keyMaterial); + aIngressMac = sha3Secure(keyMaterial); } @@ -573,7 +573,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) Secret ss; s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss); - eAAuth = recover(sigAuth, ss ^ nonceAAuth); + eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure()); // todo: test when this fails; means remote is bad or packet bits were flipped BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth)); BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey()); @@ -588,22 +588,22 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - bEncryptK = sha3(keyMaterial); + bEncryptK = sha3Secure(keyMaterial); bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - bMacK = sha3(keyMaterial); + bMacK = sha3Secure(keyMaterial); // todo: replace nonceB with decrypted nonceB keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - bEgressMac = sha3(keyMaterial); + bEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceB).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - bIngressMac = sha3(keyMaterial); + bIngressMac = sha3Secure(keyMaterial); } BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK); @@ -617,7 +617,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) { - h128 encryptK(sha3("..."), h128::AlignLeft); + SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft); h256 egressMac(sha3("+++")); // TESTING: send encrypt magic sequence bytes magic {0x22,0x40,0x08,0x91}; @@ -629,16 +629,17 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); - bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); + bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure(); plaintext.resize(magic.size()); + // @alex @subtly TODO: FIX: this check is pointless with the above line. BOOST_REQUIRE(plaintext.size() > 0); BOOST_REQUIRE(magic == plaintext); } BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) { - h128 k(sha3("0xAAAA"), h128::AlignLeft); + SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft); string m = "AAAAAAAAAAAAAAAA"; bytesConstRef msg((byte*)m.data(), m.size()); @@ -646,7 +647,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) h128 iv; tie(ciphertext, iv) = encryptSymNoAuth(k, msg); - bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); + bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure(); BOOST_REQUIRE_EQUAL(asString(plaintext), m); } diff --git a/test/libethcore/commonjs.cpp b/test/libethcore/commonjs.cpp index 72582c540..ca472a6f4 100644 --- a/test/libethcore/commonjs.cpp +++ b/test/libethcore/commonjs.cpp @@ -32,8 +32,8 @@ BOOST_AUTO_TEST_CASE(jsToPublic) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.pub()); - Public pub = dev::jsToPublic(string); + string s = toJS(kp.pub()); + Public pub = dev::jsToPublic(s); BOOST_CHECK_EQUAL(kp.pub(), pub); } @@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(jsToAddress) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.address()); - Address address = dev::jsToAddress(string); + string s = toJS(kp.address()); + Address address = dev::jsToAddress(s); BOOST_CHECK_EQUAL(kp.address(), address); } @@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE(jsToSecret) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.secret()); - Secret secret = dev::jsToSecret(string); - BOOST_CHECK_EQUAL(kp.secret(), secret); + string s = toJS(kp.secret().makeInsecure()); + Secret secret = dev::jsToSecret(s); + BOOST_CHECK_EQUAL(kp.secret().makeInsecure(), secret.makeInsecure()); } BOOST_AUTO_TEST_SUITE_END() From 17098549f8a0db2e3cae9c3558f7210cec4bbb81 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 28/53] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. --- alethzero/MainWin.cpp | 4 ++-- ethminer/CMakeLists.txt | 1 + libdevcore/Common.h | 10 ++++++++++ libdevcore/FixedHash.h | 2 ++ libdevcore/vector_ref.h | 20 ++++++++++++++++++++ libdevcrypto/Common.cpp | 14 +++++++------- libdevcrypto/Common.h | 12 ++++++++++-- libdevcrypto/CryptoPP.cpp | 2 +- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 4 ++-- libethcore/CMakeLists.txt | 4 +--- libethereum/BlockChain.cpp | 7 ++----- libethereum/BlockChain.h | 13 +++++++++++-- libethereum/CanonBlockChain.cpp | 1 + libethereum/CanonBlockChain.h | 5 ++++- libethereumx/Ethereum.cpp | 4 ++-- libethereumx/Ethereum.h | 4 ++-- libweb3jsonrpc/JsonHelper.cpp | 2 +- libweb3jsonrpc/JsonHelper.h | 2 +- libwhisper/CMakeLists.txt | 4 ++-- libwhisper/Interface.h | 4 ++-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 4 ++-- mix/ClientModel.h | 2 +- test/libdevcrypto/crypto.cpp | 4 ++-- test/libethereum/stateOriginal.cpp | 4 ++-- 28 files changed, 96 insertions(+), 47 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 406d639cc..1bebbfe93 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -360,8 +360,8 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret _id = jsToSecret(_ids.toStdString()); - KeyPair kp(_id); + Secret const& id = jsToSecret(_ids.toStdString()); + KeyPair kp(id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 8b79afd72..cda6aa8b8 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -30,6 +30,7 @@ endif() target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} devcrypto) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 612b7c685..0d632a550 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -79,6 +79,16 @@ using bytes = std::vector; using bytesRef = vector_ref; using bytesConstRef = vector_ref; +template +class secure_vector: public std::vector +{ +public: + template secure_vector(Args&& ... _args): std::vector(_args ...) {} + ~secure_vector() { vector_ref(this).cleanse(); } +}; + +using bytesSec = secure_vector; + // Numeric types. using bigint = boost::multiprecision::number>; using u64 = boost::multiprecision::number>; diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 3127b349a..98d457da3 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -214,6 +214,8 @@ public: return ret; } + void clear() { m_data.fill(0); } + private: std::array m_data; ///< The binary data. }; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b05342f71..6f2bff5bd 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,8 @@ namespace dev { +static unsigned char s_cleanseCounter = 0; + /** * A modifiable reference to an existing object or vector in memory. */ @@ -65,6 +67,24 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + uint8_t* p = (uint8_t*)begin(); + size_t len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b94c8712f..b13f25453 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -274,6 +274,13 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin return ret; } +void KeyPair::populateFromSecret(Secret const& _sec) +{ + m_secret = _sec; + if (s_secp256k1pp.verifySecret(m_secret, m_public)) + m_address = toAddress(m_public); +} + KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) @@ -285,13 +292,6 @@ KeyPair KeyPair::create() return KeyPair(); } -KeyPair::KeyPair(h256 _sec): - m_secret(_sec) -{ - if (s_secp256k1pp.verifySecret(m_secret, m_public)) - m_address = toAddress(m_public); -} - KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { return KeyPair(sha3(aesDecrypt(_seed, _password))); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9aeb85a4c..44d1c8155 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -34,7 +34,13 @@ namespace dev /// A secret key: 32 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. -using Secret = h256; +class Secret: public h256 +{ +public: + template Secret(Args&& ... _args): h256(_args ...) {} + Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} + ~Secret() { ref().cleanse(); } +}; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -151,7 +157,7 @@ public: KeyPair() {} /// Normal constructor - populates object from the given secret key. - KeyPair(Secret _k); + KeyPair(Secret const& _k) { populateFromSecret(_k); } /// Create a new, randomly generated object. static KeyPair create(); @@ -174,6 +180,8 @@ public: bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } private: + void populateFromSecret(Secret const& _k); + Secret m_secret; Public m_public; Address m_address; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 8beb8e495..693952d5f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -33,7 +33,7 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1PP::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) +bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen) { auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8); // SEC/ISO/Shoup specify counter size SHOULD be equivalent diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 6a0453330..fca094242 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -87,7 +87,7 @@ public: bool decryptECIES(Secret const& _k, bytes& io_text); /// Key derivation function used by encryptECIES and decryptECIES. - bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256); + bytes eciesKDF(Secret const& _z, bytes _s1, unsigned kdBitLen = 256); /// @returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index 0fd5a8d3f..1a2442727 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -39,7 +39,7 @@ using AliasSession = std::pair; class Alias { public: - Alias(Secret _s): m_secret(_s) {}; + Alias(Secret const& _s): m_secret(_s) {}; AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 55c944e8e..b823ba02f 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -91,13 +91,13 @@ SecretStore::SecretStore(string const& _path): m_path(_path) load(); } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const +bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - bytes key; + bytesSec key; if (it != m_keys.end()) { key = decrypt(it->second.encryptedKey, _pass()); diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 029630b4e..ea08a48b2 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -52,7 +52,7 @@ public: /// @returns the secret key stored by the given @a _uuid. /// @param _pass function that returns the password for the key. /// @param _useCache if true, allow previously decrypted keys to be returned directly. - bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + bytesSec secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in @@ -107,7 +107,7 @@ private: static bytes decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. - mutable std::unordered_map m_cached; + mutable std::unordered_map m_cached; /// Stores encrypted keys together with the file they were loaded from by uuid. std::unordered_map m_keys; diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 73ea75c8c..d740da2a2 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -23,13 +23,11 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) - if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) endif () - +target_link_libraries(${EXECUTABLE} devcrypto) if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 98655a585..b397bf3a9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -152,7 +152,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -165,9 +165,6 @@ void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); /// Open the database. - unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust); + unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); + /// Open the database, rebuilding if necessary. + void openDatabase(std::string const& _path, WithExisting _we, ProgressCallback const& _pc) + { + if (openDatabase(_path, _we) != c_minorProtocolVersion || _we == WithExisting::Verify) + rebuild(_path, _pc); + } + template T queryExtras(K const& _h, std::unordered_map& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const { { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 2a7408437..b921d67e4 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -47,6 +47,7 @@ bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) { + BlockChain::openDatabase(_path, _we, _pc); } void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d09108b38..0ff9c6521 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -52,7 +52,10 @@ class CanonBlockChain: public FullBlockChain public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): - FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) + { + BlockChain::openDatabase(_path, _we, _pc); + } ~CanonBlockChain() {} /// @returns the genesis block as its RLP-encoded byte array. diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 8ab4243a1..675614c1a 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes con return bytes(); } -Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 0e81b8e0c..1e24b396c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret const& _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index c074525b9..9ccad947d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -482,7 +482,7 @@ shh::Message toMessage(Json::Value const& _json) return ret; } -shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret const& _from) { unsigned ttl = 50; unsigned workToProve = 50; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 11219fc55..9be59bcab 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -89,7 +89,7 @@ namespace shh Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); Message toMessage(Json::Value const& _json); -Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret const& _from); std::pair toWatch(Json::Value const& _json); } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 5af43d0b2..05bf2ae20 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -21,10 +21,10 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} p2p) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index f53cb17a7..21a1355f8 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -76,8 +76,8 @@ public: void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret const& _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index dd72ff734..bf18835b6 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { AbridgedTopics topics = abridge(_fullTopics); Envelope ret(time(0) + _ttl, _ttl, topics); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 4d8b34548..1ec28ae01 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -118,11 +118,11 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret const& _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } + Envelope sealTo(Secret const& _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bf88ad66a..cff767dad 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -55,7 +55,7 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret const& _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 2db6e5faa..49c8471fd 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eA.agree(eBAck, ess); ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); @@ -581,7 +581,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytes keyMaterialBytes(512); bytesRef keyMaterial(&keyMaterialBytes); - h256 ess; + Secret ess; // todo: ecdh-agree should be able to output bytes eB.agree(eAAuth, ess); // s_secp256k1.agree(eB.seckey(), eAAuth, ess); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 163c89e50..9a806c7c4 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(Complex) cnote << "Testing State..."; - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); + KeyPair me = Secret(sha3("Gav Wood")); + KeyPair myMiner = Secret(sha3("Gav's Miner")); // KeyPair you = sha3("123"); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); From 1cd8fcc025514ec9250f4f739ebe97a8de362c3c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:53:14 +0200 Subject: [PATCH 29/53] Hold address-sorting back. --- alethzero/MainWin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1bebbfe93..16fe4378a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1340,9 +1340,7 @@ void Main::refreshAccounts() bool showContract = ui->showContracts->isChecked(); bool showBasic = ui->showBasic->isChecked(); bool onlyNamed = ui->onlyNamed->isChecked(); - auto as = ethereum()->addresses(); - sort(as.begin(), as.end()); - for (auto const& i: as) + for (auto const& i: ethereum()->addresses()) { bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) From e92392a1e38f0873838a0f1f37a93dda3bf6a963 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 21:31:06 +0200 Subject: [PATCH 30/53] SHA3 gas calc should use bigint to avoid overflow. Fixes #2582. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 9e1c4b866..62b4c871e 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -103,7 +103,7 @@ void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::SHA3: - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + runGas = c_sha3Gas + ((bigint)m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: From 441ce8f0dcd1e9d32b8eecfe213c273bf8ba6ae5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 22:13:49 +0200 Subject: [PATCH 31/53] Fix const& where it should have been value. --- alethzero/MainWin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 16fe4378a..5230eb363 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -360,8 +360,7 @@ void Main::refreshWhisper() void Main::addNewId(QString _ids) { - Secret const& id = jsToSecret(_ids.toStdString()); - KeyPair kp(id); + KeyPair kp(jsToSecret(_ids.toStdString())); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); refreshWhisper(); From 591b4c8c64fc2d7b45b2d58387a4433704ce63fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 32/53] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. --- alethzero/DappLoader.cpp | 5 +- alethzero/MainWin.cpp | 22 ++------- eth/main.cpp | 18 +++---- ethkey/KeyAux.h | 24 +++++----- libdevcore/Common.h | 29 ++++++++++-- libdevcore/CommonJS.h | 11 ++++- libdevcore/FixedHash.h | 79 +++++++++++++++++++++++++++++++ libdevcore/SHA3.cpp | 9 ++-- libdevcore/SHA3.h | 19 ++++++-- libdevcore/vector_ref.h | 12 +++++ libdevcrypto/AES.h | 2 +- libdevcrypto/Common.cpp | 32 ++++++------- libdevcrypto/Common.h | 32 +++++-------- libdevcrypto/CryptoPP.cpp | 16 +++---- libdevcrypto/CryptoPP.h | 4 +- libdevcrypto/ECDHE.cpp | 2 +- libdevcrypto/ECDHE.h | 2 +- libdevcrypto/SecretStore.cpp | 59 +++++++++++++---------- libdevcrypto/SecretStore.h | 7 +-- libethcore/BasicAuthority.cpp | 2 +- libethcore/CommonJS.h | 2 +- libethcore/KeyManager.cpp | 16 +++---- libethcore/KeyManager.h | 6 +-- libp2p/Host.cpp | 2 +- libp2p/RLPxHandshake.cpp | 4 +- libwhisper/Message.cpp | 10 ++-- libwhisper/Message.h | 2 +- mix/FileIo.cpp | 2 +- test/libdevcrypto/AES.cpp | 6 +-- test/libdevcrypto/SecretStore.cpp | 32 ++++++------- test/libdevcrypto/crypto.cpp | 39 +++++++-------- test/libethcore/commonjs.cpp | 14 +++--- 32 files changed, 320 insertions(+), 201 deletions(-) diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index a91531f89..3da3e8c35 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -130,14 +130,14 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) h256 expected = m_uriHashes[requestUrl]; bytes package(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); Secp256k1PP dec; - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); h256 got = sha3(package); if (got != expected) { //try base64 data = QByteArray::fromBase64(data); package = bytes(reinterpret_cast(data.constData()), reinterpret_cast(data.constData() + data.size())); - dec.decrypt(expected, package); + dec.decrypt(Secret(expected), package); got = sha3(package); if (got != expected) throw dev::Exception() << errinfo_comment("Dapp content hash does not match"); @@ -145,6 +145,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) RLP rlp(package); loadDapp(rlp); + bytesRef(&package).cleanse(); // TODO: replace with bytesSec once the crypto API is up to it. } catch (...) { diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 5230eb363..5b1724cb5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -845,29 +845,15 @@ void Main::readSettings(bool _skipGeometry) restoreGeometry(s.value("geometry").toByteArray()); restoreState(s.value("windowState").toByteArray()); - { - QByteArray b = s.value("address").toByteArray(); - if (!b.isEmpty()) - { - h256 k; - for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) - { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!m_keyManager.hasAccount(KeyPair(k).address())) - m_keyManager.import(k, "Imported (UNSAFE) key."); - } - } - } - { m_myIdentities.clear(); QByteArray b = s.value("identities").toByteArray(); if (!b.isEmpty()) { - h256 k; + Secret k; for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + memcpy(k.writable().data(), b.data() + i * sizeof(Secret), sizeof(Secret)); if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) m_myIdentities.append(KeyPair(k)); } @@ -960,7 +946,7 @@ void Main::on_importKey_triggered() bytes b = fromHex(s.toStdString()); if (b.size() == 32) { - auto k = KeyPair(h256(b)); + auto k = KeyPair(Secret(bytesConstRef(&b))); if (!m_keyManager.hasAccount(k.address())) { QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); @@ -1067,7 +1053,7 @@ void Main::on_exportKey_triggered() auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); Secret s = retrieveSecret(h); - QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex())); + QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.makeInsecure().hex())); } } diff --git a/eth/main.cpp b/eth/main.cpp index f85e7096f..585c96699 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -526,7 +526,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice); } @@ -594,7 +594,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce); } @@ -654,7 +654,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP { try { - Secret secret = h256(fromHex(sechex)); + Secret secret(fromHex(sechex)); cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; } catch (BadHexCharacter& _e) @@ -1147,13 +1147,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - if (config[0].size() == 32) // secret key - import and forget. - { - Secret s = config[0].toHash(); - toImport.push_back(s); - } - else // new format - just use it as an address. - signingKey = config[0].toHash
(); + signingKey = config[0].toHash
(); beneficiary = config[1].toHash
(); } @@ -1300,13 +1294,13 @@ int main(int argc, char** argv) else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); signingKey = toAddress(s); } else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc) { Secret s(fromHex(argv[++i])); - toImport.push_back(s); + toImport.emplace_back(s); sessionKey = toAddress(s); } else if ((arg == "--sign-key") && i + 1 < argc) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index af7d8e048..3505d5528 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -192,7 +192,7 @@ public: { KeyPair k(Secret::random()); while (m_icap && k.address()[0]) - k = KeyPair(sha3(k.secret())); + k = KeyPair(Secret(sha3(k.secret().ref()))); return k; } @@ -352,7 +352,7 @@ public: if (m_lock.empty()) m_lock = createPassword("Enter a password with which to secure this account: "); auto k = makeKey(); - h128 u = store.importSecret(k.secret().asBytes(), m_lock); + h128 u = store.importSecret(k.secret().ref(), m_lock); cout << "Created key " << toUUID(u) << endl; cout << " Address: " << k.address().hex() << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl; @@ -362,12 +362,12 @@ public: for (string const& input: m_inputs) { h128 u; - bytes b; - b = fromHex(input); + bytesSec b; + b.writable() = fromHex(input); if (b.size() != 32) { std::string s = contentsString(input); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = store.importKey(input); } @@ -386,18 +386,18 @@ public: if (!contents(i).empty()) { h128 u = store.readKey(i, false); - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); cout << "Key " << i << ":" << endl; cout << " UUID: " << toUUID(u) << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else if (h128 u = fromUUID(i)) { - bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); + bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); cout << "Key " << i << ":" << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << Secret(s).abridged() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; } else cerr << "Couldn't inspect " << i << "; not found." << endl; @@ -454,12 +454,12 @@ public: { string const& i = m_inputs[0]; h128 u; - bytes b; - b = fromHex(i); + bytesSec b; + b.writable() = fromHex(i); if (b.size() != 32) { std::string s = contentsString(i); - b = fromHex(s); + b.writable() = fromHex(s); if (b.size() != 32) u = wallet.store().importKey(i); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 0d632a550..b7eca90f6 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -80,11 +80,34 @@ using bytesRef = vector_ref; using bytesConstRef = vector_ref; template -class secure_vector: public std::vector +class secure_vector { public: - template secure_vector(Args&& ... _args): std::vector(_args ...) {} - ~secure_vector() { vector_ref(this).cleanse(); } + secure_vector() {} + secure_vector(secure_vector const& _c) = default; + explicit secure_vector(unsigned _size): m_data(_size) {} + explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {} + explicit secure_vector(std::vector const& _c): m_data(_c) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + ~secure_vector() { ref().cleanse(); } + + secure_vector& operator=(secure_vector const& _c) { ref().cleanse(); m_data = _c.m_data; return *this; } + std::vector& writable() { clear(); return m_data; } + std::vector const& makeInsecure() const { return m_data; } + + void clear() { ref().cleanse(); } + + vector_ref ref() { return vector_ref(&m_data); } + vector_ref ref() const { return vector_ref(&m_data); } + + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } + + void swap(secure_vector& io_other) { m_data.swap(io_other.m_data); } + +private: + std::vector m_data; }; using bytesSec = secure_vector; diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h index ade089e16..58938d2b2 100644 --- a/libdevcore/CommonJS.h +++ b/libdevcore/CommonJS.h @@ -51,10 +51,17 @@ inline std::string toJS(bytes const& _n, std::size_t _padding = 0) return "0x" + toHex(n); } -template< typename T >std::string toJS( T const& i ) +template std::string toJS(SecureFixedHash const& _i) { std::stringstream stream; - stream << "0x" << std::hex << i; + stream << "0x" << _i.makeInsecure().hex(); + return stream.str(); +} + +template std::string toJS(T const& _i) +{ + std::stringstream stream; + stream << "0x" << std::hex << _i; return stream.str(); } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 98d457da3..0de2cc825 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -220,6 +220,77 @@ private: std::array m_data; ///< The binary data. }; +template +class SecureFixedHash: private FixedHash +{ +public: + using ConstructFromHashType = typename FixedHash::ConstructFromHashType; + using ConstructFromStringType = typename FixedHash::ConstructFromStringType; + using ConstructFromPointerType = typename FixedHash::ConstructFromPointerType; + SecureFixedHash() = default; + explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b.ref(), _t) {} + template explicit SecureFixedHash(FixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h, _t) {} + template explicit SecureFixedHash(SecureFixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h.makeInsecure(), _t) {} + explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash::FromHex, ConstructFromHashType _ht = FixedHash::FailIfDifferent): FixedHash(_s, _t, _ht) {} + explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash(_d, _t) {} + ~SecureFixedHash() { ref().cleanse(); } + + SecureFixedHash& operator=(SecureFixedHash const& _c) { ref().cleanse(); FixedHash::operator=(static_cast const&>(_c)); return *this; } + + using FixedHash::size; + + bytesSec asBytesSec() const { return bytesSec(ref()); } + + FixedHash const& makeInsecure() const { return static_cast const&>(*this); } + FixedHash& writable() { clear(); return static_cast&>(*this); } + + using FixedHash::operator bool; + + // The obvious comparison operators. + bool operator==(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator==(static_cast const&>(_c)); } + bool operator!=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator!=(static_cast const&>(_c)); } + bool operator<(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<(static_cast const&>(_c)); } + bool operator>=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>=(static_cast const&>(_c)); } + bool operator<=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<=(static_cast const&>(_c)); } + bool operator>(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>(static_cast const&>(_c)); } + + using FixedHash::operator==; + using FixedHash::operator!=; + using FixedHash::operator<; + using FixedHash::operator>=; + using FixedHash::operator<=; + using FixedHash::operator>; + + // The obvious binary operators. + SecureFixedHash& operator^=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator^(FixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator|(FixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator&(FixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + + SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + SecureFixedHash operator~() const { ~static_cast&>(*this); return *this; } + + using FixedHash::abridged; + using FixedHash::abridgedMiddle; + + bytesConstRef ref() const { return FixedHash::ref(); } + byte const* data() const { return FixedHash::data(); } + + static SecureFixedHash random() { SecureFixedHash ret; ret.FixedHash::ref().randomize(); return ret; } + using FixedHash::firstBitSet; + + void clear() { ref().cleanse(); } +}; + /// Fast equality operator for h256. template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const { @@ -246,6 +317,14 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) return _out; } +/// Stream I/O for the SecureFixedHash class. +template +inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash const& _h) +{ + _out << "SecureFixedHash#" << std::hex << typename FixedHash::hash()(_h.makeInsecure()) << std::dec; + return _out; +} + // Common types of FixedHash. using h2048 = FixedHash<256>; using h1024 = FixedHash<128>; diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp index 880f23d6e..ea1f0de22 100644 --- a/libdevcore/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -211,13 +211,14 @@ defsha3(512) } -h256 sha3(bytesConstRef _input) +bool sha3(bytesConstRef _input, bytesRef o_output) { // FIXME: What with unaligned memory? - h256 ret; - keccak::sha3_256(ret.data(), 32, _input.data(), _input.size()); + if (o_output.size() != 32) + return false; + keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); - return ret; + return true; } } diff --git a/libdevcore/SHA3.h b/libdevcore/SHA3.h index c3ef524fe..7be2367e9 100644 --- a/libdevcore/SHA3.h +++ b/libdevcore/SHA3.h @@ -32,20 +32,31 @@ namespace dev // SHA-3 convenience routines. -/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -h256 sha3(bytesConstRef _input); - /// Calculate SHA3-256 hash of the given input and load it into the given output. -inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); } +/// @returns false if o_output.size() != 32. +bool sha3(bytesConstRef _input, bytesRef o_output); + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } +inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().ref()); return ret; } /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } +inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(bytesConstRef(&_input)); } /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(bytesConstRef(_input)); } /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(FixedHash const& _input) { return sha3Secure(_input.ref()); } + +/// Fully secure variants are equivalent for sha3 and sha3Secure. +inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); } +inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } +template inline SecureFixedHash<32> sha3Secure(SecureFixedHash const& _input) { return sha3Secure(_input.ref()); } /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 6f2bff5bd..1932a8fda 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -5,11 +5,13 @@ #include #include #include +#include namespace dev { static unsigned char s_cleanseCounter = 0; +static std::random_device s_vectorRefEngine; /** * A modifiable reference to an existing object or vector in memory. @@ -67,6 +69,16 @@ public: void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Populate with random data. + template + void randomize(Engine& _eng) + { + uint8_t* e = (uint8_t*)end(); + for (uint8_t* i = (uint8_t*)begin(); i != e; ++i) + *i = (uint8_t)std::uniform_int_distribution(0, 255)(_eng); + } + /// @returns a random valued object. + void randomize() { randomize(s_vectorRefEngine); } /// Securely overwrite the memory. /// @note adapted from OpenSSL's implementation. void cleanse() diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h index 60c6afdf6..6f72369f6 100644 --- a/libdevcrypto/AES.h +++ b/libdevcrypto/AES.h @@ -31,4 +31,4 @@ namespace dev bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); -} \ No newline at end of file +} diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b13f25453..606c5794c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -149,7 +149,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) return decrypt(_k, _cipher, o_plain); } -std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) +std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) { h128 iv(Nonce::get()); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); @@ -175,23 +175,23 @@ bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _pl } } -bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) +bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) { if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) - return bytes(); + return bytesSec(); SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); - bytes ret(_cipher.size()); - d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); + bytesSec ret(_cipher.size()); + d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - return bytes(); + return bytesSec(); } } @@ -239,12 +239,12 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) #endif } -bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) +bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (PKCS5_PBKDF2_HMAC().DeriveKey( - ret.data(), - ret.size(), + ret.writable().data(), + _dkLen, 0, reinterpret_cast(_pass.data()), _pass.size(), @@ -256,9 +256,9 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, return ret; } -bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) { - bytes ret(_dkLen); + bytesSec ret(_dkLen); if (libscrypt_scrypt( reinterpret_cast(_pass.data()), _pass.size(), @@ -267,8 +267,8 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin _n, _r, _p, - ret.data(), - ret.size() + ret.writable().data(), + _dkLen ) != 0) BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); return ret; @@ -285,7 +285,7 @@ KeyPair KeyPair::create() { for (int i = 0; i < 100; ++i) { - KeyPair ret(FixedHash<32>::random()); + KeyPair ret(Secret::random()); if (ret.address()) return ret; } @@ -294,7 +294,7 @@ KeyPair KeyPair::create() KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) { - return KeyPair(sha3(aesDecrypt(_seed, _password))); + return KeyPair(Secret(sha3(aesDecrypt(_seed, _password)))); } h256 crypto::kdf(Secret const& _priv, h256 const& _hash) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 44d1c8155..c90481cb4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -32,15 +32,7 @@ namespace dev { -/// A secret key: 32 bytes. -/// @NOTE This is not endian-specific; it's just a bunch of bytes. -class Secret: public h256 -{ -public: - template Secret(Args&& ... _args): h256(_args ...) {} - Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {} - ~Secret() { ref().cleanse(); } -}; +using Secret = SecureFixedHash<32>; /// A public key: 64 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -82,7 +74,7 @@ using Addresses = h160s; using AddressHash = std::unordered_set; /// A vector of secrets. -using Secrets = h256s; +using Secrets = std::vector; /// Convert a secret key into the public key equivalent. Public toPublic(Secret const& _secret); @@ -116,21 +108,21 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypts payload with random IV/ctr using AES128-CTR. -std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); +std::pair encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); /// Decrypts payload with specified IV/ctr using AES128-CTR. -bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); +bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); /// Encrypts payload with specified IV/ctr using AES128-CTR. -inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } -inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } /// Decrypts payload with specified IV/ctr using AES128-CTR. -inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } -inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); @@ -142,10 +134,10 @@ Signature sign(Secret const& _k, h256 const& _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash); /// Derive key via PBKDF2. -bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); +bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); /// Derive key via Scrypt. -bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); +bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. @@ -176,8 +168,8 @@ public: /// Retrieve the associated address of the public key. Address const& address() const { return m_address; } - bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; } - bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } + bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } + bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } private: void populateFromSecret(Secret const& _k); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 693952d5f..6366f0da1 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -67,7 +67,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) { // interop w/go ecies implementation auto r = KeyPair::create(); - h256 z; + Secret z; ecdh::agree(r.sec(), _k, z); auto key = eciesKDF(z, bytes(), 32); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); @@ -77,7 +77,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) bytes mKey(32); ctx.Final(mKey.data()); - bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); + bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; @@ -110,8 +110,8 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) // invalid message: length return false; - h256 z; - ecdh::agree(_k, *(Public*)(io_text.data()+1), z); + Secret z; + ecdh::agree(_k, *(Public*)(io_text.data() + 1), z); auto key = eciesKDF(z, bytes(), 64); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); @@ -137,7 +137,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) if (mac[i] != msgMac[i]) return false; - plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); + plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); io_text.resize(plain.size()); io_text.swap(plain); @@ -222,7 +222,7 @@ Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash) Integer kInv = k.InverseMod(m_q); Integer z(_hash.asBytes().data(), 32); - Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; + Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q; if (r == 0 || s == 0) BOOST_THROW_EXCEPTION(InvalidState()); @@ -310,7 +310,7 @@ bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p) return true; } -void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) +void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s) { // TODO: mutex ASN1::secp256k1() singleton // Creating Domain is non-const for m_oid and m_oid is not thread-safe @@ -318,7 +318,7 @@ void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; memcpy(&remote[1], _r.data(), 64); - d.Agree(o_s.data(), _s.data(), remote); + d.Agree(o_s.writable().data(), _s.data(), remote); } void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& o_p) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index fca094242..564d1c5c0 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -107,10 +107,10 @@ public: /// Verifies _s is a valid secret key and returns corresponding public key in o_p. bool verifySecret(Secret const& _s, Public& o_p); - void agree(Secret const& _s, Public const& _r, h256& o_s); + void agree(Secret const& _s, Public const& _r, Secret& o_s); protected: - void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); } + void exportPrivateKey(DL_PrivateKey_EC const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); } void exportPublicKey(DL_PublicKey_EC const& _k, Public& o_p); diff --git a/libdevcrypto/ECDHE.cpp b/libdevcrypto/ECDHE.cpp index 3005d38c1..90b3381f8 100644 --- a/libdevcrypto/ECDHE.cpp +++ b/libdevcrypto/ECDHE.cpp @@ -29,7 +29,7 @@ using namespace dev::crypto; static Secp256k1PP s_secp256k1; -void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s) +void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) { s_secp256k1.agree(_s, _r, o_s); } diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h index 1a2442727..3658caf3d 100644 --- a/libdevcrypto/ECDHE.h +++ b/libdevcrypto/ECDHE.h @@ -50,7 +50,7 @@ private: namespace ecdh { -void agree(Secret const& _s, Public const& _r, h256& o_s); +void agree(Secret const& _s, Public const& _r, Secret& o_s); } /** diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index b823ba02f..266f3735a 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -100,17 +100,17 @@ bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bytesSec key; if (it != m_keys.end()) { - key = decrypt(it->second.encryptedKey, _pass()); + key = bytesSec(decrypt(it->second.encryptedKey, _pass())); if (!key.empty()) m_cached[_uuid] = key; } return key; } -h128 SecretStore::importSecret(bytes const& _s, string const& _pass) +h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass) { h128 r; - EncryptedKey key{encrypt(_s, _pass), string()}; + EncryptedKey key{encrypt(_s.ref(), _pass), string()}; r = h128::random(); m_cached[r] = _s; m_keys[r] = move(key); @@ -118,6 +118,17 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass) return r; } +h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass) +{ + h128 r; + EncryptedKey key{encrypt(_s, _pass), string()}; + r = h128::random(); + m_cached[r] = bytesSec(_s); + m_keys[r] = move(key); + save(); + return r; +} + void SecretStore::kill(h128 const& _uuid) { m_cached.erase(_uuid); @@ -188,16 +199,16 @@ h128 SecretStore::readKeyContent(string const& _content, string const& _file) bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function const& _pass, KDF _kdf) { - bytes s = secret(_uuid, _pass, true); + bytesSec s = secret(_uuid, _pass, true); if (s.empty()) return false; m_cached.erase(_uuid); - m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf); + m_keys[_uuid].encryptedKey = encrypt(s.ref(), _newPass, _kdf); save(); return true; } -static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) +static bytesSec deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) { unsigned dklen = 32; unsigned iterations = 1 << 18; @@ -233,16 +244,16 @@ static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) } } -string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) +string SecretStore::encrypt(bytesConstRef _v, string const& _pass, KDF _kdf) { js::mObject ret; - bytes derivedKey = deriveNewKey(_pass, _kdf, ret); + bytesSec derivedKey = deriveNewKey(_pass, _kdf, ret); if (derivedKey.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed.")); ret["cipher"] = "aes-128-ctr"; - h128 key(derivedKey, h128::AlignLeft); + SecureFixedHash<16> key(derivedKey, h128::AlignLeft); h128 iv = h128::random(); { js::mObject params; @@ -251,19 +262,19 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) } // cipher text - bytes cipherText = encryptSymNoAuth(key, iv, &_v); + bytes cipherText = encryptSymNoAuth(key, iv, _v); if (cipherText.empty()) BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed.")); ret["ciphertext"] = toHex(cipherText); // and mac. - h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); + h256 mac = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); ret["mac"] = toHex(mac.ref()); return js::write_string(js::mValue(ret), true); } -bytes SecretStore::decrypt(string const& _v, string const& _pass) +bytesSec SecretStore::decrypt(string const& _v, string const& _pass) { js::mObject o; { @@ -273,14 +284,14 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) } // derive key - bytes derivedKey; + bytesSec derivedKey; if (o["kdf"].get_str() == "pbkdf2") { auto params = o["kdfparams"].get_obj(); if (params["prf"].get_str() != "hmac-sha256") { cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } unsigned iterations = params["c"].get_int(); bytes salt = fromHex(params["salt"].get_str()); @@ -294,13 +305,13 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) else { cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2")) { cwarn << "Derived key's length too short (<32 bytes)"; - return bytes(); + return bytesSec(); } bytes cipherText = fromHex(o["ciphertext"].get_str()); @@ -311,23 +322,23 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h256 mac(o["mac"].get_str()); h256 macExp; if (o.count("compat") && o["compat"].get_str() == "2") - macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); else - macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText); + macExp = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else if (o.count("sillymac")) { h256 mac(o["sillymac"].get_str()); - h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + return bytesSec(); } } else @@ -340,15 +351,15 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass) h128 iv(params["iv"].get_str()); if (o.count("compat") && o["compat"].get_str() == "2") { - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + SecureFixedHash<16> key(sha3Secure(derivedKey.ref().cropped(derivedKey.size() - 16)), h128::AlignRight); return decryptSymNoAuth(key, iv, &cipherText); } else - return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText); + return decryptSymNoAuth(SecureFixedHash<16>(derivedKey, h128::AlignLeft), iv, &cipherText); } else { cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; - return bytes(); + return bytesSec(); } } diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index ea08a48b2..fbc4c0bec 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -60,7 +60,8 @@ public: h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } /// Imports the decrypted key given by @a _s and stores it, encrypted with /// (a key derived from) the password @a _pass. - h128 importSecret(bytes const& _s, std::string const& _pass); + h128 importSecret(bytesSec const& _s, std::string const& _pass); + h128 importSecret(bytesConstRef _s, std::string const& _pass); /// Decrypts and re-encrypts the key identified by @a _uuid. bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); /// Removes the key specified by @a _uuid from both memory and disk. @@ -102,9 +103,9 @@ private: void load(std::string const& _keysPath); void load() { load(m_path); } /// Encrypts @a _v with a key derived from @a _pass or the empty string on error. - static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); + static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. - static bytes decrypt(std::string const& _v, std::string const& _pass); + static bytesSec decrypt(std::string const& _v, std::string const& _pass); /// Stores decrypted keys by uuid. mutable std::unordered_map m_cached; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7ef3dd21e..ca58f65e3 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -101,7 +101,7 @@ private: if (_name == "authorities") BasicAuthority::s_authorities = rlp.toUnorderedSet
(); else if (_name == "authority") - m_secret = rlp.toHash(); + m_secret = Secret(rlp.toHash()); else return false; return true; diff --git a/libethcore/CommonJS.h b/libethcore/CommonJS.h index 0ff21afdf..fdd18d6e5 100644 --- a/libethcore/CommonJS.h +++ b/libethcore/CommonJS.h @@ -40,7 +40,7 @@ Address toAddress(std::string const& _a); inline Public jsToPublic(std::string const& _s) { return jsToFixed(_s); } /// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length. -inline Secret jsToSecret(std::string const& _s) { return jsToFixed(_s); } +inline Secret jsToSecret(std::string const& _s) { h256 d = jsToFixed(_s); Secret ret(d); d.ref().cleanse(); return ret; } /// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length. inline Address jsToAddress(std::string const& _s) { return jsToFixed(_s); } diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 26cf451d0..6d4dab1ce 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -81,9 +81,9 @@ bool KeyManager::load(string const& _pass) { bytes salt = contents(m_keysFile + ".salt"); bytes encKeys = contents(m_keysFile); - m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16)); - bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); - RLP s(bs); + m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); + bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); + RLP s(bs.ref()); unsigned version = unsigned(s[0]); if (version == 1) { @@ -178,7 +178,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con auto passHash = hashPassword(_pass); cachePassword(_pass); m_passwordHint[passHash] = _passwordHint; - auto uuid = m_store.importSecret(_s.asBytes(), _pass); + auto uuid = m_store.importSecret(_s.asBytesSec(), _pass); m_keyInfo[uuid] = KeyInfo{passHash, _accountName}; m_addrLookup[addr] = uuid; write(m_keysFile); @@ -187,7 +187,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint) { - bytes key = m_store.secret(_uuid, [&](){ return _pass; }); + bytesSec key = m_store.secret(_uuid, [&](){ return _pass; }); if (key.empty()) return; Address a = KeyPair(Secret(key)).address(); @@ -258,7 +258,7 @@ string const& KeyManager::passwordHint(Address const& _address) const h256 KeyManager::hashPassword(string const& _pass) const { // TODO SECURITY: store this a bit more securely; Scrypt perhaps? - return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32)); + return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure()); } void KeyManager::cachePassword(string const& _password) const @@ -278,14 +278,14 @@ void KeyManager::write(string const& _pass, string const& _keysFile) const { bytes salt = h256::random().asBytes(); writeFile(_keysFile + ".salt", salt); - auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16)); cachePassword(_pass); m_master = hashPassword(_pass); write(key, _keysFile); } -void KeyManager::write(h128 const& _key, string const& _keysFile) const +void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const { RLPStream s(4); s << 1; // version diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index a2b5a4e07..0fefc17ee 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -136,8 +136,8 @@ private: // @returns false if wasn't previously loaded ok. bool write() const { return write(m_keysFile); } bool write(std::string const& _keysFile) const; - void write(std::string const& _pass, std::string const& _keysFile) const; - void write(h128 const& _key, std::string const& _keysFile) const; + void write(std::string const& _pass, std::string const& _keysFile) const; // TODO: all passwords should be a secure string. + void write(SecureFixedHash<16> const& _key, std::string const& _keysFile) const; // Ethereum keys. @@ -159,7 +159,7 @@ private: std::string m_defaultPasswordDeprecated; mutable std::string m_keysFile; - mutable h128 m_keysFileKey; + mutable SecureFixedHash<16> m_keysFileKey; mutable h256 m_master; SecretStore m_store; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 46e0efe95..dd9ff53cf 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -809,7 +809,7 @@ bytes Host::saveNetwork() const // else: TODO: use previous configuration if available RLPStream ret(3); - ret << dev::p2p::c_protocolVersion << m_alias.secret(); + ret << dev::p2p::c_protocolVersion << m_alias.secret().ref(); ret.appendList(count); if (!!count) ret.appendRaw(network.out(), count); diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index e0ebd6c2d..4fee9b42b 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -40,7 +40,7 @@ void RLPXHandshake::writeAuth() // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) Secret staticShared; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared); - sign(m_ecdhe.seckey(), staticShared ^ m_nonce).ref().copyTo(sig); + sign(m_ecdhe.seckey(), staticShared.makeInsecure() ^ m_nonce).ref().copyTo(sig); sha3(m_ecdhe.pubkey().ref(), hepubk); m_host->m_alias.pub().ref().copyTo(pubk); m_nonce.ref().copyTo(nonce); @@ -92,7 +92,7 @@ void RLPXHandshake::readAuth() Secret sharedSecret; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret); - m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); + m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret.makeInsecure() ^ m_remoteNonce); if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index bf18835b6..3216cc90b 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -60,7 +60,7 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes for (unsigned i = 0; i < _e.topic().size(); ++i) if (_e.topic()[i] == knownTopic[ti]) { - topicSecret = _fk[ti]; + topicSecret = Secret(_fk[ti]); topicIndex = i; break; } @@ -69,9 +69,9 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes return false; unsigned index = topicIndex * 2; - h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); + Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size)); - h256 key = generateGamma(topicSecret, salt) ^ encryptedKey; + Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure()); bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size()); return decryptSym(key, cipherText, o_b); } @@ -122,10 +122,10 @@ Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned // this message is for broadcast (could be read by anyone who knows at least one of the topics) // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic Secret s = Secret::random(); - for (h256 const& t : _fullTopics) + for (h256 const& t: _fullTopics) { h256 salt = h256::random(); - ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); + ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes(); ret.m_data += salt.asBytes(); } diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 1ec28ae01..c29194e97 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -127,7 +127,7 @@ public: private: bool populate(bytes const& _data); bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); - h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } + Secret generateGamma(Secret const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Public m_from; Public m_to; diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 0a583f2a0..1c9faa896 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -187,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) bytes dapp = rlpStr.out(); dev::h256 dappHash = dev::sha3(dapp); //encrypt - KeyPair key(dappHash); + KeyPair key((Secret(dappHash))); Secp256k1PP enc; enc.encrypt(key.pub(), dapp); diff --git a/test/libdevcrypto/AES.cpp b/test/libdevcrypto/AES.cpp index a8aeb4cd1..0617033aa 100644 --- a/test/libdevcrypto/AES.cpp +++ b/test/libdevcrypto/AES.cpp @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(AesDecrypt) { cout << "AesDecrypt" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address()); } @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed) { cout << "AesDecryptWrongSeed" << endl; bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "test"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword) { cout << "AesDecryptWrongPassword" << endl; bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); - KeyPair kp(sha3(aesDecrypt(&seed, "badtest"))); + KeyPair kp(sha3Secure(aesDecrypt(&seed, "badtest"))); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); } diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 30bff49d9..bff6e0720 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -61,9 +61,9 @@ BOOST_AUTO_TEST_CASE(basic_tests) SecretStore store(tmpDir.path()); h128 u = store.readKeyContent(js::write_string(o["json"], false)); cdebug << "read uuid" << u; - bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); - cdebug << "got secret" << toHex(s); - BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str()); + bytesSec s = store.secret(u, [&](){ return o["password"].get_str(); }); + cdebug << "got secret" << toHex(s.makeInsecure()); + BOOST_REQUIRE_EQUAL(toHex(s.makeInsecure()), o["priv"].get_str()); } } @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) uuid = store.importKey(importFile); BOOST_CHECK(!!uuid); BOOST_CHECK(contentsString(importFile) == keyData); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } fs::remove(importFile); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } @@ -121,15 +121,15 @@ BOOST_AUTO_TEST_CASE(import_secret) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); } } } @@ -145,12 +145,12 @@ BOOST_AUTO_TEST_CASE(wrong_password) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); // password will not be queried - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }).makeInsecure())); } { SecretStore store(storeDir.path()); @@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE(recode) { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 0); - uuid = store.importSecret(fromHex(priv), password); + uuid = store.importSecret(bytesSec(fromHex(priv)), password); BOOST_CHECK(!!uuid); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure())); BOOST_CHECK_EQUAL(store.keys().size(), 1); } { @@ -182,16 +182,16 @@ BOOST_AUTO_TEST_CASE(recode) BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; })); BOOST_CHECK_EQUAL(store.keys().size(), 1); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); store.clearCache(); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } { SecretStore store(storeDir.path()); BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); - BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure())); } } diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 49c8471fd..2d7392d7e 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_patch) BOOST_AUTO_TEST_CASE(verify_secert) { - h256 empty; + Secret empty; KeyPair kNot(empty); BOOST_REQUIRE(!kNot.address()); KeyPair k(sha3(empty)); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) bytes e(fromHex("0x01")); e.resize(32); int tests = 2; - while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + while (sha3(&e, &e), secret = sha3(secret), tests--) { KeyPair key(secret); Public pkey = key.pub(); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) Integer r = s_params.ConvertElementToInteger(rp); Integer kInv = kInt.InverseMod(q); - Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; + Integer s = (kInv * (Integer(secret.data(), 32) * r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); Signature sig; @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(ecies_kdf) BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes()); BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes()); - BOOST_REQUIRE((u256)h256(z1) > 0); + BOOST_REQUIRE(!!z1); BOOST_REQUIRE(z1 == z2); BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0); @@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(ecdh) ECDH::Domain dhA(s_curveOID); Secret shared; - BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); + BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.sec().data(), pubb)); BOOST_REQUIRE(shared); } @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA); - sign(eA.seckey(), ssA ^ nonceA).ref().copyTo(sig); + sign(eA.seckey(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig); sha3(eA.pubkey().ref(), hepubk); nodeA.pub().ref().copyTo(pubk); nonceA.ref().copyTo(nonce); @@ -520,21 +520,21 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - aEncryptK = sha3(keyMaterial); + aEncryptK = sha3Secure(keyMaterial); aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - aMacK = sha3(keyMaterial); + aMacK = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceBAck).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - aEgressMac = sha3(keyMaterial); + aEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (aMacK ^ nonceA).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - aIngressMac = sha3(keyMaterial); + aIngressMac = sha3Secure(keyMaterial); } @@ -573,7 +573,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) Secret ss; s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss); - eAAuth = recover(sigAuth, ss ^ nonceAAuth); + eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure()); // todo: test when this fails; means remote is bad or packet bits were flipped BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth)); BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey()); @@ -588,22 +588,22 @@ BOOST_AUTO_TEST_CASE(handshakeNew) ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); // auto token = sha3(ssA); - bEncryptK = sha3(keyMaterial); + bEncryptK = sha3Secure(keyMaterial); bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - bMacK = sha3(keyMaterial); + bMacK = sha3Secure(keyMaterial); // todo: replace nonceB with decrypted nonceB keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); - bEgressMac = sha3(keyMaterial); + bEgressMac = sha3Secure(keyMaterial); keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); (bMacK ^ nonceB).ref().copyTo(keyMaterial); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); - bIngressMac = sha3(keyMaterial); + bIngressMac = sha3Secure(keyMaterial); } BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK); @@ -617,7 +617,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew) BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) { - h128 encryptK(sha3("..."), h128::AlignLeft); + SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft); h256 egressMac(sha3("+++")); // TESTING: send encrypt magic sequence bytes magic {0x22,0x40,0x08,0x91}; @@ -629,16 +629,17 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); - bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); + bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure(); plaintext.resize(magic.size()); + // @alex @subtly TODO: FIX: this check is pointless with the above line. BOOST_REQUIRE(plaintext.size() > 0); BOOST_REQUIRE(magic == plaintext); } BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) { - h128 k(sha3("0xAAAA"), h128::AlignLeft); + SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft); string m = "AAAAAAAAAAAAAAAA"; bytesConstRef msg((byte*)m.data(), m.size()); @@ -646,7 +647,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) h128 iv; tie(ciphertext, iv) = encryptSymNoAuth(k, msg); - bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); + bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure(); BOOST_REQUIRE_EQUAL(asString(plaintext), m); } diff --git a/test/libethcore/commonjs.cpp b/test/libethcore/commonjs.cpp index 72582c540..ca472a6f4 100644 --- a/test/libethcore/commonjs.cpp +++ b/test/libethcore/commonjs.cpp @@ -32,8 +32,8 @@ BOOST_AUTO_TEST_CASE(jsToPublic) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.pub()); - Public pub = dev::jsToPublic(string); + string s = toJS(kp.pub()); + Public pub = dev::jsToPublic(s); BOOST_CHECK_EQUAL(kp.pub(), pub); } @@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(jsToAddress) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.address()); - Address address = dev::jsToAddress(string); + string s = toJS(kp.address()); + Address address = dev::jsToAddress(s); BOOST_CHECK_EQUAL(kp.address(), address); } @@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE(jsToSecret) { cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); - string string = toJS(kp.secret()); - Secret secret = dev::jsToSecret(string); - BOOST_CHECK_EQUAL(kp.secret(), secret); + string s = toJS(kp.secret().makeInsecure()); + Secret secret = dev::jsToSecret(s); + BOOST_CHECK_EQUAL(kp.secret().makeInsecure(), secret.makeInsecure()); } BOOST_AUTO_TEST_SUITE_END() From c429b03ddb964c602c1b5fcd719fc55a6a24f1be Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 28 Jul 2015 09:55:27 +0200 Subject: [PATCH 33/53] Disable chunking until further notice --- libethash-cl/ethash_cl_miner.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 8042888cb..2183de320 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -371,6 +371,9 @@ bool ethash_cl_miner::init( } catch (cl::Error const& err) { + ETHCL_LOG("Allocating/mapping single buffer failed with: " << err.what() << "(" << err.err() << "). GPU can't allocate the DAG in a single chunk. Bailing."); + return false; +#if 0 // Disabling chunking for release since it seems not to work. Never manages to mine a block. TODO: Fix when time is found. int errCode = err.err(); if (errCode != CL_INVALID_BUFFER_SIZE || errCode != CL_MEM_OBJECT_ALLOCATION_FAILURE) ETHCL_LOG("Allocating/mapping single buffer failed with: " << err.what() << "(" << errCode << ")"); @@ -409,6 +412,7 @@ bool ethash_cl_miner::init( memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); } +#endif } // create buffer for header ETHCL_LOG("Creating buffer for header."); From 0ecb5a67eadfef8b3f94f226a58676fda184fb3c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 11:57:49 +0200 Subject: [PATCH 34/53] Don't stop syncing when a random bad block comes in the queue. --- libethereum/BlockChain.cpp | 89 ++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 98655a585..f4c17e595 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -384,52 +384,49 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c Transactions goodTransactions; unsigned count = 0; for (VerifiedBlock const& block: blocks) - if (!badBlocks.empty()) - badBlocks.push_back(block.verified.info.hash()); - else - { - do { - try - { - // Nonce & uncle nonces already verified in verification thread at this point. - ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); - fresh += r.liveBlocks; - dead += r.deadBlocks; - goodTransactions.reserve(goodTransactions.size() + r.goodTranactions.size()); - std::move(std::begin(r.goodTranactions), std::end(r.goodTranactions), std::back_inserter(goodTransactions)); - ++count; - } - catch (dev::eth::UnknownParent) - { - cwarn << "ODD: Import queue contains block with unknown parent.";// << LogTag::Error << boost::current_exception_diagnostic_information(); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. - badBlocks.push_back(block.verified.info.hash()); - } - catch (dev::eth::FutureTime) - { - cwarn << "ODD: Import queue contains a block with future time."; - this_thread::sleep_for(chrono::seconds(1)); - continue; - } - catch (dev::eth::TransientError) - { - this_thread::sleep_for(chrono::milliseconds(100)); - continue; - } - catch (Exception& ex) - { - // cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!";// << LogTag::Error << diagnostic_information(ex); - if (m_onBad) - m_onBad(ex); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. - badBlocks.push_back(block.verified.info.hash()); - } - } while (false); - } + { + do { + try + { + // Nonce & uncle nonces already verified in verification thread at this point. + ImportRoute r; + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + fresh += r.liveBlocks; + dead += r.deadBlocks; + goodTransactions.reserve(goodTransactions.size() + r.goodTranactions.size()); + std::move(std::begin(r.goodTranactions), std::end(r.goodTranactions), std::back_inserter(goodTransactions)); + ++count; + } + catch (dev::eth::UnknownParent) + { + cwarn << "ODD: Import queue contains block with unknown parent.";// << LogTag::Error << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + catch (dev::eth::FutureTime) + { + cwarn << "ODD: Import queue contains a block with future time."; + this_thread::sleep_for(chrono::seconds(1)); + continue; + } + catch (dev::eth::TransientError) + { + this_thread::sleep_for(chrono::milliseconds(100)); + continue; + } + catch (Exception& ex) + { +// cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!";// << LogTag::Error << diagnostic_information(ex); + if (m_onBad) + m_onBad(ex); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + } while (false); + } return make_tuple(ImportRoute{dead, fresh, goodTransactions}, _bq.doneDrain(badBlocks), count); } From 6d10e19fb126dc30929672f1c2af65eddb8faa33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Jul 2015 12:03:47 +0200 Subject: [PATCH 35/53] Place project version in cmake variable PROJECT_VERSION. --- BuildInfo.h.in | 4 ++-- CMakeLists.txt | 11 +++++++++-- libdevcore/Common.cpp | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/BuildInfo.h.in b/BuildInfo.h.in index 7d2bfc1c8..5e97b71a5 100644 --- a/BuildInfo.h.in +++ b/BuildInfo.h.in @@ -1,7 +1,7 @@ #pragma once +#define ETH_PROJECT_VERSION "@PROJECT_VERSION@" #define ETH_COMMIT_HASH @ETH_COMMIT_HASH@ #define ETH_CLEAN_REPO @ETH_CLEAN_REPO@ #define ETH_BUILD_TYPE @ETH_BUILD_TYPE@ -#define ETH_BUILD_PLATFORM @ETH_BUILD_PLATFORM@ - +#define ETH_BUILD_PLATFORM @ETH_BUILD_PLATFORM@ diff --git a/CMakeLists.txt b/CMakeLists.txt index edf57debe..bbdda0a77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,13 @@ # cmake global cmake_minimum_required(VERSION 2.8.12) -project(ethereum) +set(PROJECT_VERSION "0.9.34") +if (${CMAKE_VERSION} VERSION_GREATER 3.0) + cmake_policy(SET CMP0048 NEW) # allow VERSION argument in project() + project(ethereum VERSION ${PROJECT_VERSION}) +else() + project(ethereum) +endif() set(CMAKE_AUTOMOC ON) @@ -136,6 +142,7 @@ function(createBuildInfo) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -DETH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" -DETH_DST_DIR="${CMAKE_BINARY_DIR}" -DETH_BUILD_TYPE="${_cmake_build_type}" -DETH_BUILD_PLATFORM="${ETH_BUILD_PLATFORM}" + -DPROJECT_VERSION="${PROJECT_VERSION}" -P "${ETH_SCRIPTS_DIR}/buildinfo.cmake" ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -539,7 +546,7 @@ if (WIN32) set(CPACK_PACKAGE_VENDOR "ethereum.org") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") - set(CPACK_PACKAGE_VERSION "0.9.34") + set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) set(CPACK_GENERATOR "NSIS") # seems to be not working # set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp") diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index d97b44445..6fd97a781 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -22,13 +22,14 @@ #include "Common.h" #include "Exceptions.h" #include "Log.h" +#include "BuildInfo.h" using namespace std; using namespace dev; namespace dev { -char const* Version = "0.9.34"; +char const* Version = ETH_PROJECT_VERSION; const u256 UndefinedU256 = ~(u256)0; @@ -57,4 +58,3 @@ TimerHelper::~TimerHelper() } } - From 6ee25c93d6ceaa12ebd3a7f2b7864c89690a21ba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 12:25:48 +0200 Subject: [PATCH 36/53] Allow importing of ethersale wallets in CLI. Fixes #2606. --- alethzero/MainWin.cpp | 40 ++++++--------------------------------- eth/main.cpp | 13 +++++++++++++ ethkey/KeyAux.h | 19 +++++++++++++++++-- libethcore/KeyManager.cpp | 35 ++++++++++++++++++++++++++++++++++ libethcore/KeyManager.h | 3 +++ 5 files changed, 74 insertions(+), 36 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 406d639cc..8bb86f850 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1017,46 +1017,18 @@ void Main::on_claimPresale_triggered() QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); try { - js::mValue val; - json_spirit::read_string(asString(dev::contents(s.toStdString())), val); - auto obj = val.get_obj(); - if (obj["encseed"].type() == js::str_type) - { - auto encseed = fromHex(obj["encseed"].get_str()); - KeyPair k; - for (bool gotit = false; !gotit;) - { - gotit = true; - k = KeyPair::fromEncryptedSeed(&encseed, QInputDialog::getText(this, "Enter Password", "Enter the wallet's passphrase", QLineEdit::Password).toStdString()); - if (obj["ethaddr"].type() == js::str_type) - { - Address a(obj["ethaddr"].get_str()); - Address b = k.address(); - if (a != b) - { - if (QMessageBox::warning(this, "Password Wrong", "Could not import the secret key: the password you gave appears to be wrong.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) - return; - else - gotit = false; - } - } - } - - cnote << k.address(); - if (!m_keyManager.hasAccount(k.address())) - ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice()); - else - QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); - } + KeyPair k = m_keyManager.presaleSecret(dev::contentsString(s.toStdString()), [&](bool){ return QInputDialog::getText(this, "Enter Password", "Enter the wallet's passphrase", QLineEdit::Password).toStdString(); }); + cnote << k.address(); + if (!m_keyManager.hasAccount(k.address())) + ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice()); else - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type") ); - + QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); } + catch (dev::eth::PasswordUnknown&) {} catch (...) { cerr << "Unhandled exception!" << endl << boost::current_exception_diagnostic_information(); - QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Ethereum key file."); } } diff --git a/eth/main.cpp b/eth/main.cpp index f85e7096f..ce3007241 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -140,6 +140,7 @@ void help() << " -R,--rebuild Rebuild the blockchain from the existing database." << endl << " --rescue Attempt to rescue a corrupt database." << endl << endl + << " --import-presale Import a presale key; you'll need to type the password to this." << endl << " -s,--import-secret Import a secret key into the key store and use as the default." << endl << " -S,--import-session-secret Import a secret key into the key store and use as the default for this session only." << endl << " --sign-key
Sign all transactions with the key of the given address." << endl @@ -226,6 +227,12 @@ void version() exit(0); } +void importPresale(KeyManager& _km, string const& _file, function _pass) +{ + KeyPair k = _km.presaleSecret(contentsString(_file), [&](bool){ return _pass(); }); + _km.import(k.secret(), "Presale wallet" + _file + " (insecure)"); +} + Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250"); string pretty(h160 _a, dev::eth::State const& _st) { @@ -1120,6 +1127,7 @@ int main(int argc, char** argv) Address signingKey; Address sessionKey; Address beneficiary = signingKey; + strings presaleImports; /// Structured logging params bool structuredLogging = false; @@ -1434,6 +1442,8 @@ int main(int argc, char** argv) pinning = true; else if (arg == "--hermit") pinning = disableDiscovery = true; + else if (arg == "--import-presale" && i + 1 < argc) + presaleImports.push_back(argv[++i]); else if (arg == "-f" || arg == "--force-mining") forceMining = true; else if (arg == "--old-interactive") @@ -1711,6 +1721,9 @@ int main(int argc, char** argv) keyManager.create(masterPassword); } + for (auto const& presale: presaleImports) + importPresale(keyManager, presale, [&](){ return getPassword("Enter your wallet password for " + presale + ": "); }); + for (auto const& s: toImport) { keyManager.import(s, "Imported key (UNSAFE)"); diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index af7d8e048..5f97375c8 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -104,6 +104,7 @@ public: New, Import, ImportWithAddress, + ImportPresale, Export, Recode, Kill, @@ -143,7 +144,7 @@ public: m_mode = OperationMode::DecodeTx; else if (arg == "--import-bare") m_mode = OperationMode::ImportBare; - else if (arg == "--list-bare") + else if (arg == "-l" || arg == "--list-bare") m_mode = OperationMode::ListBare; else if (arg == "--export-bare") m_mode = OperationMode::ExportBare; @@ -168,7 +169,13 @@ public: m_inputs = strings(1, argv[++i]); m_name = argv[++i]; } - else if ((arg == "-i" || arg == "--import-with-address") && i + 3 < argc) + else if (arg == "--import-presale" && i + 2 < argc) + { + m_mode = OperationMode::ImportPresale; + m_inputs = strings(1, argv[++i]); + m_name = argv[++i]; + } + else if (arg == "--import-with-address" && i + 3 < argc) { m_mode = OperationMode::ImportWithAddress; m_inputs = strings(1, argv[++i]); @@ -477,6 +484,13 @@ public: cout << " UUID: " << toUUID(u) << endl; break; } + case OperationMode::ImportPresale: + { + std::string pw; + KeyPair k = wallet.presaleSecret(contentsString(m_inputs[0]), [&](bool){ return (pw = getPassword("Enter the password for the presale key: ")); }); + wallet.import(k.secret(), m_name, pw, "Same password as used for presale key"); + break; + } case OperationMode::List: { vector bare; @@ -530,6 +544,7 @@ public: << " -l,--list List all keys available in wallet." << endl << " -n,--new Create a new key with given name and add it in the wallet." << endl << " -i,--import [||] Import keys from given source and place in wallet." << endl + << " --import-presale Import a presale wallet into a key with the given name." << endl << " --import-with-address [||]
Import keys from given source with given address and place in wallet." << endl << " -e,--export [
| , ... ] Export given keys." << endl << " -r,--recode [
|| , ... ] Decrypt and re-encrypt given keys." << endl diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 26cf451d0..3b1da2562 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -23,12 +23,14 @@ #include #include #include +#include #include #include #include using namespace std; using namespace dev; using namespace eth; +namespace js = json_spirit; namespace fs = boost::filesystem; KeyManager::KeyManager(string const& _keysFile, string const& _secretsPath): @@ -216,6 +218,39 @@ void KeyManager::kill(Address const& _a) write(m_keysFile); } +KeyPair KeyManager::presaleSecret(std::string const& _json, function const& _password) +{ + js::mValue val; + json_spirit::read_string(_json, val); + auto obj = val.get_obj(); + string p = _password(true); + if (obj["encseed"].type() == js::str_type) + { + auto encseed = fromHex(obj["encseed"].get_str()); + KeyPair k; + for (bool gotit = false; !gotit;) + { + gotit = true; + k = KeyPair::fromEncryptedSeed(&encseed, p); + if (obj["ethaddr"].type() == js::str_type) + { + Address a(obj["ethaddr"].get_str()); + Address b = k.address(); + if (a != b) + { + if ((p = _password(false)).empty()) + BOOST_THROW_EXCEPTION(PasswordUnknown()); + else + gotit = false; + } + } + } + return k; + } + else + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type")); +} + Addresses KeyManager::accounts() const { Addresses ret; diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index a2b5a4e07..86419c0ef 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -123,6 +123,9 @@ public: static std::string defaultPath() { return getDataDir("ethereum") + "/keys.info"; } + /// Extracts the secret key from the presale wallet. + KeyPair presaleSecret(std::string const& _json, std::function const& _password); + private: std::string getPassword(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; std::string getPassword(h256 const& _passHash, std::function const& _pass = DontKnowThrow) const; From 321b977e73cc45cc686b25d55c03223aceac1387 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 14:11:53 +0200 Subject: [PATCH 37/53] Fix tests. --- libethereum/BlockChain.cpp | 6 +++--- libethereum/BlockChain.h | 22 ++++++++++++++++------ libethereum/CanonBlockChain.cpp | 5 +++-- test/libethereum/gaspricer.cpp | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 87d2e54c7..a32f41830 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -146,13 +146,13 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path): m_dbPath(_path) { - open(_genesisBlock, _genesisState, _path, _we, _p); + open(_genesisBlock, _genesisState, _path); } -void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting, ProgressCallback const&) +void BlockChain::open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index c047fc4b6..c60482817 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -106,11 +106,11 @@ class BlockChain public: /// Doesn't open the database - if you want it open it's up to you to subclass this and open it /// in the constructor there. - BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path); ~BlockChain(); /// Reopen everything. - virtual void reopen(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()) { close(); open(m_genesisBlock, m_genesisState, m_dbPath, _we, _pc); } + virtual void reopen(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()) { close(); open(m_genesisBlock, m_genesisState, m_dbPath); openDatabase(m_dbPath, _we, _pc); } /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// To be called from main loop every 100ms or so. @@ -295,8 +295,10 @@ protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } /// Initialise everything and ready for openning the database. - void open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p); + // TODO: rename to init + void open(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path); /// Open the database. + // TODO: rename to open. unsigned openDatabase(std::string const& _path, WithExisting _we); /// Finalise everything and close the database. void close(); @@ -398,9 +400,11 @@ class FullBlockChain: public BlockChain public: using BlockHeader = typename Sealer::BlockHeader; - FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): - BlockChain(_genesisBlock, _genesisState, _path, _we, _p) - {} + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _pc = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path) + { + openDatabase(_path, _we, _pc); + } /// Get the header of a block (or the most recent mined if none given). Thread-safe. typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } @@ -491,6 +495,12 @@ public: res.block = bytesConstRef(_block); return res; } + +protected: + /// Constructor for derived classes to use when they'll open the chain db afterwards. + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path): + BlockChain(_genesisBlock, _genesisState, _path) + {} }; std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index b921d67e4..635b0bbd7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -45,7 +45,7 @@ string CanonBlockChain::s_genesisStateJSON; bytes CanonBlockChain::s_genesisExtraData; CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) + FullBlockChain(createGenesisBlock(), createGenesisState(), _path) { BlockChain::openDatabase(_path, _we, _pc); } @@ -53,7 +53,8 @@ CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc) { close(); - open(createGenesisBlock(), createGenesisState(), m_dbPath, _we, _pc); + open(createGenesisBlock(), createGenesisState(), m_dbPath); + openDatabase(m_dbPath, _we, _pc); } bytes CanonBlockChain::createGenesisBlock() diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index fc1c082b8..b4cbed8cb 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; namespace dev { namespace test { -void executeGasPricerTest(const string name, double _etherPrice, double _blockFee, const string bcTestPath, TransactionPriority _txPrio, u256 _expectedAsk, u256 _expectedBid) +void executeGasPricerTest(string const& name, double _etherPrice, double _blockFee, string const& bcTestPath, TransactionPriority _txPrio, u256 _expectedAsk, u256 _expectedBid) { cnote << name; BasicGasPricer gp(u256(double(ether / 1000) / _etherPrice), u256(_blockFee * 1000)); From 665c7240f880a79f4d20c2a6028695dcfcb0de66 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 28 Jul 2015 14:17:22 +0200 Subject: [PATCH 38/53] bugfix --- libethcore/Common.cpp | 29 ----------------------------- libethcore/Params.cpp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index eefc3052b..343d87be1 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -51,36 +51,7 @@ const unsigned c_databaseBaseVersion = 9; const unsigned c_databaseVersionModifier = 0; #endif -#if ETH_FRONTIER -Network c_network = resetNetwork(Network::Frontier); -#else -Network c_network = resetNetwork(Network::Olympic); -#endif -Network resetNetwork(Network _n) -{ - c_network = _n; - c_maximumExtraDataSize = c_network == Network::Olympic ? 1024 : 32; - switch(_n) - { - case Network::Turbo: - c_minGasLimit = 100000000; - break; - case Network::Olympic: - c_minGasLimit = 125000; - break; - case Network::Frontier: - c_minGasLimit = 5000; - break; - } - - c_gasLimitBoundDivisor = 1024; - c_minimumDifficulty = 131072; - c_difficultyBoundDivisor = 2048; - c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; - c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); - return _n; -} const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index c1290219e..0612db84e 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -38,6 +38,37 @@ u256 c_durationLimit; u256 c_blockReward; //--- END: AUTOGENERATED FROM /feeStructure.json +#if ETH_FRONTIER +Network c_network = resetNetwork(Network::Frontier); +#else +Network c_network = resetNetwork(Network::Olympic); +#endif + +Network resetNetwork(Network _n) +{ + c_network = _n; + c_maximumExtraDataSize = c_network == Network::Olympic ? 1024 : 32; + switch(_n) + { + case Network::Turbo: + c_minGasLimit = 100000000; + break; + case Network::Olympic: + c_minGasLimit = 125000; + break; + case Network::Frontier: + c_minGasLimit = 5000; + break; + } + + c_gasLimitBoundDivisor = 1024; + c_minimumDifficulty = 131072; + c_difficultyBoundDivisor = 2048; + c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 13; + c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); + return _n; +} + } } From f16cb2e23e309b36846e82de20e35e1dc18ef5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Jul 2015 14:34:55 +0200 Subject: [PATCH 39/53] Force Interpreter VM when VM tracing requested. Fixes https://github.com/ethereum/cpp-ethereum/issues/2585. --- libethereum/State.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5639b8bb6..27263caf8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1137,6 +1137,12 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { + auto onOp = _onOp; +#if ETH_VMTRACE + if (isChannelVisible()) + onOp = Executive::simpleTrace(); // override tracer +#endif + #if ETH_PARANOIA paranoia("start of execution.", true); State old(*this); @@ -1161,16 +1167,11 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << toHex(e.t().rlp()); #endif if (!e.execute()) -#if ETH_VMTRACE { - if (isChannelVisible()) - e.go(e.simpleTrace()); - else - e.go(_onOp); + if (onOp) + VMFactory::setKind(VMKind::Interpreter); // force interpreter if a trace is wanted + e.go(onOp); } -#else - e.go(_onOp); -#endif e.finalize(); #if ETH_PARANOIA @@ -1183,13 +1184,13 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per else { commit(); - + #if ETH_PARANOIA && !ETH_FATDB ctrace << "Executed; now" << rootHash(); ctrace << old.diff(*this); - + paranoia("after execution commit.", true); - + if (e.t().receiveAddress()) { EnforceRefs r(m_db, true); @@ -1200,9 +1201,9 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per } } #endif - + // TODO: CHECK TRIE after level DB flush to make sure exactly the same. - + // Add to the user-originated transactions that we've executed. m_transactions.push_back(e.t()); m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs())); From a51037e64504bec6bcc673dd31436707436a9f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Jul 2015 14:35:14 +0200 Subject: [PATCH 40/53] Fix incorrect std::move. --- libp2p/RLPXSocketIO.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libp2p/RLPXSocketIO.cpp b/libp2p/RLPXSocketIO.cpp index deb47a728..aa4df7e20 100644 --- a/libp2p/RLPXSocketIO.cpp +++ b/libp2p/RLPXSocketIO.cpp @@ -1,16 +1,16 @@ /* This file is part of cpp-ethereum. - + cpp-ethereum 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 3 of the License, or (at your option) any later version. - + cpp-ethereum 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 cpp-ethereum. If not, see . */ @@ -34,7 +34,7 @@ RLPXSocketIO::RLPXSocketIO(unsigned _protCount, RLPXFrameCoder& _coder, bi::tcp: m_flowControl(_flowControl), m_coder(_coder), m_socket(_socket), - m_writers(move(writers(_protCount))), + m_writers(writers(_protCount)), m_egressCapacity(m_flowControl ? _initialCapacity : MaxPacketSize * m_writers.size()) {} @@ -61,11 +61,11 @@ void RLPXSocketIO::send(unsigned _protocolType, unsigned _type, RLPStream& _payl void RLPXSocketIO::doWrite() { m_toSend.clear(); - + size_t capacity; DEV_GUARDED(x_queued) capacity = min(m_egressCapacity, MaxPacketSize); - + size_t active = 0; for (auto const& w: m_writers) if (w.size()) @@ -97,7 +97,7 @@ void RLPXSocketIO::write(size_t _dequed) { if (ec) return; // TCPSocketWriteError - + bool reschedule = false; DEV_GUARDED(x_queued) { @@ -109,4 +109,4 @@ void RLPXSocketIO::write(size_t _dequed) if (reschedule) doWrite(); }); -} \ No newline at end of file +} From ef98742820567ceb6a93bebde11bcee554ec6b97 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Jul 2015 14:37:36 +0200 Subject: [PATCH 41/53] Internal jsonrpc uses its own session. Fixes #2597 --- eth/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 87f5e1b53..4d3707c10 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1810,7 +1810,8 @@ int main(int argc, char** argv) #if ETH_JSCONSOLE || !ETH_TRUE JSLocalConsole console; shared_ptr rpcServer = make_shared(*console.connector(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer); - console.eval("web3.admin.setSessionKey('" + jsonAdmin + "')"); + string sessionKey = rpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); + console.eval("web3.admin.setSessionKey('" + sessionKey + "')"); while (!g_exit) { console.readExpression(); From 78fd8548edb0f0622fb1141b7ce3905cd002f159 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 28 Jul 2015 14:44:55 +0200 Subject: [PATCH 42/53] fixed JitWorker initialization --- libevm/SmartVM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index 50a548002..565e88213 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -61,8 +61,8 @@ namespace class JitWorker { - std::thread m_worker; concurrent_queue m_queue; + std::thread m_worker; // Worker must be last to initialize void work() { From c30ae3216d5b7336c793b5f041b2f2e90744b7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Jul 2015 14:47:55 +0200 Subject: [PATCH 43/53] Force Interpreter VM when VM tracing requested (moved from State to Executive). Fixes https://github.com/ethereum/cpp-ethereum/issues/2585. --- libethereum/Executive.cpp | 3 ++- libethereum/State.cpp | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index d281a00fd..f78e8f7f4 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -325,7 +325,8 @@ bool Executive::go(OnOpFunc const& _onOp) #endif try { - auto vm = VMFactory::create(); + // Create VM instance. Force Interpreter if tracing requested. + auto vm = _onOp ? VMFactory::create(VMKind::Interpreter) : VMFactory::create(); if (m_isCreation) { auto out = vm->exec(m_gas, *m_ext, _onOp); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 27263caf8..3127ad1f6 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1167,11 +1167,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << toHex(e.t().rlp()); #endif if (!e.execute()) - { - if (onOp) - VMFactory::setKind(VMKind::Interpreter); // force interpreter if a trace is wanted e.go(onOp); - } e.finalize(); #if ETH_PARANOIA From 8f1d5b4330e08a8369f9624cac377f4ff0b807aa Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Jul 2015 14:51:47 +0200 Subject: [PATCH 44/53] Fixed typo. --- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 6 +++--- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 ++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- libweb3jsonrpc/WebThreeStubServerBase.h | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6858d7ecf..214dbab1e 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -233,7 +233,7 @@ Main::Main(QWidget *parent) : m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); - auto sessionKey = w3ss->newSession(SessionPermissions{{Priviledge::Admin}}); + auto sessionKey = w3ss->newSession(SessionPermissions{{Privilege::Admin}}); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); diff --git a/eth/main.cpp b/eth/main.cpp index 4d3707c10..157cc3b76 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1779,9 +1779,9 @@ int main(int argc, char** argv) jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) - jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Privilege::Admin}}); else - jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}}); + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Privilege::Admin}}); cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; writeFile(getDataDir("web3") + "/session.key", jsonAdmin); writeFile(getDataDir("web3") + "/session.url", "http://localhost:" + toString(jsonRPCURL)); @@ -1810,7 +1810,7 @@ int main(int argc, char** argv) #if ETH_JSCONSOLE || !ETH_TRUE JSLocalConsole console; shared_ptr rpcServer = make_shared(*console.connector(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer); - string sessionKey = rpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); + string sessionKey = rpcServer->newSession(SessionPermissions{{Privilege::Admin}}); console.eval("web3.admin.setSessionKey('" + sessionKey + "')"); while (!g_exit) { diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 0a7277e06..7dd1ed246 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -77,7 +77,7 @@ bool WebThreeStubServer::eth_notePassword(string const& _password) return true; } -#define ADMIN requires(_session, Priviledge::Admin) +#define ADMIN requires(_session, Privilege::Admin) Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _session) { diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 2860f852b..35ea03737 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -40,7 +40,7 @@ class BlockQueue; struct SessionPermissions { - std::unordered_set priviledges; + std::unordered_set privileges; }; /** @@ -59,7 +59,7 @@ public: virtual void setMiningBenefactorChanger(std::function const& _f) { m_setMiningBenefactor = _f; } private: - virtual bool hasPriviledgeLevel(std::string const& _session, Priviledge _l) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.priviledges.count(_l); } + virtual bool hasPrivilegeLevel(std::string const& _session, Privilege _l) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.privileges.count(_l); } virtual dev::eth::Interface* client() override; virtual std::shared_ptr face() override; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index dbcbe03cd..bf0576039 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -510,7 +510,7 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _source) return res; } -#define ADMIN requires(_session, Priviledge::Admin) +#define ADMIN requires(_session, Privilege::Admin) bool WebThreeStubServerBase::admin_web3_setVerbosity(int _v, string const& _session) { diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 62209a5b4..4230f7237 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -59,7 +59,7 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; -enum class Priviledge +enum class Privilege { Admin }; @@ -69,9 +69,9 @@ enum class Priviledge namespace std { -template<> struct hash +template<> struct hash { - size_t operator()(dev::Priviledge _value) const { return (size_t)_value; } + size_t operator()(dev::Privilege _value) const { return (size_t)_value; } }; } @@ -190,8 +190,8 @@ public: std::map const& ids() const { return m_shhIds; } protected: - void requires(std::string const& _session, Priviledge _l) const { if (!hasPriviledgeLevel(_session, _l)) throw jsonrpc::JsonRpcException("Invalid priviledges"); } - virtual bool hasPriviledgeLevel(std::string const& _session, Priviledge _l) const { (void)_session; (void)_l; return false; } + void requires(std::string const& _session, Privilege _l) const { if (!hasPrivilegeLevel(_session, _l)) throw jsonrpc::JsonRpcException("Invalid privileges"); } + virtual bool hasPrivilegeLevel(std::string const& _session, Privilege _l) const { (void)_session; (void)_l; return false; } virtual dev::eth::Interface* client() = 0; virtual std::shared_ptr face() = 0; From 35b84ae7e73b9aa84b73b1ef4fac326a3d014425 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 15:16:27 +0200 Subject: [PATCH 45/53] Use atomic for g_silence. Fixed #2285. --- eth/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 4d3707c10..9a6169b67 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -66,7 +66,7 @@ using namespace dev::eth; using namespace boost::algorithm; using dev::eth::Instruction; -static bool g_silence = false; +static std::atomic g_silence = {false}; void interactiveHelp() { @@ -1560,7 +1560,7 @@ int main(int argc, char** argv) }; auto getPassword = [&](string const& prompt){ - auto s = g_silence; + bool s = g_silence; g_silence = true; cout << endl; string ret = dev::getPassword(prompt); From 1d4eeb3a665f8fb277208b52147a1868bc5412e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Jul 2015 16:02:16 +0200 Subject: [PATCH 46/53] Fix evmjit Windows exports. --- evmjit/include/evmjit/JIT-c.h | 14 +++++++++++--- evmjit/libevmjit/JIT-c.cpp | 6 +++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/evmjit/include/evmjit/JIT-c.h b/evmjit/include/evmjit/JIT-c.h index a92b29090..d7c792451 100644 --- a/evmjit/include/evmjit/JIT-c.h +++ b/evmjit/include/evmjit/JIT-c.h @@ -1,6 +1,14 @@ #include "stdint.h" +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#else +#define EXPORT +#endif + #ifdef __cplusplus extern "C" { #endif @@ -51,11 +59,11 @@ typedef enum evmjit_return_code typedef struct evmjit_context evmjit_context; -evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env); +EXPORT evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env); -evmjit_return_code evmjit_exec(evmjit_context* _context); +EXPORT evmjit_return_code evmjit_exec(evmjit_context* _context); -void evmjit_destroy(evmjit_context* _context); +EXPORT void evmjit_destroy(evmjit_context* _context); inline char const* evmjit_get_output(evmjit_runtime_data* _data) { return _data->callData; } diff --git a/evmjit/libevmjit/JIT-c.cpp b/evmjit/libevmjit/JIT-c.cpp index 2fd578108..7c5cd0b14 100644 --- a/evmjit/libevmjit/JIT-c.cpp +++ b/evmjit/libevmjit/JIT-c.cpp @@ -6,7 +6,7 @@ extern "C" { using namespace dev::evmjit; -EXPORT evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env) +evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env) { auto data = reinterpret_cast(_data); auto env = reinterpret_cast(_env); @@ -20,13 +20,13 @@ EXPORT evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env) return reinterpret_cast(context); } -EXPORT void evmjit_destroy(evmjit_context* _context) +void evmjit_destroy(evmjit_context* _context) { auto context = reinterpret_cast(_context); delete context; } -EXPORT evmjit_return_code evmjit_exec(evmjit_context* _context) +evmjit_return_code evmjit_exec(evmjit_context* _context) { auto context = reinterpret_cast(_context); From 8c6b653790634c2451068682a4534f836264937e Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 28 Jul 2015 16:02:44 +0200 Subject: [PATCH 47/53] clear state on dropping transactions from queue --- libethereum/Client.cpp | 16 ++++++++++++++++ libethereum/Client.h | 4 ++++ libethereum/TransactionQueue.cpp | 6 +++++- libethereum/TransactionQueue.h | 4 ++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 0ffc4dcd7..7a9172a90 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -94,6 +94,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_tqReplaced = m_tq.onReplaced([=](h256 const&){ this->resetState(); }); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); @@ -650,6 +651,21 @@ void Client::resyncStateFromChain() } } +void Client::resetState() +{ + State newPreMine; + DEV_READ_GUARDED(x_preMine) + newPreMine = m_preMine; + + DEV_WRITE_GUARDED(x_working) + m_working = newPreMine; + DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + + onPostStateChanged(); + onTransactionQueueReady(); +} + void Client::onChainChanged(ImportRoute const& _ir) { h256Hash changeds; diff --git a/libethereum/Client.h b/libethereum/Client.h index 630898b20..973270877 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -254,6 +254,9 @@ protected: /// Called after processing blocks by onChainChanged(_ir) void resyncStateFromChain(); + /// Clear working state of transactions + void resetState(); + /// Magically called when the chain has changed. An import route is provided. /// Called by either submitWork() or in our main thread through syncBlockQueue(). void onChainChanged(ImportRoute const& _ir); @@ -307,6 +310,7 @@ protected: std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; + Handler m_tqReplaced; Handler<> m_bqReady; bool m_wouldMine = false; ///< True if we /should/ be mining. diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 5de86c818..aeeb35214 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -147,7 +147,11 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio if (_transaction.gasPrice() < (*t->second).transaction.gasPrice()) return ImportResult::OverbidGasPrice; else - remove_WITH_LOCK((*t->second).transaction.sha3()); + { + h256 dropped = (*t->second).transaction.sha3(); + remove_WITH_LOCK(dropped); + m_onReplaced(dropped); + } } } auto fs = m_future.find(_transaction.from()); diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index f6c140e6f..9c8283aa2 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -117,6 +117,9 @@ public: /// Register a handler that will be called once asynchronous verification is comeplte an transaction has been imported template Handler onImport(T const& _t) { return m_onImport.add(_t); } + /// Register a handler that will be called once asynchronous verification is comeplte an transaction has been imported + template Handler onReplaced(T const& _t) { return m_onReplaced.add(_t); } + private: /// Verified and imported transaction @@ -184,6 +187,7 @@ private: Signal<> m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. Signal m_onImport; ///< Called for each import attempt. Arguments are result, transaction id an node id. Be nice and exit fast. + Signal m_onReplaced; ///< Called whan transction is dropped during a call to import() to make room for another transaction. unsigned m_limit; ///< Max number of pending transactions unsigned m_futureLimit; ///< Max number of future transactions unsigned m_futureSize = 0; ///< Current number of future transactions From a286c5f95aa69561eeb4ef3d0e06321850d8c4ee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 19:54:17 +0200 Subject: [PATCH 48/53] Version bump. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 261e0a6f6..20203b6f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # cmake global cmake_minimum_required(VERSION 2.8.12) -set(PROJECT_VERSION "0.9.34") +set(PROJECT_VERSION "0.9.35") if (${CMAKE_VERSION} VERSION_GREATER 3.0) cmake_policy(SET CMP0048 NEW) # allow VERSION argument in project() project(ethereum VERSION ${PROJECT_VERSION}) From 11abba272be5e663a058991a26cc356b6a365614 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 21:13:48 +0200 Subject: [PATCH 49/53] Target 5000 gas floor for frontier. --- libethcore/BlockInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 60fb13ba9..4729ff25e 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -191,7 +191,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - static const u256 c_gasFloorTarget = 3141592; + u256 const c_gasFloorTarget = c_network == Network::Frontier ? 5000 : 3141592; if (!m_number) throw GenesisBlockCannotBeCalculated(); From 756ca99f6d1fca9eff7667fb5aa61072dd762ca2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 21:54:53 +0200 Subject: [PATCH 50/53] Minor updates to gas limit floor machanism. --- eth/main.cpp | 5 +++++ libethcore/BlockInfo.cpp | 14 +++++++------- libethcore/BlockInfo.h | 3 ++- libethcore/Params.cpp | 3 ++- libethcore/Params.h | 1 + 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 8528b0526..e17a6ebaf 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1105,6 +1105,7 @@ int main(int argc, char** argv) string jsonAdmin; string genesisJSON; dev::eth::Network releaseNetwork = c_network; + u256 gasFloor = UndefinedU256; string privateChain; bool upnp = true; @@ -1347,6 +1348,8 @@ int main(int argc, char** argv) } else if (arg == "--frontier") releaseNetwork = eth::Network::Frontier; + else if (arg == "--gas-floor" && i + 1 < argc) + gasFloor = u256(argv[++i]); else if (arg == "--olympic") releaseNetwork = eth::Network::Olympic; /* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) @@ -1514,6 +1517,8 @@ int main(int argc, char** argv) CanonBlockChain::forceGenesisExtraData(sha3(privateChain).asBytes()); if (!genesisJSON.empty()) CanonBlockChain::setGenesis(genesisJSON); + if (gasFloor != UndefinedU256) + c_gasFloorTarget = gasFloor; if (g_logVerbosity > 0) { diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 4729ff25e..0b1cdd622 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -184,23 +184,23 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) m_stateRoot = _parent.stateRoot(); m_number = _parent.m_number + 1; m_parentHash = _parent.m_hash; - m_gasLimit = selectGasLimit(_parent); + m_gasLimit = _parent.childGasLimit(); m_gasUsed = 0; m_difficulty = calculateDifficulty(_parent); } -u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const +u256 BlockInfo::childGasLimit(u256 const& _gasFloorTarget) const { - u256 const c_gasFloorTarget = c_network == Network::Frontier ? 5000 : 3141592; + u256 gasFloorTarget = + _gasFloorTarget == UndefinedU256 ? c_gasFloorTarget : _gasFloorTarget; if (!m_number) throw GenesisBlockCannotBeCalculated(); else - // target minimum of 3141592 - if (_parent.m_gasLimit < c_gasFloorTarget) - return min(c_gasFloorTarget, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); + if (m_gasLimit < gasFloorTarget) + return min(gasFloorTarget, m_gasLimit + m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_gasFloorTarget, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(gasFloorTarget, m_gasLimit - m_gasLimit / c_gasLimitBoundDivisor + 1 + (m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 8474284a3..c6812a112 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -115,7 +115,7 @@ public: void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; - u256 selectGasLimit(BlockInfo const& _parent) const; + u256 childGasLimit(u256 const& _gasFloorTarget = UndefinedU256) const; h256 const& boundary() const; h256 const& parentHash() const { return m_parentHash; } @@ -127,6 +127,7 @@ public: void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setGasLimit(u256 const& _v) { m_gasLimit = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index 0612db84e..fbf0f6d9e 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -36,6 +36,7 @@ u256 c_minimumDifficulty; u256 c_difficultyBoundDivisor; u256 c_durationLimit; u256 c_blockReward; +u256 c_gasFloorTarget; //--- END: AUTOGENERATED FROM /feeStructure.json #if ETH_FRONTIER @@ -60,7 +61,7 @@ Network resetNetwork(Network _n) c_minGasLimit = 5000; break; } - + c_gasFloorTarget = c_network == Network::Frontier ? 5000 : 3141592; c_gasLimitBoundDivisor = 1024; c_minimumDifficulty = 131072; c_difficultyBoundDivisor = 2048; diff --git a/libethcore/Params.h b/libethcore/Params.h index 6736d4f86..69469612b 100644 --- a/libethcore/Params.h +++ b/libethcore/Params.h @@ -36,6 +36,7 @@ extern u256 c_difficultyBoundDivisor; extern u256 c_durationLimit; extern u256 c_maximumExtraDataSize; extern u256 c_blockReward; +extern u256 c_gasFloorTarget; //--- END: AUTOGENERATED FROM /feeStructure.json } From 23983aaf9755cb1a9bf1a44f6cff1e0cbe93982b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 22:13:24 +0200 Subject: [PATCH 51/53] Fix for gas floor calc. --- libethcore/BlockInfo.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 0b1cdd622..6252497b5 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -194,13 +194,10 @@ u256 BlockInfo::childGasLimit(u256 const& _gasFloorTarget) const u256 gasFloorTarget = _gasFloorTarget == UndefinedU256 ? c_gasFloorTarget : _gasFloorTarget; - if (!m_number) - throw GenesisBlockCannotBeCalculated(); + if (m_gasLimit < gasFloorTarget) + return min(gasFloorTarget, m_gasLimit + m_gasLimit / c_gasLimitBoundDivisor - 1); else - if (m_gasLimit < gasFloorTarget) - return min(gasFloorTarget, m_gasLimit + m_gasLimit / c_gasLimitBoundDivisor - 1); - else - return max(gasFloorTarget, m_gasLimit - m_gasLimit / c_gasLimitBoundDivisor + 1 + (m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(gasFloorTarget, m_gasLimit - m_gasLimit / c_gasLimitBoundDivisor + 1 + (m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const From 2513561a33286254bbff68b203ff32113d86fee4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 23:31:12 +0200 Subject: [PATCH 52/53] Avoid mining invalid blocks. Actually allow external mining. --- libethcore/BlockInfo.cpp | 2 +- libethcore/Ethash.cpp | 9 ++++++++- libethcore/Ethash.h | 2 ++ libethereum/Client.cpp | 1 + libethereum/State.cpp | 6 +++++- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 6252497b5..5cf909959 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -176,7 +176,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); if (m_sha3Uncles != sha3(root[2].data())) - BOOST_THROW_EXCEPTION(InvalidUnclesHash()); + BOOST_THROW_EXCEPTION(InvalidUnclesHash() << Hash256RequirementError(sha3(root[2].data()), m_sha3Uncles)); } void BlockInfo::populateFromParent(BlockInfo const& _parent) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 101fd1611..511146b75 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -177,15 +177,22 @@ StringHashMap Ethash::BlockHeaderRaw::jsInfo() const return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; } - +void Ethash::manuallySetWork(SealEngineFace* _engine, BlockHeader const& _work) +{ + // set m_sealing to the current problem. + if (EthashSealEngine* e = dynamic_cast(_engine)) + e->m_sealing = _work; +} void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) { if (EthashSealEngine* e = dynamic_cast(_engine)) + { // Go via the farm since the handler function object is stored as a local within the Farm's lambda. // Has the side effect of stopping local workers, which is good, as long as it only does it for // valid submissions. static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); + } } bool Ethash::isWorking(SealEngineFace* _engine) diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 0ea80f5e1..a0904fa62 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -99,6 +99,8 @@ public: }; using BlockHeader = BlockHeaderPolished; + static void manuallySetWork(SealEngineFace* _engine, BlockHeader const& _work); + // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); }; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 7a9172a90..2322d1e46 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -924,6 +924,7 @@ std::tuple EthashClient::getEthashWork() // otherwise, set this to true so that it gets prepped next time. m_remoteWorking = true; Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + Ethash::manuallySetWork(m_sealEngine.get(), bh); return std::tuple(bh.hashWithout(), bh.seedHash(), bh.boundary()); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 3127ad1f6..b8c0ce89c 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -906,8 +906,12 @@ bool State::sealBlock(bytesConstRef _header) if (!m_committedToMine) return false; + // Check that this header is indeed for this block. + if (BlockInfo(_header, CheckNothing, h256{}, HeaderData).hashWithout() != m_currentBlock.hashWithout()) + return false; + + // Looks good! clog(StateDetail) << "Sealing block!"; - // Got it! // Compile block: RLPStream ret; From 91050f2b4aa016921d8fb4d4fa055f45372c4910 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 00:33:57 +0200 Subject: [PATCH 53/53] Fix mining. --- eth/main.cpp | 7 +++++-- libethcore/EthashCPUMiner.cpp | 20 +++++++++++++++++++ libethcore/EthashCPUMiner.h | 12 ++++-------- libethcore/Farm.h | 2 -- libweb3jsonrpc/WebThreeStubServer.cpp | 28 +++++++++++++-------------- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index e17a6ebaf..fefac5138 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -291,10 +291,13 @@ enum class Format Human }; -void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining) +void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned& io_mining) { - if (_c->isMining() && _c->blockChain().details().number - _start == _mining) + if (io_mining != ~(unsigned)0 && io_mining && _c->isMining() && _c->blockChain().details().number - _start == io_mining) + { _c->stopMining(); + io_mining = ~(unsigned)0; + } this_thread::sleep_for(chrono::milliseconds(100)); } diff --git a/libethcore/EthashCPUMiner.cpp b/libethcore/EthashCPUMiner.cpp index f14c7b625..0c645c831 100644 --- a/libethcore/EthashCPUMiner.cpp +++ b/libethcore/EthashCPUMiner.cpp @@ -53,6 +53,26 @@ static string jsonEncode(map const& _m) } #endif +EthashCPUMiner::EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): + GenericMiner(_ci), Worker("miner" + toString(index())) +{ +} + +EthashCPUMiner::~EthashCPUMiner() +{ +} + +void EthashCPUMiner::kickOff() +{ + stopWorking(); + startWorking(); +} + +void EthashCPUMiner::pause() +{ + stopWorking(); +} + void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); diff --git a/libethcore/EthashCPUMiner.h b/libethcore/EthashCPUMiner.h index ff3c58df1..ce464b0e2 100644 --- a/libethcore/EthashCPUMiner.h +++ b/libethcore/EthashCPUMiner.h @@ -35,7 +35,8 @@ namespace eth class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci); + ~EthashCPUMiner(); static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -44,13 +45,8 @@ public: static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } - - void pause() override { stopWorking(); } + void kickOff() override; + void pause() override; private: void workLoop() override; diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c86b4804e..146bf1caa 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -67,7 +67,6 @@ public: void setWork(WorkPackage const& _wp) { WriteGuard l(x_minerWork); - cdebug << "Farm::setWork()"; if (_wp.headerHash == m_work.headerHash) return; m_work = _wp; @@ -84,7 +83,6 @@ public: bool start(std::string const& _sealer) { WriteGuard l(x_minerWork); - cdebug << "start()"; if (!m_miners.empty() && m_lastSealer == _sealer) return true; if (!m_sealers.count(_sealer)) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 7dd1ed246..b90c43cf3 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -77,11 +77,11 @@ bool WebThreeStubServer::eth_notePassword(string const& _password) return true; } -#define ADMIN requires(_session, Privilege::Admin) +#define ADMIN_GUARD requires(_session, Privilege::Admin) Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _session) { - ADMIN; + ADMIN_GUARD; Json::Value ret; BlockQueueStatus bqs = m_web3.ethereum()->blockQueue().status(); ret["importing"] = (int)bqs.importing; @@ -96,14 +96,14 @@ Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _sessio bool WebThreeStubServer::admin_eth_setAskPrice(std::string const& _wei, std::string const& _session) { - ADMIN; + ADMIN_GUARD; m_gp.setAsk(jsToU256(_wei)); return true; } bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) { - ADMIN; + ADMIN_GUARD; m_gp.setBid(jsToU256(_wei)); return true; } @@ -120,7 +120,7 @@ dev::eth::BlockQueue const& WebThreeStubServer::bq() const Json::Value WebThreeStubServer::admin_eth_findBlock(std::string const& _blockHash, std::string const& _session) { - ADMIN; + ADMIN_GUARD; h256 h(_blockHash); if (bc().isKnown(h)) return toJson(bc().info(h)); @@ -141,20 +141,20 @@ Json::Value WebThreeStubServer::admin_eth_findBlock(std::string const& _blockHas std::string WebThreeStubServer::admin_eth_blockQueueFirstUnknown(std::string const& _session) { - ADMIN; + ADMIN_GUARD; return bq().firstUnknown().hex(); } bool WebThreeStubServer::admin_eth_blockQueueRetryUnknown(std::string const& _session) { - ADMIN; + ADMIN_GUARD; m_web3.ethereum()->retryUnknown(); return true; } Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _session) { - ADMIN; + ADMIN_GUARD; Json::Value ret; u256 total = 0; u256 pendingtotal = 0; @@ -184,7 +184,7 @@ Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _sessio Json::Value WebThreeStubServer::admin_eth_newAccount(Json::Value const& _info, std::string const& _session) { - ADMIN; + ADMIN_GUARD; if (!_info.isMember("name")) throw jsonrpc::JsonRpcException("No member found: name"); string name = _info["name"].asString(); @@ -206,7 +206,7 @@ Json::Value WebThreeStubServer::admin_eth_newAccount(Json::Value const& _info, s bool WebThreeStubServer::admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) { - ADMIN; + ADMIN_GUARD; Address a; h128 uuid = fromUUID(_uuidOrAddress); if (uuid) @@ -222,7 +222,7 @@ bool WebThreeStubServer::admin_eth_setMiningBenefactor(std::string const& _uuidO Json::Value WebThreeStubServer::admin_eth_inspect(std::string const& _address, std::string const& _session) { - ADMIN; + ADMIN_GUARD; if (!isHash
(_address)) throw jsonrpc::JsonRpcException("Invalid address given."); @@ -251,7 +251,7 @@ h256 WebThreeStubServer::blockHash(std::string const& _blockNumberOrHash) const Json::Value WebThreeStubServer::admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) { - ADMIN; + ADMIN_GUARD; Json::Value ret; PopulationStatistics ps; m_web3.ethereum()->state(blockHash(_blockNumberOrHash), &ps); @@ -263,7 +263,7 @@ Json::Value WebThreeStubServer::admin_eth_reprocess(std::string const& _blockNum Json::Value WebThreeStubServer::admin_eth_vmTrace(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) { - ADMIN; + ADMIN_GUARD; Json::Value ret; @@ -299,7 +299,7 @@ Json::Value WebThreeStubServer::admin_eth_vmTrace(std::string const& _blockNumbe Json::Value WebThreeStubServer::admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) { - ADMIN; + ADMIN_GUARD; if (_txIndex < 0) throw jsonrpc::JsonRpcException("Negative index"); auto h = blockHash(_blockNumberOrHash);