Browse Source

Version bump, KeyManager.

cl-refactor
Gav Wood 10 years ago
parent
commit
b2857b26ea
  1. 161
      exp/main.cpp
  2. 2
      libdevcore/Common.cpp

161
exp/main.cpp

@ -67,40 +67,36 @@ namespace fs = boost::filesystem;
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; }
class KeyManager: public Worker
class KeyStore
{
public:
KeyManager() { readKeys(); }
~KeyManager() {}
KeyStore() { readKeys(); }
~KeyStore() {}
Secret secret(h128 const& _uuid, function<std::string()> const& _pass)
bytes key(h128 const& _uuid, function<std::string()> const& _pass)
{
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return Secret();
Secret ret(decrypt(it->second, _pass()));
if (ret)
m_cached[_uuid] = ret;
return ret;
return bytes();
bytes key = decrypt(it->second, _pass());
if (!key.empty())
m_cached[_uuid] = key;
return key;
}
h128 import(Secret const& _s, std::string const& _pass)
h128 import(bytes const& _s, std::string const& _pass)
{
h128 r(sha3(_s));
h128 r = h128::random();
m_cached[r] = _s;
m_keys[r] = encrypt(_s.asBytes(), _pass);
m_keys[r] = encrypt(_s, _pass);
writeKeys();
return r;
}
h128 create(std::string const& _pass)
{
return import(Secret::random(), _pass);
}
// Clear any cached keys.
void clearCache() const { m_cached.clear(); }
private:
@ -137,8 +133,8 @@ private:
else
cwarn << "Cannot read key version" << version;
}
else
cwarn << "Invalid JSON in key file" << it->path().string();
// else
// cwarn << "Invalid JSON in key file" << it->path().string();
}
}
@ -232,10 +228,135 @@ private:
}
}
mutable std::map<h128, Secret> m_cached;
mutable std::map<h128, bytes> m_cached;
std::map<h128, js::mValue> m_keys;
};
class UnknownPassword: public Exception {};
struct KeyInfo
{
h256 passHash;
std::string name;
};
static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); };
// This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store.
class KeyManager
{
public:
KeyManager() { m_cachedPasswords[sha3(m_password)] = m_password; }
~KeyManager() {}
void load(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
try {
bytes salt = contents(_keysFile + ".salt");
bytes encKeys = contents(_keysFile);
m_key = h128(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys);
RLP s(bs);
unsigned version = (unsigned)s[0];
if (version == 1)
{
for (auto const& i: s[1])
m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]};
for (auto const& i: s[2])
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
}
catch (...) {}
m_cachedPasswords[sha3(m_password)] = m_password;
}
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool save(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") { if (!m_key) return false; save(m_key, _keysFile); return true; }
void save(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
save(key, _keysFile);
}
void save(h128 const& _key, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
RLPStream s(4);
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(m_passwordInfo.size());
for (auto const& i: m_passwordInfo)
s.appendList(2) << i.first << i.second;
s.append(m_password);
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key;
}
Secret secret(Address const& _address, function<std::string()> const& _pass = DontKnowThrow)
{
auto it = m_addrLookup.find(_address);
if (it == m_addrLookup.end())
return Secret();
return secret(it->second, _pass);
}
Secret secret(h128 const& _uuid, function<std::string()> const& _pass = DontKnowThrow)
{
return Secret(m_store.key(_uuid, [&](){
auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash);
if (it == m_cachedPasswords.end())
{
std::string p = _pass();
m_cachedPasswords[sha3(p)] = p;
return p;
}
else
return it->second;
}));
}
h128 import(Secret const& _s, std::string const& _pass, string const& _info = std::string(), string const& _passInfo = std::string())
{
Address addr = KeyPair(_s).address();
auto passHash = sha3(_pass);
m_cachedPasswords[passHash] = _pass;
m_passwordInfo[passHash] = _passInfo;
auto uuid = m_store.import(_s.asBytes(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _info};
m_addrLookup[addr] = uuid;
return uuid;
}
h128 import(Secret const& _s, std::string const& _info = std::string())
{
// cache password, remember the key, remember the address
return import(_s, m_password, _info, std::string());
}
private:
// Ethereum keys.
std::map<Address, h128> m_addrLookup;
std::map<h128, KeyInfo> m_keyInfo;
std::map<h256, std::string> m_passwordInfo;
// Passwords that we're storing.
std::map<h256, std::string> m_cachedPasswords;
// The default password for keys in the keystore - protected by the master password.
std::string m_password = asString(h256::random().asBytes());
KeyStore m_store;
h128 m_key;
};
int main()
{
KeyManager keyman;

2
libdevcore/Common.cpp

@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.9.15o";
char const* Version = "0.9.16";
void HasInvariants::checkInvariants() const
{

Loading…
Cancel
Save