Ethereum  PoC-8
The C++ Implementation of Ethereum
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(fs::path const& _keysFile, fs::path 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(appendToFilename(m_keysFile, ".salt")).empty() && !contents(m_keysFile).empty();
54 }
55 
56 void KeyManager::create(string const& _pass)
57 {
58  m_defaultPasswordDeprecated = asString(h256::random().asBytes());
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::load(string const& _pass)
75 {
76  try
77  {
78  bytes salt = contents(appendToFilename(m_keysFile, ".salt"));
79  bytes encKeys = contents(m_keysFile);
80  if (encKeys.empty())
81  return false;
82  m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
83  bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
84  RLP s(bs.ref());
85  unsigned version = unsigned(s[0]);
86  if (version == 1)
87  {
88  bool saveRequired = false;
89  for (auto const& i: s[1])
90  {
91  h128 uuid(i[1]);
92  Address addr(i[0]);
93  if (uuid)
94  {
95  if (m_store.contains(uuid))
96  {
97  m_addrLookup[addr] = uuid;
98  m_uuidLookup[uuid] = addr;
99  m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
100  if (m_store.noteAddress(uuid, addr))
101  saveRequired = true;
102  }
103  else
104  cwarn << "Missing key:" << uuid << addr;
105  }
106  else
107  m_keyInfo[addr] = KeyInfo(h256(i[2]), string(i[3]), i.itemCount() > 4 ? string(i[4]) : "");
108 // cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3];
109  }
110  if (saveRequired)
111  m_store.save();
112 
113  for (auto const& i: s[2])
114  m_passwordHint[h256(i[0])] = string(i[1]);
115  m_defaultPasswordDeprecated = string(s[3]);
116  }
117 // cdebug << hashPassword(m_password) << toHex(m_password);
118  cachePassword(m_defaultPasswordDeprecated);
119 // cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
120  cachePassword(asString(m_keysFileKey.ref()));
121 // cdebug << hashPassword(_pass) << _pass;
122  m_master = hashPassword(_pass);
123  cachePassword(_pass);
124  return true;
125  }
126  catch (...)
127  {
128  return false;
129  }
130 }
131 
132 Secret KeyManager::secret(Address const& _address, function<string()> const& _pass, bool _usePasswordCache) const
133 {
134  return secret(m_addrLookup.at(_address), _pass, _usePasswordCache);
135 }
136 
137 Secret KeyManager::secret(h128 const& _uuid, function<string()> const& _pass, bool _usePasswordCache) const
138 {
139  if (_usePasswordCache)
140  return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }, _usePasswordCache));
141  else
142  return Secret(m_store.secret(_uuid, _pass, _usePasswordCache));
143 }
144 
145 string KeyManager::getPassword(h128 const& _uuid, function<string()> const& _pass) const
146 {
147  h256 ph;
148  auto ait = m_uuidLookup.find(_uuid);
149  if (ait != m_uuidLookup.end())
150  {
151  auto kit = m_keyInfo.find(ait->second);
152  if (kit != m_keyInfo.end())
153  ph = kit->second.passHash;
154  }
155  return getPassword(ph, _pass);
156 }
157 
158 string KeyManager::getPassword(h256 const& _passHash, function<string()> const& _pass) const
159 {
160  auto it = m_cachedPasswords.find(_passHash);
161  if (it != m_cachedPasswords.end())
162  return it->second;
163  for (unsigned i = 0; i < 10; ++i)
164  {
165  string p = _pass();
166  if (p.empty())
167  break;
168  if (_passHash == UnknownPassword || hashPassword(p) == _passHash)
169  {
170  cachePassword(p);
171  return p;
172  }
173  }
174  return string();
175 }
176 
177 h128 KeyManager::uuid(Address const& _a) const
178 {
179  auto it = m_addrLookup.find(_a);
180  if (it == m_addrLookup.end())
181  return h128();
182  return it->second;
183 }
184 
185 Address KeyManager::address(h128 const& _uuid) const
186 {
187  auto it = m_uuidLookup.find(_uuid);
188  if (it == m_uuidLookup.end())
189  return Address();
190  return it->second;
191 }
192 
193 h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint)
194 {
195  Address addr = KeyPair(_s).address();
196  auto passHash = hashPassword(_pass);
197  cachePassword(_pass);
198  m_passwordHint[passHash] = _passwordHint;
199  auto uuid = m_store.importSecret(_s.asBytesSec(), _pass);
200  m_keyInfo[addr] = KeyInfo{passHash, _accountName, ""};
201  m_addrLookup[addr] = uuid;
202  m_uuidLookup[uuid] = addr;
203  write(m_keysFile);
204  return uuid;
205 }
206 
207 void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
208 {
209  bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });
210  if (key.empty())
211  return;
212  Address a = KeyPair(Secret(key)).address();
213  auto passHash = hashPassword(_pass);
214  if (!m_cachedPasswords.count(passHash))
215  cachePassword(_pass);
216  importExisting(_uuid, _info, a, passHash, _passwordHint);
217 }
218 
219 void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint)
220 {
221  if (!m_passwordHint.count(_passHash))
222  m_passwordHint[_passHash] = _passwordHint;
223  m_uuidLookup[_uuid] = _address;
224  m_addrLookup[_address] = _uuid;
225  m_keyInfo[_address].passHash = _passHash;
226  m_keyInfo[_address].accountName = _accountName;
227  write(m_keysFile);
228 }
229 
230 void KeyManager::kill(Address const& _a)
231 {
232  auto id = m_addrLookup[_a];
233  m_uuidLookup.erase(id);
234  m_addrLookup.erase(_a);
235  m_keyInfo.erase(_a);
236  m_store.kill(id);
237  write(m_keysFile);
238 }
239 
240 KeyPair KeyManager::presaleSecret(std::string const& _json, function<string(bool)> const& _password)
241 {
242  js::mValue val;
243  json_spirit::read_string(_json, val);
244  auto obj = val.get_obj();
245  string p = _password(true);
246  if (obj["encseed"].type() == js::str_type)
247  {
248  auto encseed = fromHex(obj["encseed"].get_str());
249  while (true)
250  {
251  KeyPair k = KeyPair::fromEncryptedSeed(&encseed, p);
252  if (obj["ethaddr"].type() == js::str_type)
253  {
254  Address a(obj["ethaddr"].get_str());
255  Address b = k.address();
256  if (a != b)
257  {
258  if ((p = _password(false)).empty())
259  BOOST_THROW_EXCEPTION(PasswordUnknown());
260  continue;
261  }
262  }
263  return k;
264  }
265  }
266  else
267  BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type"));
268 }
269 
271 {
272  set<Address> addresses;
273  for (auto const& i: m_keyInfo)
274  addresses.insert(i.first);
275  for (auto const& key: m_store.keys())
276  addresses.insert(m_store.address(key));
277  // Remove the zero address if present
278  return Addresses{addresses.upper_bound(Address()), addresses.end()};
279 }
280 
281 bool KeyManager::hasAccount(Address const& _address) const
282 {
283  if (!_address)
284  return false;
285  if (m_keyInfo.count(_address))
286  return true;
287  for (auto const& key: m_store.keys())
288  if (m_store.address(key) == _address)
289  return true;
290  return false;
291 }
292 
293 string const& KeyManager::accountName(Address const& _address) const
294 {
295  try
296  {
297  return m_keyInfo.at(_address).accountName;
298  }
299  catch (...)
300  {
301  return EmptyString;
302  }
303 }
304 
305 string const& KeyManager::passwordHint(Address const& _address) const
306 {
307  try
308  {
309  auto& info = m_keyInfo.at(_address);
310  if (info.passwordHint.size())
311  return info.passwordHint;
312  return m_passwordHint.at(info.passHash);
313  }
314  catch (...)
315  {
316  return EmptyString;
317  }
318 }
319 
320 h256 KeyManager::hashPassword(string const& _pass) const
321 {
322  // TODO SECURITY: store this a bit more securely; Scrypt perhaps?
323  return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure());
324 }
325 
326 void KeyManager::cachePassword(string const& _password) const
327 {
328  m_cachedPasswords[hashPassword(_password)] = _password;
329 }
330 
331 bool KeyManager::write(fs::path const& _keysFile) const
332 {
333  if (!m_keysFileKey)
334  return false;
335  write(m_keysFileKey, _keysFile);
336  return true;
337 }
338 
339 void KeyManager::write(string const& _pass, fs::path const& _keysFile) const
340 {
341  bytes salt = h256::random().asBytes();
342  writeFile(appendToFilename(_keysFile, ".salt"), salt, true);
343  auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
344 
345  cachePassword(_pass);
346  m_master = hashPassword(_pass);
347  write(key, _keysFile);
348 }
349 
350 void KeyManager::write(SecureFixedHash<16> const& _key, fs::path const& _keysFile) const
351 {
352  RLPStream s(4);
353  s << 1; // version
354 
355  s.appendList(m_keyInfo.size());
356  for (auto const& info: m_keyInfo)
357  {
358  h128 id = uuid(info.first);
359  auto const& ki = info.second;
360  s.appendList(5) << info.first << id << ki.passHash << ki.accountName << ki.passwordHint;
361  }
362 
363  s.appendList(m_passwordHint.size());
364  for (auto const& i: m_passwordHint)
365  s.appendList(2) << i.first << i.second;
366  s.append(m_defaultPasswordDeprecated);
367 
368  writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()), true);
369  m_keysFileKey = _key;
370  cachePassword(defaultPassword());
371 }
372 
374 {
375  KeyPair p = KeyPair::create();
376  bool keepGoing = true;
377  unsigned done = 0;
378  auto f = [&]() {
379  KeyPair lp = KeyPair::create();
380  while (keepGoing)
381  {
382  done++;
383  if (done % 1000 == 0)
384  cnote << "Tried" << done << "keys";
385  lp = KeyPair::create();
386  auto a = lp.address();
387  if (_type == NewKeyType::NoVanity ||
388  (_type == NewKeyType::DirectICAP && !a[0]) ||
389  (_type == NewKeyType::FirstTwo && a[0] == a[1]) ||
390  (_type == NewKeyType::FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
391  (_type == NewKeyType::FirstThree && a[0] == a[1] && a[1] == a[2]) ||
392  (_type == NewKeyType::FirstFour && a[0] == a[1] && a[1] == a[2] && a[2] == a[3])
393  )
394  break;
395  }
396  if (keepGoing)
397  p = lp;
398  keepGoing = false;
399  };
400 
401  vector<std::thread*> ts;
402  for (unsigned t = 0; t < std::thread::hardware_concurrency() - 1; ++t)
403  ts.push_back(new std::thread(f));
404  f();
405 
406  for (std::thread* t: ts)
407  {
408  t->join();
409  delete t;
410  }
411  return p;
412 }
dev::eth::KeyManager::hasAccount
bool hasAccount(Address const &_address) const
Definition: KeyManager.cpp:281
dev::encryptSymNoAuth
std::pair< bytes, h128 > encryptSymNoAuth(SecureFixedHash< 16 > const &_k, bytesConstRef _plain)
Encrypts payload with random IV/ctr using AES128-CTR.
Definition: Common.cpp:175
dev::eth::KeyManager::NewKeyType::FirstFour
@ FirstFour
dev::contents
bytes contents(boost::filesystem::path const &_file)
Definition: CommonIO.cpp:107
dev::eth::KeyManager::NewKeyType::DirectICAP
@ DirectICAP
dev::decryptSymNoAuth
bytesSec decryptSymNoAuth(SecureFixedHash< 16 > const &_k, h128 const &_iv, bytesConstRef _cipher)
Decrypts payload with specified IV/ctr using AES128-CTR.
Definition: Common.h:124
dev::eth::KeyManager::import
h128 import(Secret const &_s, std::string const &_accountName, std::string const &_pass, std::string const &_passwordHint)
dev::eth::KeyInfo
Definition: KeyManager.h:39
dev::secure_vector::empty
bool empty() const
Definition: Common.h:107
dev::SecretStore::noteAddress
bool noteAddress(h128 const &_uuid, Address const &_address)
Definition: SecretStore.cpp:205
dev::secure_vector::ref
vector_ref< T > ref()
Definition: Common.h:103
dev::SecureFixedHash< 16 >
JsonSpiritHeaders.h
dev::KDF
KDF
Definition: SecretStore.h:35
dev::pbkdf2
bytesSec pbkdf2(std::string const &_pass, bytes const &_salt, unsigned _iterations, unsigned _dkLen=32)
Derive key via PBKDF2.
dev::eth::KeyManager::NewKeyType::FirstTwo
@ FirstTwo
dev::h256
FixedHash< 32 > h256
Definition: FixedHash.h:356
dev::eth::KeyManager::NewKeyType
NewKeyType
Definition: KeyManager.h:77
dev::Addresses
h160s Addresses
A vector of Ethereum addresses.
Definition: Address.h:33
dev::FixedHash< 20 >
dev::eth::KeyManager::recode
bool recode(Address const &_address, std::string const &_newPass, std::string const &_hint, std::function< std::string()> const &_pass=DontKnowThrow, KDF _kdf=KDF::Scrypt)
Definition: KeyManager.cpp:62
dev::eth::KeyManager::NewKeyType::NoVanity
@ NoVanity
dev::SecretStore::keys
std::vector< h128 > keys() const
Returns the uuids of all stored keys.
Definition: SecretStore.h:95
dev::eth::KeyManager::secret
Secret secret(Address const &_address, std::function< std::string()> const &_pass=DontKnowThrow, bool _usePasswordCache=true) const
dev::Exception
Base class for all exceptions.
Definition: Exceptions.h:39
dev::KeyPair::create
static KeyPair create()
Create a new, randomly generated object.
Definition: Common.cpp:340
dev::SecureFixedHash::asBytesSec
bytesSec asBytesSec() const
Definition: FixedHash.h:261
dev::eth::KeyManager::store
SecretStore & store()
Definition: KeyManager.h:112
dev::eth::KeyManager::create
void create(std::string const &_pass)
Definition: KeyManager.cpp:56
dev::eth::KeyManager::presaleSecret
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:240
dev::secure_vector
Definition: Common.h:78
dev::h128
FixedHash< 16 > h128
Definition: FixedHash.h:358
dev::eth::KeyManager::passwordHint
std::string const & passwordHint(Address const &_address) const
Definition: KeyManager.cpp:305
dev::eth::KeyManager::exists
bool exists() const
Definition: KeyManager.cpp:51
dev::eth::KeyManager::NewKeyType::FirstTwoNextTwo
@ FirstTwoNextTwo
dev::appendToFilename
boost::filesystem::path appendToFilename(boost::filesystem::path const &_orig, std::string const &_suffix)
cnote
#define cnote
dev::KeyPair::fromEncryptedSeed
static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const &_password)
Create from an encrypted seed.
Definition: Common.cpp:350
dev::eth::KeyManager::load
bool load(std::string const &_pass)
Definition: KeyManager.cpp:74
dev::getPassword
std::string getPassword(std::string const &_prompt)
Requests the user to enter a password on the console.
Definition: CommonIO.cpp:154
dev::eth::KeyManager::~KeyManager
~KeyManager()
Definition: KeyManager.cpp:48
dev::eth::KeyManager::uuid
h128 uuid(Address const &_a) const
Definition: KeyManager.cpp:177
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
SHA3.h
dev::SecretStore::importSecret
h128 importSecret(bytesSec const &_s, std::string const &_pass)
dev::FixedHash< 32 >::random
static FixedHash random()
Definition: FixedHash.h:167
dev::KeyPair::address
Address const & address() const
Retrieve the associated address of the public key.
Definition: Common.h:168
KeyManager.h
dev::SecretStore::contains
bool contains(h128 const &_k) const
Definition: SecretStore.h:98
dev::eth::KeyManager::accounts
Addresses accounts() const
Definition: KeyManager.cpp:270
dev::RLPStream
Class for writing to an RLP bytestream.
Definition: RLP.h:370
dev::eth::KeyManager::newKeyPair
static KeyPair newKeyPair(NewKeyType _type)
Definition: KeyManager.cpp:373
dev::SecretStore::kill
void kill(h128 const &_uuid)
Removes the key specified by _uuid from both memory and disk.
Definition: SecretStore.cpp:168
dev::eth::KeyManager::noteHint
void noteHint(std::string const &_pass, std::string const &_hint)
Definition: KeyManager.h:91
dev::asBytes
bytes asBytes(std::string const &_b)
Converts a string to a byte array containing the string's (byte) data.
Definition: CommonData.h:106
dev::asString
std::string asString(bytes const &_b)
Definition: CommonData.h:93
std
Definition: FixedHash.h:393
dev::eth::PasswordUnknown
Definition: KeyManager.h:36
dev::SecretStore::save
void save(boost::filesystem::path const &_keysPath)
Store all keys in the directory _keysPath.
dev::eth::KeyManager::kill
void kill(h128 const &_id)
Definition: KeyManager.h:125
dev::eth::KeyManager::address
Address address(h128 const &_uuid) const
Definition: KeyManager.cpp:185
dev::EmptyString
std::string const EmptyString
Definition: Common.cpp:34
dev
Definition: Address.cpp:21
dev::KeyPair
Definition: Common.h:149
dev::Secret
SecureFixedHash< 32 > Secret
Definition: Common.h:36
cwarn
#define cwarn
Guards.h
dev::eth::KeyManager::accountName
std::string const & accountName(Address const &_address) const
Definition: KeyManager.cpp:293
dev::writeFile
void writeFile(boost::filesystem::path const &_file, bytesConstRef _data, bool _writeDeleteRename)
Definition: CommonIO.cpp:125
dev::FixedHash::asBytes
bytes asBytes() const
Definition: FixedHash.h:150
dev::eth::KeyManager::NewKeyType::FirstThree
@ FirstThree
dev::RLP
Definition: RLP.h:48
dev::Address
h160 Address
Definition: Address.h:30
dev::SecretStore::address
Address address(h128 const &_uuid) const
Definition: SecretStore.h:121
dev::eth::KeyManager::importExisting
void importExisting(h128 const &_uuid, std::string const &_accountName, std::string const &_pass, std::string const &_passwordHint)
dev::SecureFixedHash::ref
bytesConstRef ref() const
Definition: FixedHash.h:302
Log.h
RLP.h
dev::fromHex
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:81
dev::SecretStore::secret
bytesSec secret(h128 const &_uuid, std::function< std::string()> const &_pass, bool _useCache=true) const
dev::errinfo_comment
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:69