From 49a826397b1411dcbb433bcf5a9f21c67538b98c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 01/22] 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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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 07/22] 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 08/22] 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 09/22] 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 10/22] 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 11/22] 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 2f1986185859e81e6085f783f1ae17dbf8b9f098 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 12/22] 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 2a7c56aef796964bedb27ac7fff1e212b4a98c91 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 13/22] 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 14/22] 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 15/22] 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 16/22] 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 17/22] 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 18/22] 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 19/22] 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 20/22] 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 21/22] 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 22/22] 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()