Fabcoin Core  0.16.2
P2P Digital Currency
KeyManager.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include "KeyManager.h"
23 #include <thread>
24 #include <mutex>
25 #include <boost/filesystem.hpp>
27 #include <libdevcore/Log.h>
28 #include <libdevcore/Guards.h>
29 #include <libdevcore/RLP.h>
30 #include <libdevcore/SHA3.h>
31 using namespace std;
32 using namespace dev;
33 using namespace eth;
34 namespace js = json_spirit;
35 namespace fs = boost::filesystem;
36 
37 KeyManager::KeyManager(string const& _keysFile, string const& _secretsPath):
38  m_keysFile(_keysFile), m_store(_secretsPath)
39 {
40  for (auto const& uuid: m_store.keys())
41  {
42  auto addr = m_store.address(uuid);
43  m_addrLookup[addr] = uuid;
44  m_uuidLookup[uuid] = addr;
45  }
46 }
47 
49 {}
50 
51 bool KeyManager::exists() const
52 {
53  return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty();
54 }
55 
56 void KeyManager::create(string const& _pass)
57 {
59  write(_pass, m_keysFile);
60 }
61 
62 bool KeyManager::recode(Address const& _address, string const& _newPass, string const& _hint, function<string()> const& _pass, KDF _kdf)
63 {
64  noteHint(_newPass, _hint);
65  h128 u = uuid(_address);
66  if (!store().recode(u, _newPass, [&](){ return getPassword(u, _pass); }, _kdf))
67  return false;
68 
69  m_keyInfo[_address].passHash = hashPassword(_newPass);
70  write();
71  return true;
72 }
73 
74 bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, function<string()> const& _pass, KDF _kdf)
75 {
76  h128 u = uuid(_address);
77  string p;
78  if (_newPass == SemanticPassword::Existing)
79  p = getPassword(u, _pass);
80  else if (_newPass == SemanticPassword::Master)
81  p = defaultPassword();
82  else
83  return false;
84 
85  return recode(_address, p, string(), _pass, _kdf);
86 }
87 
88 bool KeyManager::load(string const& _pass)
89 {
90  try
91  {
92  bytes salt = contents(m_keysFile + ".salt");
93  bytes encKeys = contents(m_keysFile);
94  if (encKeys.empty())
95  return false;
96  m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
97  bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
98  RLP s(bs.ref());
99  unsigned version = unsigned(s[0]);
100  if (version == 1)
101  {
102  bool saveRequired = false;
103  for (auto const& i: s[1])
104  {
105  h128 uuid(i[1]);
106  Address addr(i[0]);
107  if (uuid)
108  {
109  if (m_store.contains(uuid))
110  {
111  m_addrLookup[addr] = uuid;
112  m_uuidLookup[uuid] = addr;
113  m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
114  if (m_store.noteAddress(uuid, addr))
115  saveRequired = true;
116  }
117  else
118  cwarn << "Missing key:" << uuid << addr;
119  }
120  else
121  {
122  // TODO: brain wallet.
123  m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
124  }
125 // cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3];
126  }
127  if (saveRequired)
128  m_store.save();
129 
130  for (auto const& i: s[2])
131  m_passwordHint[h256(i[0])] = string(i[1]);
132  m_defaultPasswordDeprecated = string(s[3]);
133  }
134 // cdebug << hashPassword(m_password) << toHex(m_password);
136 // cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
138 // cdebug << hashPassword(_pass) << _pass;
139  m_master = hashPassword(_pass);
140  cachePassword(_pass);
141  return true;
142  }
143  catch (...)
144  {
145  return false;
146  }
147 }
148 
149 Secret KeyManager::secret(Address const& _address, function<string()> const& _pass, bool _usePasswordCache) const
150 {
151  if (m_addrLookup.count(_address))
152  return secret(m_addrLookup.at(_address), _pass, _usePasswordCache);
153  else
154  return brain(_pass());
155 }
156 
157 Secret KeyManager::secret(h128 const& _uuid, function<string()> const& _pass, bool _usePasswordCache) const
158 {
159  if (_usePasswordCache)
160  return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }, _usePasswordCache));
161  else
162  return Secret(m_store.secret(_uuid, _pass, _usePasswordCache));
163 }
164 
165 string KeyManager::getPassword(h128 const& _uuid, function<string()> const& _pass) const
166 {
167  h256 ph;
168  auto ait = m_uuidLookup.find(_uuid);
169  if (ait != m_uuidLookup.end())
170  {
171  auto kit = m_keyInfo.find(ait->second);
172  if (kit != m_keyInfo.end())
173  ph = kit->second.passHash;
174  }
175  return getPassword(ph, _pass);
176 }
177 
178 string KeyManager::getPassword(h256 const& _passHash, function<string()> const& _pass) const
179 {
180  auto it = m_cachedPasswords.find(_passHash);
181  if (it != m_cachedPasswords.end())
182  return it->second;
183  for (unsigned i = 0; i < 10; ++i)
184  {
185  string p = _pass();
186  if (p.empty())
187  break;
188  if (_passHash == UnknownPassword || hashPassword(p) == _passHash)
189  {
190  cachePassword(p);
191  return p;
192  }
193  }
194  return string();
195 }
196 
197 h128 KeyManager::uuid(Address const& _a) const
198 {
199  auto it = m_addrLookup.find(_a);
200  if (it == m_addrLookup.end())
201  return h128();
202  return it->second;
203 }
204 
205 Address KeyManager::address(h128 const& _uuid) const
206 {
207  auto it = m_uuidLookup.find(_uuid);
208  if (it == m_uuidLookup.end())
209  return Address();
210  return it->second;
211 }
212 
213 h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint)
214 {
215  Address addr = KeyPair(_s).address();
216  auto passHash = hashPassword(_pass);
217  cachePassword(_pass);
218  m_passwordHint[passHash] = _passwordHint;
219  auto uuid = m_store.importSecret(_s.asBytesSec(), _pass);
220  m_keyInfo[addr] = KeyInfo{passHash, _accountName, ""};
221  m_addrLookup[addr] = uuid;
222  m_uuidLookup[uuid] = addr;
223  write(m_keysFile);
224  return uuid;
225 }
226 
227 Secret KeyManager::brain(string const& _seed)
228 {
229  h256 r = sha3(_seed);
230  for (auto i = 0; i < 16384; ++i)
231  r = sha3(r);
232  Secret ret(r);
233  r.ref().cleanse();
234  while (toAddress(ret)[0])
235  ret = sha3(ret);
236  return ret;
237 }
238 
239 Secret KeyManager::subkey(Secret const& _s, unsigned _index)
240 {
241  RLPStream out(2);
242  out << _s.ref();
243  out << _index;
244  bytesSec r;
245  out.swapOut(r.writable());
246  return sha3(r);
247 }
248 
249 Address KeyManager::importBrain(string const& _seed, string const& _accountName, string const& _passwordHint)
250 {
251  Address addr = toAddress(brain(_seed));
252  m_keyInfo[addr].accountName = _accountName;
253  m_keyInfo[addr].passwordHint = _passwordHint;
254  write();
255  return addr;
256 }
257 
258 void KeyManager::importExistingBrain(Address const& _a, string const& _accountName, string const& _passwordHint)
259 {
260  m_keyInfo[_a].accountName = _accountName;
261  m_keyInfo[_a].passwordHint = _passwordHint;
262  write();
263 }
264 
265 void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
266 {
267  bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });
268  if (key.empty())
269  return;
270  Address a = KeyPair(Secret(key)).address();
271  auto passHash = hashPassword(_pass);
272  if (!m_cachedPasswords.count(passHash))
273  cachePassword(_pass);
274  importExisting(_uuid, _info, a, passHash, _passwordHint);
275 }
276 
277 void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint)
278 {
279  if (!m_passwordHint.count(_passHash))
280  m_passwordHint[_passHash] = _passwordHint;
281  m_uuidLookup[_uuid] = _address;
282  m_addrLookup[_address] = _uuid;
283  m_keyInfo[_address].passHash = _passHash;
284  m_keyInfo[_address].accountName = _accountName;
285  write(m_keysFile);
286 }
287 
288 void KeyManager::kill(Address const& _a)
289 {
290  auto id = m_addrLookup[_a];
291  m_uuidLookup.erase(id);
292  m_addrLookup.erase(_a);
293  m_keyInfo.erase(_a);
294  m_store.kill(id);
295  write(m_keysFile);
296 }
297 
298 KeyPair KeyManager::presaleSecret(std::string const& _json, function<string(bool)> const& _password)
299 {
300  js::mValue val;
301  json_spirit::read_string(_json, val);
302  auto obj = val.get_obj();
303  string p = _password(true);
304  if (obj["encseed"].type() == js::str_type)
305  {
306  auto encseed = fromHex(obj["encseed"].get_str());
307  while (true)
308  {
309  KeyPair k = KeyPair::fromEncryptedSeed(&encseed, p);
310  if (obj["ethaddr"].type() == js::str_type)
311  {
312  Address a(obj["ethaddr"].get_str());
313  Address b = k.address();
314  if (a != b)
315  {
316  if ((p = _password(false)).empty())
317  BOOST_THROW_EXCEPTION(PasswordUnknown());
318  continue;
319  }
320  }
321  return k;
322  }
323  }
324  else
325  BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type"));
326 }
327 
329 {
330  set<Address> addresses;
331  for (auto const& i: m_keyInfo)
332  addresses.insert(i.first);
333  for (auto const& key: m_store.keys())
334  addresses.insert(m_store.address(key));
335  // Remove the zero address if present
336  return Addresses{addresses.upper_bound(Address()), addresses.end()};
337 }
338 
339 bool KeyManager::hasAccount(Address const& _address) const
340 {
341  if (!_address)
342  return false;
343  if (m_keyInfo.count(_address))
344  return true;
345  for (auto const& key: m_store.keys())
346  if (m_store.address(key) == _address)
347  return true;
348  return false;
349 }
350 
351 string const& KeyManager::accountName(Address const& _address) const
352 {
353  try
354  {
355  return m_keyInfo.at(_address).accountName;
356  }
357  catch (...)
358  {
359  return EmptyString;
360  }
361 }
362 
363 void KeyManager::changeName(Address const& _address, std::string const& _name)
364 {
365  auto it = m_keyInfo.find(_address);
366  if (it != m_keyInfo.end())
367  {
368  it->second.accountName = _name;
369  write(m_keysFile);
370  }
371 }
372 
373 string const& KeyManager::passwordHint(Address const& _address) const
374 {
375  try
376  {
377  auto& info = m_keyInfo.at(_address);
378  if (info.passwordHint.size())
379  return info.passwordHint;
380  return m_passwordHint.at(info.passHash);
381  }
382  catch (...)
383  {
384  return EmptyString;
385  }
386 }
387 
388 h256 KeyManager::hashPassword(string const& _pass) const
389 {
390  // TODO SECURITY: store this a bit more securely; Scrypt perhaps?
391  return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure());
392 }
393 
394 void KeyManager::cachePassword(string const& _password) const
395 {
396  m_cachedPasswords[hashPassword(_password)] = _password;
397 }
398 
399 bool KeyManager::write(string const& _keysFile) const
400 {
401  if (!m_keysFileKey)
402  return false;
403  write(m_keysFileKey, _keysFile);
404  return true;
405 }
406 
407 void KeyManager::write(string const& _pass, string const& _keysFile) const
408 {
409  bytes salt = h256::random().asBytes();
410  writeFile(_keysFile + ".salt", salt, true);
411  auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
412 
413  cachePassword(_pass);
414  m_master = hashPassword(_pass);
415  write(key, _keysFile);
416 }
417 
418 void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const
419 {
420  RLPStream s(4);
421  s << 1; // version
422 
423  s.appendList(m_keyInfo.size());
424  for (auto const& info: m_keyInfo)
425  {
426  h128 id = uuid(info.first);
427  auto const& ki = info.second;
428  s.appendList(5) << info.first << id << ki.passHash << ki.accountName << ki.passwordHint;
429  }
430 
431  s.appendList(m_passwordHint.size());
432  for (auto const& i: m_passwordHint)
433  s.appendList(2) << i.first << i.second;
435 
436  writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()), true);
437  m_keysFileKey = _key;
439 }
440 
442 {
443  KeyPair p;
444  bool keepGoing = true;
445  unsigned done = 0;
446  function<void()> f = [&]() {
447  KeyPair lp;
448  while (keepGoing)
449  {
450  done++;
451  if (done % 1000 == 0)
452  cnote << "Tried" << done << "keys";
453  lp = KeyPair::create();
454  auto a = lp.address();
455  if (_type == NewKeyType::NoVanity ||
456  (_type == NewKeyType::DirectICAP && !a[0]) ||
457  (_type == NewKeyType::FirstTwo && a[0] == a[1]) ||
458  (_type == NewKeyType::FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
459  (_type == NewKeyType::FirstThree && a[0] == a[1] && a[1] == a[2]) ||
460  (_type == NewKeyType::FirstFour && a[0] == a[1] && a[1] == a[2] && a[2] == a[3])
461  )
462  break;
463  }
464  if (keepGoing)
465  p = lp;
466  keepGoing = false;
467  };
468 
469  vector<std::thread*> ts;
470  for (unsigned t = 0; t < std::thread::hardware_concurrency() - 1; ++t)
471  ts.push_back(new std::thread(f));
472  f();
473 
474  for (std::thread* t: ts)
475  {
476  t->join();
477  delete t;
478  }
479  return p;
480 }
const Object & get_obj() const
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
Address address(h128 const &_uuid) const
Definition: SecretStore.h:119
static KeyPair presaleSecret(std::string const &_json, std::function< std::string(bool)> const &_password)
Extracts the secret key from the presale wallet.
Definition: KeyManager.cpp:298
bool recode(Address const &_address, SemanticPassword _newPass, std::function< std::string()> const &_pass=DontKnowThrow, KDF _kdf=KDF::Scrypt)
std::string const & accountName(Address const &_address) const
Definition: KeyManager.cpp:351
SecretStore m_store
Definition: KeyManager.h:189
std::string m_keysFile
Definition: KeyManager.h:186
void writeFile(std::string const &_file, bytesConstRef _data, bool _writeDeleteRename=false)
Write the given binary data into the given file, replacing the file if it pre-exists.
Definition: CommonIO.cpp:107
bool hasAccount(Address const &_address) const
Definition: KeyManager.cpp:339
RLPStream & append(unsigned _s)
Append given datum to the byte stream.
Definition: RLP.h:395
bytes const & out() const
Read the byte stream.
Definition: RLP.h:433
h128 uuid(Address const &_a) const
Definition: KeyManager.cpp:197
bytesSec decryptSymNoAuth(SecureFixedHash< 16 > const &_k, h128 const &_iv, bytesConstRef _cipher)
Decrypts payload with specified IV/ctr using AES128-CTR.
Definition: Common.h:129
bytesSec pbkdf2(std::string const &_pass, bytes const &_salt, unsigned _iterations, unsigned _dkLen=32)
Derive key via PBKDF2.
Address importBrain(std::string const &_seed, std::string const &_accountName, std::string const &_seedHint)
Definition: KeyManager.cpp:249
void noteHint(std::string const &_pass, std::string const &_hint)
Definition: KeyManager.h:90
Simple class that represents a "key pair".
Definition: Common.h:150
h256 hashPassword(std::string const &_pass) const
Definition: KeyManager.cpp:388
h160 Address
An Ethereum address: 20 bytes.
Definition: Common.h:62
std::pair< bytes, h128 > encryptSymNoAuth(SecureFixedHash< 16 > const &_k, bytesConstRef _plain)
Encrypts payload with random IV/ctr using AES128-CTR.
Definition: Common.cpp:157
std::vector< h128 > keys() const
Returns the uuids of all stored keys.
Definition: SecretStore.h:93
static KeyPair create()
Create a new, randomly generated object.
Definition: Common.cpp:307
SecureFixedHash< 32 > Secret
Definition: Common.h:35
for(size_t i=trim;i< len;i++) hash[i-trim]
std::hash for asio::adress
Definition: Common.h:323
void cleanse()
Securely overwrite the memory.
Definition: vector_ref.h:74
bool write() const
Definition: KeyManager.h:160
void importExistingBrain(Address const &_a, std::string const &_accountName, std::string const &_seedHint)
Definition: KeyManager.cpp:258
static KeyPair newKeyPair(NewKeyType _type)
Definition: KeyManager.cpp:441
void version()
Definition: main.cpp:53
std::string const & passwordHint(Address const &_address) const
Definition: KeyManager.cpp:373
Secret secret(Address const &_address, std::function< std::string()> const &_pass=DontKnowThrow, bool _usePasswordCache=true) const
h128 import(Secret const &_s, std::string const &_accountName, std::string const &_pass, std::string const &_passwordHint)
#define a(i)
bytesConstRef ref() const
Definition: FixedHash.h:292
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
bool read_string(const String_type &s, Value_type &value)
SemanticPassword
Definition: KeyManager.h:53
Base class for all exceptions.
Definition: Exceptions.h:39
bytesRef ref()
Definition: FixedHash.h:133
bytesSec asBytesSec() const
Definition: FixedHash.h:251
bytesSec secret(h128 const &_uuid, std::function< std::string()> const &_pass, bool _useCache=true) const
void create(std::string const &_pass)
Definition: KeyManager.cpp:56
void kill(h128 const &_id)
Definition: KeyManager.h:133
std::vector< byte > bytes
Definition: Common.h:75
static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const &_password)
Create from an encrypted seed.
Definition: Common.cpp:317
Fixed-size raw-byte array container type, with an API optimised for storing hashes.
Definition: FixedHash.h:47
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
bytes asBytes(std::string const &_b)
Converts a string to a byte array containing the string&#39;s (byte) data.
Definition: CommonData.h:92
FixedHash< 32 > h256
Definition: FixedHash.h:340
#define cwarn
Definition: Log.h:304
std::string getPassword(h128 const &_uuid, std::function< std::string()> const &_pass=DontKnowThrow) const
Address toAddress(std::string const &_s)
Convert the given string into an address.
Definition: Common.cpp:56
std::string m_defaultPasswordDeprecated
Definition: KeyManager.h:184
void cachePassword(std::string const &_password) const
Stores the password by its hash in the password cache.
Definition: KeyManager.cpp:394
h128 importSecret(bytesSec const &_s, std::string const &_pass)
Imports the decrypted key given by _s and stores it, encrypted with (a key derived from) the password...
h160s Addresses
A vector of Ethereum addresses.
Definition: Common.h:68
#define b(i, j)
std::vector< T > & writable()
Definition: Common.h:101
Address const & address() const
Retrieve the associated address of the public key.
Definition: Common.h:173
static FixedHash random()
Definition: FixedHash.h:162
bytes asBytes() const
Definition: FixedHash.h:145
#define f(x)
Definition: gost.cpp:57
void importExisting(h128 const &_uuid, std::string const &_accountName, std::string const &_pass, std::string const &_passwordHint)
Address address(h128 const &_uuid) const
Definition: KeyManager.cpp:205
FixedHash< 16 > h128
Definition: FixedHash.h:342
#define cnote
Definition: Log.h:303
PlatformStyle::TableColorType type
Definition: rpcconsole.cpp:61
std::unordered_map< h256, std::string > m_passwordHint
Mapping password hash -> password hint.
Definition: KeyManager.h:174
bool load(std::string const &_pass)
Definition: KeyManager.cpp:88
void save(std::string const &_keysPath)
Store all keys in the directory _keysPath.
SecureFixedHash< 16 > m_keysFileKey
Definition: KeyManager.h:187
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:78
bool contains(h128 const &_k) const
Definition: SecretStore.h:96
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
std::unordered_map< Address, KeyInfo > m_keyInfo
Mapping address -> key info.
Definition: KeyManager.h:172
void kill(h128 const &_uuid)
Removes the key specified by _uuid from both memory and disk.
bool exists() const
Definition: KeyManager.cpp:51
std::unordered_map< h256, std::string > m_cachedPasswords
Definition: KeyManager.h:177
void swapOut(bytes &_dest)
Swap the contents of the output stream out for some other byte array.
Definition: RLP.h:439
std::unordered_map< Address, h128 > m_addrLookup
Mapping address -> key uuid.
Definition: KeyManager.h:170
Addresses accounts() const
Definition: KeyManager.cpp:328
static Secret brain(std::string const &_seed)
Definition: KeyManager.cpp:227
std::string get_str(std::string::const_iterator begin, std::string::const_iterator end)
Class for writing to an RLP bytestream.
Definition: RLP.h:383
bytes contents(std::string const &_file)
Retrieve and returns the contents of the given file.
SecretStore & store()
Definition: KeyManager.h:118
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
std::string asString(bytes const &_b)
Converts byte array to a string containing the same (binary) data.
Definition: CommonData.h:79
void changeName(Address const &_address, std::string const &_name)
Should be called to change password.
Definition: KeyManager.cpp:363
static Secret subkey(Secret const &_s, unsigned _index)
Definition: KeyManager.cpp:239
bool noteAddress(h128 const &_uuid, Address const &_address)
std::string defaultPassword(std::function< std::string()> const &_pass=DontKnowThrow) const
Definition: KeyManager.h:152
std::unordered_map< h128, Address > m_uuidLookup
Mapping key uuid -> address.
Definition: KeyManager.h:168
bool empty() const
Definition: Common.h:110