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 #pragma once 6 7 #include <functional> 8 #include <mutex> 9 #include <libdevcore/FixedHash.h> 10 #include <libdevcore/FileSystem.h> 11 #include "Common.h" 12 13 #include <boost/filesystem.hpp> 14 15 namespace dev 16 { 17 18 enum class KDF { 19 PBKDF2_SHA256, 20 Scrypt, 21 }; 22 23 /** 24 * Manages encrypted keys stored in a certain directory on disk. The keys are read into memory 25 * and changes to the keys are automatically synced to the directory. 26 * Each file stores exactly one key in a specific JSON format whose file name is derived from the 27 * UUID of the key. 28 * @note that most of the functions here affect the filesystem and throw exceptions on failure, 29 * and they also throw exceptions upon rare malfunction in the cryptographic functions. 30 */ 31 class SecretStore 32 { 33 public: 34 struct EncryptedKey 35 { 36 std::string encryptedKey; 37 boost::filesystem::path filename; 38 Address address; 39 }; 40 41 /// Construct a new SecretStore but don't read any keys yet. 42 /// Call setPath in 43 SecretStore() = default; 44 45 /// Construct a new SecretStore and read all keys in the given directory. 46 SecretStore(boost::filesystem::path const& _path); 47 48 /// Set a path for finding secrets. 49 void setPath(boost::filesystem::path const& _path); 50 51 /// @returns the secret key stored by the given @a _uuid. 52 /// @param _pass function that returns the password for the key. 53 /// @param _useCache if true, allow previously decrypted keys to be returned directly. 54 bytesSec secret(h128 const& _uuid, std::function<std::string()> const& _pass, bool _useCache = true) const; 55 /// @returns the secret key stored by the given @a _uuid. 56 /// @param _pass function that returns the password for the key. 57 static bytesSec secret(std::string const& _content, std::string const& _pass); 58 /// @returns the secret key stored by the given @a _address. 59 /// @param _pass function that returns the password for the key. 60 bytesSec secret(Address const& _address, std::function<std::string()> const& _pass) const; 61 /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. importKey(std::string const & _file)62 h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } 63 /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in 64 /// the managed directory. importKeyContent(std::string const & _content)65 h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } 66 /// Imports the decrypted key given by @a _s and stores it, encrypted with 67 /// (a key derived from) the password @a _pass. 68 h128 importSecret(bytesSec const& _s, std::string const& _pass); 69 h128 importSecret(bytesConstRef _s, std::string const& _pass); 70 /// Decrypts and re-encrypts the key identified by @a _uuid. 71 bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt); 72 /// Decrypts and re-encrypts the key identified by @a _address. 73 bool recode(Address const& _address, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt); 74 /// Removes the key specified by @a _uuid from both memory and disk. 75 void kill(h128 const& _uuid); 76 77 /// Returns the uuids of all stored keys. keys()78 std::vector<h128> keys() const { return keysOf(m_keys); } 79 80 /// @returns true iff we have the given key stored. contains(h128 const & _k)81 bool contains(h128 const& _k) const { return m_keys.count(_k); } 82 83 /// Clears all cached decrypted keys. The passwords have to be supplied in order to retrieve 84 /// secrets again after calling this function. 85 void clearCache() const; 86 87 /// Import the key from the file @a _file, but do not copy it to the managed directory yet. 88 /// @param _takeFileOwnership if true, deletes the file if it is not the canonical file for the 89 /// key (derived from its uuid). 90 h128 readKey(boost::filesystem::path const& _file, bool _takeFileOwnership); 91 /// Import the key contained in the json-encoded @a _content, but do not store it in the 92 /// managed directory. 93 /// @param _file if given, assume this file contains @a _content and delete it later, if it is 94 /// not the canonical file for the key (derived from the uuid). 95 h128 readKeyContent(std::string const& _content, boost::filesystem::path const& _file = boost::filesystem::path()); 96 97 /// Store all keys in the directory @a _keysPath. 98 void save(boost::filesystem::path const& _keysPath); 99 /// Store all keys in the managed directory. save()100 void save() { save(m_path); } 101 /// @returns true if the current file @arg _uuid contains an empty address. m_keys will be updated with the given @arg _address. 102 bool noteAddress(h128 const& _uuid, Address const& _address); 103 /// @returns the address of the given key or the zero address if it is unknown. address(h128 const & _uuid)104 Address address(h128 const& _uuid) const { return m_keys.at(_uuid).address; } 105 106 /// @returns the default path for the managed directory. defaultPath()107 static boost::filesystem::path defaultPath() { return getDataDir("web3") / boost::filesystem::path("keys"); } 108 109 private: 110 /// Loads all keys in the given directory. 111 void load(boost::filesystem::path const& _keysPath); load()112 void load() { load(m_path); } 113 /// Encrypts @a _v with a key derived from @a _pass or the empty string on error. 114 static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); 115 /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. 116 static bytesSec decrypt(std::string const& _v, std::string const& _pass); 117 /// @returns the key given the @a _address. 118 std::pair<h128 const, EncryptedKey> const* key(Address const& _address) const; 119 std::pair<h128 const, EncryptedKey>* key(Address const& _address); 120 /// Stores decrypted keys by uuid. 121 mutable std::unordered_map<h128, bytesSec> m_cached; 122 /// Stores encrypted keys together with the file they were loaded from by uuid. 123 std::unordered_map<h128, EncryptedKey> m_keys; 124 125 boost::filesystem::path m_path; 126 }; 127 128 } 129 130