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