Browse Source

Fairly complete implementation of KeyManager - now to integrate.

cl-refactor
Gav Wood 10 years ago
parent
commit
de10fdc403
  1. 128
      exp/main.cpp

128
exp/main.cpp

@ -70,10 +70,10 @@ inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref
class KeyStore
{
public:
KeyStore() { readKeys(); }
KeyStore() { load(); }
~KeyStore() {}
bytes key(h128 const& _uuid, function<std::string()> const& _pass)
bytes secret(h128 const& _uuid, function<std::string()> const& _pass)
{
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
@ -81,41 +81,55 @@ public:
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return bytes();
bytes key = decrypt(it->second, _pass());
bytes key = decrypt(it->second.first, _pass());
if (!key.empty())
m_cached[_uuid] = key;
return key;
}
h128 import(bytes const& _s, std::string const& _pass)
h128 importSecret(bytes const& _s, std::string const& _pass)
{
h128 r = h128::random();
m_cached[r] = _s;
m_keys[r] = encrypt(_s, _pass);
writeKeys();
m_keys[r] = make_pair(encrypt(_s, _pass), std::string());
save();
return r;
}
void kill(h128 const& _uuid)
{
m_cached.erase(_uuid);
if (m_keys.count(_uuid))
{
boost::filesystem::remove(m_keys[_uuid].second);
m_keys.erase(_uuid);
}
}
// Clear any cached keys.
void clearCache() const { m_cached.clear(); }
private:
void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
void save(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
boost::filesystem::create_directories(p);
for (auto const& k: m_keys)
for (auto& k: m_keys)
{
std::string uuid = toUUID(k.first);
std::string filename = (p / uuid).string() + ".json";
js::mObject v;
v["crypto"] = k.second;
v["crypto"] = k.second.first;
v["id"] = uuid;
v["version"] = 2;
writeFile((p / uuid).string() + ".json", js::write_string(js::mValue(v), true));
writeFile(filename, js::write_string(js::mValue(v), true));
if (!k.second.second.empty() && k.second.second != filename)
boost::filesystem::remove(k.second.second);
k.second.second = filename;
}
}
void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
void load(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
js::mValue v;
@ -129,7 +143,7 @@ private:
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
m_keys[fromUUID(o["id"].get_str())] = make_pair(o["crypto"], it->path().string());
else
cwarn << "Cannot read key version" << version;
}
@ -229,7 +243,7 @@ private:
}
mutable std::map<h128, bytes> m_cached;
std::map<h128, js::mValue> m_keys;
std::map<h128, std::pair<js::mValue, std::string>> m_keys;
};
class UnknownPassword: public Exception {};
@ -237,7 +251,7 @@ class UnknownPassword: public Exception {};
struct KeyInfo
{
h256 passHash;
std::string name;
std::string info;
};
static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); };
@ -255,7 +269,7 @@ static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword())
class KeyManager
{
public:
KeyManager() {}
KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info"): m_keysFile(_keysFile) {}
~KeyManager() {}
void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; }
@ -289,7 +303,7 @@ public:
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
m_cachedPasswords[sha3(m_password)] = m_password;
m_cachedPasswords[hashPassword(m_password)] = m_password;
return true;
}
catch (...) {
@ -312,12 +326,12 @@ public:
Secret secret(h128 const& _uuid, function<std::string()> const& _pass = DontKnowThrow)
{
return Secret(m_store.key(_uuid, [&](){
return Secret(m_store.secret(_uuid, [&](){
auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash);
if (it == m_cachedPasswords.end())
{
std::string p = _pass();
m_cachedPasswords[sha3(p)] = p;
m_cachedPasswords[hashPassword(p)] = p;
return p;
}
else
@ -325,45 +339,89 @@ public:
}));
}
h128 import(Secret const& _s, std::string const& _pass, string const& _info = std::string(), string const& _passInfo = std::string())
h128 uuid(Address const& _a) const
{
auto it = m_addrLookup.find(_a);
if (it == m_addrLookup.end())
return h128();
return it->second;
}
Address address(h128 const& _uuid) const
{
for (auto const& i: m_addrLookup)
if (i.second == _uuid)
return i.first;
return Address();
}
h128 import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo)
{
Address addr = KeyPair(_s).address();
auto passHash = sha3(_pass);
auto passHash = hashPassword(_pass);
m_cachedPasswords[passHash] = _pass;
m_passwordInfo[passHash] = _passInfo;
auto uuid = m_store.import(_s.asBytes(), _pass);
auto uuid = m_store.importSecret(_s.asBytes(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _info};
m_addrLookup[addr] = uuid;
save(m_keysFile);
return uuid;
}
h128 import(Secret const& _s, std::string const& _info = std::string())
h128 import(Secret const& _s, std::string const& _info)
{
// cache password, remember the key, remember the address
return import(_s, m_password, _info, std::string());
return import(_s, _info, m_password, std::string());
}
void importExisting(h128 const& _uuid, std::string const& _pass, std::string const& _info = std::string(), std::string const& _passInfo = std::string())
void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo)
{
bytes key = m_store.key(_uuid, [&](){ return _pass; });
bytes key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty())
return;
Address a = KeyPair(Secret(key)).address();
auto passHash = sha3(_pass);
auto passHash = hashPassword(_pass);
if (!m_passwordInfo.count(passHash))
m_passwordInfo[passHash] = _passInfo;
if (!m_cachedPasswords.count(passHash))
m_cachedPasswords[passHash] = _pass;
m_addrLookup[a] = _uuid;
m_keyInfo[_uuid].passHash = passHash;
m_keyInfo[_uuid].name = _info;
m_keyInfo[_uuid].info = _info;
save(m_keysFile);
}
void kill(h128 const& _id)
{
kill(address(_id));
}
void kill(Address const& _a)
{
auto id = m_addrLookup[_a];
m_addrLookup.erase(_a);
m_keyInfo.erase(id);
m_store.kill(id);
}
std::map<Address, std::string> keys() const
{
std::map<Address, std::string> ret;
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0)
ret[i.first] = m_keyInfo.at(i.second).info;
return ret;
}
KeyStore& store() { return m_store; }
private:
h256 hashPassword(std::string const& _pass) const
{
// TODO SECURITY: store this a bit more securely; Scrypt perhaps?
return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32));
}
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool save(std::string const& _keysFile)
@ -388,7 +446,7 @@ private:
s << 1;
s.appendList(m_addrLookup.size());
for (auto const& i: m_addrLookup)
s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name;
s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].info;
s.appendList(m_passwordInfo.size());
for (auto const& i: m_passwordInfo)
s.appendList(2) << i.first << i.second;
@ -411,7 +469,7 @@ private:
KeyStore m_store;
h128 m_key;
std::string m_keysFile = getDataDir("ethereum") + "/keys.info";
std::string m_keysFile;
};
int main()
@ -422,10 +480,16 @@ int main()
else
keyman.create("foo");
auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0");
keyman.importExisting(id, "bar");
Address a("9cab1cc4e8fe528267c6c3af664a1adbce810b5f");
// keyman.importExisting(fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"), "{\"name\":\"Gavin Wood - Main identity\"}", "bar", "{\"hint\":\"Not foo.\"}");
// Address a2 = keyman.address(keyman.import(Secret::random(), "Key with no additional security."));
// cdebug << toString(a2);
Address a2("19c486071651b2650449ba3c6a807f316a73e8fe");
cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
cdebug << "Secret key for " << toUUID(id) << "is" << keyman.store().key(id, [](){ return "bar"; });
}
#elif 0

Loading…
Cancel
Save