1 // Aleth: Ethereum C++ client, tools and libraries. 2 // Copyright 2015-2019 Aleth Authors. 3 // Licensed under the GNU General Public License, Version 3. 4 5 6 #pragma once 7 8 #include <functional> 9 #include <mutex> 10 #include <libdevcore/FileSystem.h> 11 #include <libdevcore/CommonData.h> 12 #include <libdevcrypto/SecretStore.h> 13 14 #include <boost/filesystem.hpp> 15 16 namespace dev 17 { 18 namespace eth 19 { 20 class PasswordUnknown: public Exception {}; 21 22 struct KeyInfo 23 { 24 KeyInfo() = default; passHashKeyInfo25 KeyInfo(h256 const& _passHash, std::string const& _accountName, std::string const& _passwordHint = std::string()): passHash(_passHash), accountName(_accountName), passwordHint(_passwordHint) {} 26 27 /// Hash of the password or h256() / UnknownPassword if unknown. 28 h256 passHash; 29 /// Name of the key, or JSON key info if begins with '{'. 30 std::string accountName; 31 /// Hint of the password. Alternative place for storage than the hash-based lookup. 32 std::string passwordHint; 33 }; 34 35 static h256 const UnknownPassword; 36 /// Password query function that never returns a password. 37 static auto const DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); }; 38 39 enum class SemanticPassword 40 { 41 Existing, 42 Master 43 }; 44 45 // TODO: This one is specifically for Ethereum, but we can make it generic in due course. 46 // TODO: hidden-partition style key-store. 47 /** 48 * @brief High-level manager of password-encrypted keys for Ethereum. 49 * Usage: 50 * 51 * Call exists() to check whether there is already a database. If so, get the master password from 52 * the user and call load() with it. If not, get a new master password from the user (get them to type 53 * it twice and keep some hint around!) and call create() with it. 54 * 55 * Uses a "key file" (and a corresponding .salt file) that contains encrypted information about the keys and 56 * a directory called "secrets path" that contains a file for each key. 57 */ 58 class KeyManager 59 { 60 public: 61 enum class NewKeyType { DirectICAP = 0, NoVanity, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour }; 62 63 KeyManager(boost::filesystem::path const& _keysFile = defaultPath(), boost::filesystem::path const& _secretsPath = SecretStore::defaultPath()); 64 ~KeyManager(); 65 setKeysFile(boost::filesystem::path const & _keysFile)66 void setKeysFile(boost::filesystem::path const& _keysFile) { m_keysFile = _keysFile; } keysFile()67 boost::filesystem::path const& keysFile() const { return m_keysFile; } 68 69 bool exists() const; 70 void create(std::string const& _pass); 71 bool load(std::string const& _pass); save(std::string const & _pass)72 void save(std::string const& _pass) const { write(_pass, m_keysFile); } 73 notePassword(std::string const & _pass)74 void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; } noteHint(std::string const & _pass,std::string const & _hint)75 void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordHint[hashPassword(_pass)] = _hint; } haveHint(std::string const & _pass)76 bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); } 77 78 /// @returns the list of account addresses. 79 Addresses accounts() const; 80 /// @returns a hashset of all account addresses. accountsHash()81 AddressHash accountsHash() const { return AddressHash() + accounts(); } 82 bool hasAccount(Address const& _address) const; 83 /// @returns the human-readable name or json-encoded info of the account for the given address. 84 std::string const& accountName(Address const& _address) const; 85 /// @returns the password hint for the account for the given address; 86 std::string const& passwordHint(Address const& _address) const; 87 88 /// @returns the uuid of the key for the address @a _a or the empty hash on error. 89 h128 uuid(Address const& _a) const; 90 /// @returns the address corresponding to the key with uuid @a _uuid or the zero address on error. 91 Address address(h128 const& _uuid) const; 92 93 h128 import(Secret const& _s, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint); import(Secret const & _s,std::string const & _accountName)94 h128 import(Secret const& _s, std::string const& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); } 95 store()96 SecretStore& store() { return m_store; } 97 void importExisting(h128 const& _uuid, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint); 98 void importExisting(h128 const& _uuid, std::string const& _accountName, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passwordHint = std::string()); 99 100 /// @returns the secret key associated with an address provided the password query 101 /// function @a _pass or the zero-secret key on error. 102 Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow, bool _usePasswordCache = true) const; 103 /// @returns the secret key associated with the uuid of a key provided the password query 104 /// function @a _pass or the zero-secret key on error. 105 Secret secret(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow, bool _usePasswordCache = true) const; 106 107 bool recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function<std::string()> const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); 108 kill(h128 const & _id)109 void kill(h128 const& _id) { kill(address(_id)); } 110 void kill(Address const& _a); 111 defaultPath()112 static boost::filesystem::path defaultPath() { return getDataDir("ethereum") / boost::filesystem::path("keys.info"); } 113 114 /// Extracts the secret key from the presale wallet. 115 static KeyPair presaleSecret(std::string const& _json, std::function<std::string(bool)> const& _password); 116 117 /// @returns new random keypair with given vanity 118 static KeyPair newKeyPair(NewKeyType _type); 119 private: 120 std::string getPassword(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow) const; 121 std::string getPassword(h256 const& _passHash, std::function<std::string()> const& _pass = DontKnowThrow) const; 122 std::string defaultPassword(std::function<std::string()> const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); } 123 h256 hashPassword(std::string const& _pass) const; 124 125 /// Stores the password by its hash in the password cache. 126 void cachePassword(std::string const& _password) const; 127 128 // Only use if previously loaded ok. 129 // @returns false if wasn't previously loaded ok. write()130 bool write() const { return write(m_keysFile); } 131 bool write(boost::filesystem::path const& _keysFile) const; 132 void write(std::string const& _pass, boost::filesystem::path const& _keysFile) const; // TODO: all passwords should be a secure string. 133 void write(SecureFixedHash<16> const& _key, boost::filesystem::path const& _keysFile) const; 134 135 // Ethereum keys. 136 137 /// Mapping key uuid -> address. 138 std::unordered_map<h128, Address> m_uuidLookup; 139 /// Mapping address -> key uuid. 140 std::unordered_map<Address, h128> m_addrLookup; 141 /// Mapping address -> key info. 142 std::unordered_map<Address, KeyInfo> m_keyInfo; 143 /// Mapping password hash -> password hint. 144 std::unordered_map<h256, std::string> m_passwordHint; 145 146 // Passwords that we're storing. Mapping password hash -> password. 147 mutable std::unordered_map<h256, std::string> m_cachedPasswords; 148 149 // DEPRECATED. 150 // Used to be the default password for keys in the keystore, stored in the keys file. 151 // Now the default password is based off the key of the keys file directly, so this is redundant 152 // except for the fact that people have existing keys stored with it. Leave for now until/unless 153 // we have an upgrade strategy. 154 std::string m_defaultPasswordDeprecated; 155 156 mutable boost::filesystem::path m_keysFile; 157 mutable SecureFixedHash<16> m_keysFileKey; 158 mutable h256 m_master; 159 SecretStore m_store; 160 }; 161 162 } 163 } 164