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 #include "KeyManager.h"
7 #include <thread>
8 #include <mutex>
9 #include <boost/filesystem.hpp>
10 #include <json_spirit/JsonSpiritHeaders.h>
11 #include <libdevcore/Log.h>
12 #include <libdevcore/Guards.h>
13 #include <libdevcore/RLP.h>
14 #include <libdevcore/SHA3.h>
15 using namespace std;
16 using namespace dev;
17 using namespace eth;
18 namespace js = json_spirit;
19 namespace fs = boost::filesystem;
20
KeyManager(fs::path const & _keysFile,fs::path const & _secretsPath)21 KeyManager::KeyManager(fs::path const& _keysFile, fs::path const& _secretsPath):
22 m_keysFile(_keysFile), m_store(_secretsPath)
23 {
24 for (auto const& uuid: m_store.keys())
25 {
26 auto addr = m_store.address(uuid);
27 m_addrLookup[addr] = uuid;
28 m_uuidLookup[uuid] = addr;
29 }
30 }
31
~KeyManager()32 KeyManager::~KeyManager()
33 {}
34
exists() const35 bool KeyManager::exists() const
36 {
37 return !contents(appendToFilename(m_keysFile, ".salt")).empty() && !contents(m_keysFile).empty();
38 }
39
create(string const & _pass)40 void KeyManager::create(string const& _pass)
41 {
42 m_defaultPasswordDeprecated = asString(h256::random().asBytes());
43 write(_pass, m_keysFile);
44 }
45
recode(Address const & _address,string const & _newPass,string const & _hint,function<string ()> const & _pass,KDF _kdf)46 bool KeyManager::recode(Address const& _address, string const& _newPass, string const& _hint, function<string()> const& _pass, KDF _kdf)
47 {
48 noteHint(_newPass, _hint);
49 h128 u = uuid(_address);
50 if (!store().recode(u, _newPass, [&](){ return getPassword(u, _pass); }, _kdf))
51 return false;
52
53 m_keyInfo[_address].passHash = hashPassword(_newPass);
54 write();
55 return true;
56 }
57
load(string const & _pass)58 bool KeyManager::load(string const& _pass)
59 {
60 try
61 {
62 bytes salt = contents(appendToFilename(m_keysFile, ".salt"));
63 bytes encKeys = contents(m_keysFile);
64 if (encKeys.empty())
65 return false;
66 m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
67 bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
68 RLP s(bs.ref());
69 unsigned version = unsigned(s[0]);
70 if (version == 1)
71 {
72 bool saveRequired = false;
73 for (auto const& i: s[1])
74 {
75 h128 uuid(i[1]);
76 Address addr(i[0]);
77 if (uuid)
78 {
79 if (m_store.contains(uuid))
80 {
81 m_addrLookup[addr] = uuid;
82 m_uuidLookup[uuid] = addr;
83 m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
84 if (m_store.noteAddress(uuid, addr))
85 saveRequired = true;
86 }
87 else
88 cwarn << "Missing key:" << uuid << addr;
89 }
90 else
91 m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
92 // cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3];
93 }
94 if (saveRequired)
95 m_store.save();
96
97 for (auto const& i: s[2])
98 m_passwordHint[h256(i[0])] = string(i[1]);
99 m_defaultPasswordDeprecated = string(s[3]);
100 }
101 // cdebug << hashPassword(m_password) << toHex(m_password);
102 cachePassword(m_defaultPasswordDeprecated);
103 // cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
104 cachePassword(asString(m_keysFileKey.ref()));
105 // cdebug << hashPassword(_pass) << _pass;
106 m_master = hashPassword(_pass);
107 cachePassword(_pass);
108 return true;
109 }
110 catch (...)
111 {
112 return false;
113 }
114 }
115
secret(Address const & _address,function<string ()> const & _pass,bool _usePasswordCache) const116 Secret KeyManager::secret(Address const& _address, function<string()> const& _pass, bool _usePasswordCache) const
117 {
118 return secret(m_addrLookup.at(_address), _pass, _usePasswordCache);
119 }
120
secret(h128 const & _uuid,function<string ()> const & _pass,bool _usePasswordCache) const121 Secret KeyManager::secret(h128 const& _uuid, function<string()> const& _pass, bool _usePasswordCache) const
122 {
123 if (_usePasswordCache)
124 return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }, _usePasswordCache));
125 else
126 return Secret(m_store.secret(_uuid, _pass, _usePasswordCache));
127 }
128
getPassword(h128 const & _uuid,function<string ()> const & _pass) const129 string KeyManager::getPassword(h128 const& _uuid, function<string()> const& _pass) const
130 {
131 h256 ph;
132 auto ait = m_uuidLookup.find(_uuid);
133 if (ait != m_uuidLookup.end())
134 {
135 auto kit = m_keyInfo.find(ait->second);
136 if (kit != m_keyInfo.end())
137 ph = kit->second.passHash;
138 }
139 return getPassword(ph, _pass);
140 }
141
getPassword(h256 const & _passHash,function<string ()> const & _pass) const142 string KeyManager::getPassword(h256 const& _passHash, function<string()> const& _pass) const
143 {
144 auto it = m_cachedPasswords.find(_passHash);
145 if (it != m_cachedPasswords.end())
146 return it->second;
147 for (unsigned i = 0; i < 10; ++i)
148 {
149 string p = _pass();
150 if (p.empty())
151 break;
152 if (_passHash == UnknownPassword || hashPassword(p) == _passHash)
153 {
154 cachePassword(p);
155 return p;
156 }
157 }
158 return string();
159 }
160
uuid(Address const & _a) const161 h128 KeyManager::uuid(Address const& _a) const
162 {
163 auto it = m_addrLookup.find(_a);
164 if (it == m_addrLookup.end())
165 return h128();
166 return it->second;
167 }
168
address(h128 const & _uuid) const169 Address KeyManager::address(h128 const& _uuid) const
170 {
171 auto it = m_uuidLookup.find(_uuid);
172 if (it == m_uuidLookup.end())
173 return Address();
174 return it->second;
175 }
176
import(Secret const & _s,string const & _accountName,string const & _pass,string const & _passwordHint)177 h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint)
178 {
179 Address addr = KeyPair(_s).address();
180 auto passHash = hashPassword(_pass);
181 cachePassword(_pass);
182 m_passwordHint[passHash] = _passwordHint;
183 auto uuid = m_store.importSecret(_s.asBytesSec(), _pass);
184 m_keyInfo[addr] = KeyInfo{passHash, _accountName, ""};
185 m_addrLookup[addr] = uuid;
186 m_uuidLookup[uuid] = addr;
187 write(m_keysFile);
188 return uuid;
189 }
190
importExisting(h128 const & _uuid,string const & _info,string const & _pass,string const & _passwordHint)191 void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
192 {
193 bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });
194 if (key.empty())
195 return;
196 Address a = KeyPair(Secret(key)).address();
197 auto passHash = hashPassword(_pass);
198 if (!m_cachedPasswords.count(passHash))
199 cachePassword(_pass);
200 importExisting(_uuid, _info, a, passHash, _passwordHint);
201 }
202
importExisting(h128 const & _uuid,string const & _accountName,Address const & _address,h256 const & _passHash,string const & _passwordHint)203 void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint)
204 {
205 if (!m_passwordHint.count(_passHash))
206 m_passwordHint[_passHash] = _passwordHint;
207 m_uuidLookup[_uuid] = _address;
208 m_addrLookup[_address] = _uuid;
209 m_keyInfo[_address].passHash = _passHash;
210 m_keyInfo[_address].accountName = _accountName;
211 write(m_keysFile);
212 }
213
kill(Address const & _a)214 void KeyManager::kill(Address const& _a)
215 {
216 auto id = m_addrLookup[_a];
217 m_uuidLookup.erase(id);
218 m_addrLookup.erase(_a);
219 m_keyInfo.erase(_a);
220 m_store.kill(id);
221 write(m_keysFile);
222 }
223
presaleSecret(std::string const & _json,function<string (bool)> const & _password)224 KeyPair KeyManager::presaleSecret(std::string const& _json, function<string(bool)> const& _password)
225 {
226 js::mValue val;
227 json_spirit::read_string(_json, val);
228 auto obj = val.get_obj();
229 string p = _password(true);
230 if (obj["encseed"].type() == js::str_type)
231 {
232 auto encseed = fromHex(obj["encseed"].get_str());
233 while (true)
234 {
235 KeyPair k = KeyPair::fromEncryptedSeed(&encseed, p);
236 if (obj["ethaddr"].type() == js::str_type)
237 {
238 Address a(obj["ethaddr"].get_str());
239 Address b = k.address();
240 if (a != b)
241 {
242 if ((p = _password(false)).empty())
243 BOOST_THROW_EXCEPTION(PasswordUnknown());
244 continue;
245 }
246 }
247 return k;
248 }
249 }
250 else
251 BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type"));
252 }
253
accounts() const254 Addresses KeyManager::accounts() const
255 {
256 set<Address> addresses;
257 for (auto const& i: m_keyInfo)
258 addresses.insert(i.first);
259 for (auto const& key: m_store.keys())
260 addresses.insert(m_store.address(key));
261 // Remove the zero address if present
262 return Addresses{addresses.upper_bound(Address()), addresses.end()};
263 }
264
hasAccount(Address const & _address) const265 bool KeyManager::hasAccount(Address const& _address) const
266 {
267 if (!_address)
268 return false;
269 if (m_keyInfo.count(_address))
270 return true;
271 for (auto const& key: m_store.keys())
272 if (m_store.address(key) == _address)
273 return true;
274 return false;
275 }
276
accountName(Address const & _address) const277 string const& KeyManager::accountName(Address const& _address) const
278 {
279 try
280 {
281 return m_keyInfo.at(_address).accountName;
282 }
283 catch (...)
284 {
285 return EmptyString;
286 }
287 }
288
passwordHint(Address const & _address) const289 string const& KeyManager::passwordHint(Address const& _address) const
290 {
291 try
292 {
293 auto& info = m_keyInfo.at(_address);
294 if (info.passwordHint.size())
295 return info.passwordHint;
296 return m_passwordHint.at(info.passHash);
297 }
298 catch (...)
299 {
300 return EmptyString;
301 }
302 }
303
hashPassword(string const & _pass) const304 h256 KeyManager::hashPassword(string const& _pass) const
305 {
306 // TODO SECURITY: store this a bit more securely; Scrypt perhaps?
307 return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure());
308 }
309
cachePassword(string const & _password) const310 void KeyManager::cachePassword(string const& _password) const
311 {
312 m_cachedPasswords[hashPassword(_password)] = _password;
313 }
314
write(fs::path const & _keysFile) const315 bool KeyManager::write(fs::path const& _keysFile) const
316 {
317 if (!m_keysFileKey)
318 return false;
319 write(m_keysFileKey, _keysFile);
320 return true;
321 }
322
write(string const & _pass,fs::path const & _keysFile) const323 void KeyManager::write(string const& _pass, fs::path const& _keysFile) const
324 {
325 bytes salt = h256::random().asBytes();
326 writeFile(appendToFilename(_keysFile, ".salt"), salt, true);
327 auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
328
329 cachePassword(_pass);
330 m_master = hashPassword(_pass);
331 write(key, _keysFile);
332 }
333
write(SecureFixedHash<16> const & _key,fs::path const & _keysFile) const334 void KeyManager::write(SecureFixedHash<16> const& _key, fs::path const& _keysFile) const
335 {
336 RLPStream s(4);
337 s << 1; // version
338
339 s.appendList(m_keyInfo.size());
340 for (auto const& info: m_keyInfo)
341 {
342 h128 id = uuid(info.first);
343 auto const& ki = info.second;
344 s.appendList(5) << info.first << id << ki.passHash << ki.accountName << ki.passwordHint;
345 }
346
347 s.appendList(m_passwordHint.size());
348 for (auto const& i: m_passwordHint)
349 s.appendList(2) << i.first << i.second;
350 s.append(m_defaultPasswordDeprecated);
351
352 writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()), true);
353 m_keysFileKey = _key;
354 cachePassword(defaultPassword());
355 }
356
newKeyPair(KeyManager::NewKeyType _type)357 KeyPair KeyManager::newKeyPair(KeyManager::NewKeyType _type)
358 {
359 KeyPair p = KeyPair::create();
360 bool keepGoing = true;
361 unsigned done = 0;
362 auto f = [&]() {
363 KeyPair lp = KeyPair::create();
364 while (keepGoing)
365 {
366 done++;
367 if (done % 1000 == 0)
368 cnote << "Tried" << done << "keys";
369 lp = KeyPair::create();
370 auto a = lp.address();
371 if (_type == NewKeyType::NoVanity ||
372 (_type == NewKeyType::DirectICAP && !a[0]) ||
373 (_type == NewKeyType::FirstTwo && a[0] == a[1]) ||
374 (_type == NewKeyType::FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
375 (_type == NewKeyType::FirstThree && a[0] == a[1] && a[1] == a[2]) ||
376 (_type == NewKeyType::FirstFour && a[0] == a[1] && a[1] == a[2] && a[2] == a[3])
377 )
378 break;
379 }
380 if (keepGoing)
381 p = lp;
382 keepGoing = false;
383 };
384
385 vector<std::thread*> ts;
386 for (unsigned t = 0; t < std::thread::hardware_concurrency() - 1; ++t)
387 ts.push_back(new std::thread(f));
388 f();
389
390 for (std::thread* t: ts)
391 {
392 t->join();
393 delete t;
394 }
395 return p;
396 }
397