Browse Source

Ability to import version 1 keys. Possibly.

cl-refactor
Gav Wood 10 years ago
parent
commit
e789f645ea
  1. 8
      alethzero/Main.ui
  2. 27
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 105
      libdevcrypto/SecretStore.cpp
  5. 4
      libdevcrypto/SecretStore.h

8
alethzero/Main.ui

@ -157,6 +157,7 @@
<addaction name="newAccount"/> <addaction name="newAccount"/>
<addaction name="importKey"/> <addaction name="importKey"/>
<addaction name="importKeyFile"/> <addaction name="importKeyFile"/>
<addaction name="claimPresale"/>
<addaction name="exportKey"/> <addaction name="exportKey"/>
<addaction name="killAccount"/> <addaction name="killAccount"/>
<addaction name="separator"/> <addaction name="separator"/>
@ -1656,7 +1657,7 @@ font-size: 14pt</string>
<string>&amp;Enable Local Addresses</string> <string>&amp;Enable Local Addresses</string>
</property> </property>
</action> </action>
<action name="importKeyFile"> <action name="claimPresale">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1745,6 +1746,11 @@ font-size: 14pt</string>
<string>Co&amp;nfirm Transactions</string> <string>Co&amp;nfirm Transactions</string>
</property> </property>
</action> </action>
<action name="importKeyFile">
<property name="text">
<string>Import &amp;Secret Key File...</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

27
alethzero/MainWin.cpp

@ -813,6 +813,33 @@ void Main::on_importKey_triggered()
} }
void Main::on_importKeyFile_triggered() void Main::on_importKeyFile_triggered()
{
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
h128 uuid = m_keyManager.store().importKey(s.toStdString());
if (!uuid)
{
QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Web3 key file.");
return;
}
QString info = QInputDialog::getText(this, "Import Key File", "Enter a description of this key to help you recognise it in the future.");
QString pass;
for (Secret s; !s;)
{
s = Secret(m_keyManager.store().secret(uuid, [&](){
pass = QInputDialog::getText(this, "Import Key File", "Enter the password for the key to complete the import.", QLineEdit::Password);
return pass.toStdString();
}, false));
if (!s && QMessageBox::question(this, "Import Key File", "The password you provided is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
QString hint = QInputDialog::getText(this, "Import Key File", "Enter a hint for this password to help you remember it.");
m_keyManager.importExisting(uuid, info.toStdString(), pass.toStdString(), hint.toStdString());
}
void Main::on_claimPresale_triggered()
{ {
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
try try

1
alethzero/MainWin.h

@ -138,6 +138,7 @@ private slots:
void on_killAccount_triggered(); void on_killAccount_triggered();
void on_importKey_triggered(); void on_importKey_triggered();
void on_importKeyFile_triggered(); void on_importKeyFile_triggered();
void on_claimPresale_triggered();
void on_exportKey_triggered(); void on_exportKey_triggered();
// Account pane // Account pane

105
libdevcrypto/SecretStore.cpp

@ -22,6 +22,7 @@
#include "SecretStore.h" #include "SecretStore.h"
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
@ -42,10 +43,10 @@ SecretStore::~SecretStore()
{ {
} }
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass) const bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass, bool _useCache) const
{ {
auto rit = m_cached.find(_uuid); auto rit = m_cached.find(_uuid);
if (rit != m_cached.end()) if (_useCache && rit != m_cached.end())
return rit->second; return rit->second;
auto it = m_keys.find(_uuid); auto it = m_keys.find(_uuid);
if (it == m_keys.end()) if (it == m_keys.end())
@ -101,28 +102,71 @@ void SecretStore::save(std::string const& _keysPath)
} }
} }
static js::mValue upgraded(std::string const& _s)
{
js::mValue v;
js::read_string(_s, v);
if (v.type() != js::obj_type)
return js::mValue();
js::mObject ret = v.get_obj();
unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0;
if (version == 1)
{
// upgrade to version 2
js::mObject old;
swap(old, ret);
ret["id"] = old["Id"];
js::mObject c;
c["ciphertext"] = old["Crypto"].get_obj()["CipherText"];
c["cipher"] = "aes-128-cbc";
{
js::mObject cp;
cp["iv"] = old["Crypto"].get_obj()["IV"];
c["cipherparams"] = cp;
}
c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"];
{
js::mObject kp;
kp["salt"] = old["Crypto"].get_obj()["Salt"];
for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj())
if (i.first != "SaltLen")
kp[boost::to_lower_copy(i.first)] = i.second;
c["kdfparams"] = kp;
}
c["sillymac"] = old["Crypto"].get_obj()["MAC"];
c["sillymacjson"] = _s;
ret["crypto"] = c;
version = 2;
}
if (version == 2)
return ret;
return js::mValue();
}
void SecretStore::load(std::string const& _keysPath) void SecretStore::load(std::string const& _keysPath)
{ {
fs::path p(_keysPath); fs::path p(_keysPath);
boost::filesystem::create_directories(p); boost::filesystem::create_directories(p);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path())) if (is_regular_file(it->path()))
{ readKey(it->path().string(), true);
cdebug << "Reading" << it->path(); }
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type) h128 SecretStore::readKey(std::string const& _file, bool _deleteFile)
{ {
js::mObject o = v.get_obj(); cdebug << "Reading" << _file;
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; js::mValue u = upgraded(contentsString(_file));
if (version == 2) if (u.type() == js::obj_type)
m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string()); {
else js::mObject& o = u.get_obj();
cwarn << "Cannot read key version" << version; auto uuid = fromUUID(o["id"].get_str());
} m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _deleteFile ? _file : string());
// else return uuid;
// cwarn << "Invalid JSON in key file" << it->path().string(); }
} else
cwarn << "Invalid JSON in key file" << _file;
return h128();
} }
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
@ -202,13 +246,28 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
bytes cipherText = fromHex(o["ciphertext"].get_str()); bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC // check MAC
h256 mac(o["mac"].get_str()); if (o.count("mac"))
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{ {
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); h256 mac(o["mac"].get_str());
return bytes(); h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
} }
else if (o.count("sillymac"))
{
h256 mac(o["sillymac"].get_str());
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
}
else
cwarn << "No MAC. Proceeding anyway.";
// decrypt // decrypt
if (o["cipher"].get_str() == "aes-128-cbc") if (o["cipher"].get_str() == "aes-128-cbc")

4
libdevcrypto/SecretStore.h

@ -36,7 +36,8 @@ public:
SecretStore(); SecretStore();
~SecretStore(); ~SecretStore();
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass) const; bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass, bool _useCache = true) const;
h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; }
h128 importSecret(bytes const& _s, std::string const& _pass); h128 importSecret(bytes const& _s, std::string const& _pass);
void kill(h128 const& _uuid); void kill(h128 const& _uuid);
@ -48,6 +49,7 @@ private:
void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); void load(std::string const& _keysPath = getDataDir("web3") + "/keys");
static std::string encrypt(bytes const& _v, std::string const& _pass); static std::string encrypt(bytes const& _v, std::string const& _pass);
static bytes decrypt(std::string const& _v, std::string const& _pass); static bytes decrypt(std::string const& _v, std::string const& _pass);
h128 readKey(std::string const& _file, bool _deleteFile);
mutable std::unordered_map<h128, bytes> m_cached; mutable std::unordered_map<h128, bytes> m_cached;
std::unordered_map<h128, std::pair<std::string, std::string>> m_keys; std::unordered_map<h128, std::pair<std::string, std::string>> m_keys;

Loading…
Cancel
Save