Gav Wood
10 years ago
15 changed files with 528 additions and 17 deletions
@ -0,0 +1,33 @@ |
|||||
|
cmake_policy(SET CMP0015 NEW) |
||||
|
set(CMAKE_AUTOMOC OFF) |
||||
|
|
||||
|
aux_source_directory(. SRC_LIST) |
||||
|
|
||||
|
include_directories(BEFORE ..) |
||||
|
include_directories(${Boost_INCLUDE_DIRS}) |
||||
|
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) |
||||
|
|
||||
|
if (JSCONSOLE) |
||||
|
include_directories(${V8_INCLUDE_DIRS}) |
||||
|
endif() |
||||
|
|
||||
|
set(EXECUTABLE ethkey) |
||||
|
|
||||
|
file(GLOB HEADERS "*.h") |
||||
|
|
||||
|
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) |
||||
|
|
||||
|
add_dependencies(${EXECUTABLE} BuildInfo.h) |
||||
|
|
||||
|
target_link_libraries(${EXECUTABLE} devcrypto) |
||||
|
target_link_libraries(${EXECUTABLE} ethcore) |
||||
|
|
||||
|
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) |
||||
|
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) |
||||
|
endif() |
||||
|
|
||||
|
if (APPLE) |
||||
|
install(TARGETS ${EXECUTABLE} DESTINATION bin) |
||||
|
else() |
||||
|
eth_install_executable(${EXECUTABLE}) |
||||
|
endif() |
@ -0,0 +1,351 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum is free software: you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation, either version 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
cpp-ethereum is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License |
||||
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/** @file KeyAux.cpp
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2014 |
||||
|
* CLI module for key management. |
||||
|
*/ |
||||
|
|
||||
|
#include <thread> |
||||
|
#include <chrono> |
||||
|
#include <fstream> |
||||
|
#include <iostream> |
||||
|
#include <boost/algorithm/string.hpp> |
||||
|
#include <boost/algorithm/string/trim_all.hpp> |
||||
|
#include <libdevcore/SHA3.h> |
||||
|
#include <libdevcore/FileSystem.h> |
||||
|
#include <libethcore/KeyManager.h> |
||||
|
#include <libethcore/ICAP.h> |
||||
|
#include "BuildInfo.h" |
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
using namespace boost::algorithm; |
||||
|
|
||||
|
#undef RETURN |
||||
|
|
||||
|
class BadArgument: public Exception {}; |
||||
|
|
||||
|
string getAccountPassword(KeyManager& keyManager, Address const& a) |
||||
|
{ |
||||
|
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); |
||||
|
} |
||||
|
|
||||
|
string createPassword(std::string const& _prompt) |
||||
|
{ |
||||
|
string ret; |
||||
|
while (true) |
||||
|
{ |
||||
|
ret = getPassword(_prompt); |
||||
|
string confirm = getPassword("Please confirm the password by entering it again: "); |
||||
|
if (ret == confirm) |
||||
|
break; |
||||
|
cout << "Passwords were different. Try again." << endl; |
||||
|
} |
||||
|
return ret; |
||||
|
// cout << "Enter a hint to help you remember this password: " << flush;
|
||||
|
// cin >> hint;
|
||||
|
// return make_pair(ret, hint);
|
||||
|
} |
||||
|
|
||||
|
pair<string, string> createPassword(KeyManager& _keyManager, std::string const& _prompt) |
||||
|
{ |
||||
|
string pass; |
||||
|
while (true) |
||||
|
{ |
||||
|
pass = getPassword(_prompt); |
||||
|
string confirm = getPassword("Please confirm the password by entering it again: "); |
||||
|
if (pass == confirm) |
||||
|
break; |
||||
|
cout << "Passwords were different. Try again." << endl; |
||||
|
} |
||||
|
string hint; |
||||
|
if (!_keyManager.haveHint(pass)) |
||||
|
{ |
||||
|
cout << "Enter a hint to help you remember this password: " << flush; |
||||
|
cin >> hint; |
||||
|
} |
||||
|
return make_pair(pass, hint); |
||||
|
} |
||||
|
|
||||
|
class KeyCLI |
||||
|
{ |
||||
|
public: |
||||
|
enum class OperationMode |
||||
|
{ |
||||
|
None, |
||||
|
ListBare, |
||||
|
NewBare, |
||||
|
ImportBare, |
||||
|
ExportBare, |
||||
|
RecodeBare, |
||||
|
FirstWallet, |
||||
|
CreateWallet, |
||||
|
List = FirstWallet, |
||||
|
New, |
||||
|
Import, |
||||
|
Export, |
||||
|
Recode, |
||||
|
Kill |
||||
|
}; |
||||
|
|
||||
|
KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {} |
||||
|
|
||||
|
bool interpretOption(int& i, int argc, char** argv) |
||||
|
{ |
||||
|
string arg = argv[i]; |
||||
|
if (arg == "-n" || arg == "--new") |
||||
|
m_mode = OperationMode::New; |
||||
|
else if (arg == "--wallet-path" && i + 1 < argc) |
||||
|
m_walletPath = argv[++i]; |
||||
|
else if (arg == "--secrets-path" && i + 1 < argc) |
||||
|
m_secretsPath = argv[++i]; |
||||
|
else if ((arg == "-m" || arg == "--master") && i + 1 < argc) |
||||
|
m_masterPassword = argv[++i]; |
||||
|
else if (arg == "--unlock" && i + 1 < argc) |
||||
|
m_unlocks.push_back(argv[++i]); |
||||
|
else if (arg == "--lock" && i + 1 < argc) |
||||
|
m_lock = argv[++i]; |
||||
|
else if (arg == "--kdf" && i + 1 < argc) |
||||
|
m_kdf = argv[++i]; |
||||
|
else if (arg == "--kdf-param" && i + 2 < argc) |
||||
|
{ |
||||
|
auto n = argv[++i]; |
||||
|
auto v = argv[++i]; |
||||
|
m_kdfParams[n] = v; |
||||
|
} |
||||
|
else if (arg == "--new-bare") |
||||
|
m_mode = OperationMode::NewBare; |
||||
|
else if (arg == "--import-bare") |
||||
|
m_mode = OperationMode::ImportBare; |
||||
|
else if (arg == "--list-bare") |
||||
|
m_mode = OperationMode::ListBare; |
||||
|
else if (arg == "--export-bare") |
||||
|
m_mode = OperationMode::ExportBare; |
||||
|
else if (arg == "--recode-bare") |
||||
|
m_mode = OperationMode::RecodeBare; |
||||
|
else if (arg == "--create-wallet") |
||||
|
m_mode = OperationMode::CreateWallet; |
||||
|
else if (arg == "--list") |
||||
|
m_mode = OperationMode::List; |
||||
|
else if ((arg == "-n" || arg == "--new") && i + 1 < argc) |
||||
|
{ |
||||
|
m_mode = OperationMode::New; |
||||
|
m_name = argv[++i]; |
||||
|
} |
||||
|
else if ((arg == "-i" || arg == "--import") && i + 2 < argc) |
||||
|
{ |
||||
|
m_mode = OperationMode::Import; |
||||
|
m_inputs = strings(1, argv[++i]); |
||||
|
m_name = argv[++i]; |
||||
|
} |
||||
|
else if (arg == "--export") |
||||
|
m_mode = OperationMode::Export; |
||||
|
else if (arg == "--recode") |
||||
|
m_mode = OperationMode::Recode; |
||||
|
else if (arg == "--no-icap") |
||||
|
m_icap = false; |
||||
|
else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) |
||||
|
m_inputs.push_back(arg); |
||||
|
else |
||||
|
return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
KeyPair makeKey() const |
||||
|
{ |
||||
|
KeyPair k(Secret::random()); |
||||
|
while (m_icap && k.address()[0]) |
||||
|
k = KeyPair(sha3(k.secret())); |
||||
|
return k; |
||||
|
} |
||||
|
|
||||
|
void execute() |
||||
|
{ |
||||
|
if (m_mode == OperationMode::CreateWallet) |
||||
|
{ |
||||
|
KeyManager wallet(m_walletPath, m_secretsPath); |
||||
|
if (m_masterPassword.empty()) |
||||
|
m_masterPassword = createPassword("Please enter a MASTER password to protect your key store (make it strong!): "); |
||||
|
if (m_masterPassword.empty()) |
||||
|
cerr << "Aborted (empty password not allowed)." << endl; |
||||
|
else |
||||
|
wallet.create(m_masterPassword); |
||||
|
} |
||||
|
else if (m_mode < OperationMode::FirstWallet) |
||||
|
{ |
||||
|
SecretStore store(m_secretsPath); |
||||
|
switch (m_mode) |
||||
|
{ |
||||
|
case OperationMode::ListBare: |
||||
|
for (h128 const& u: std::set<h128>() + store.keys()) |
||||
|
cout << toUUID(u) << endl; |
||||
|
break; |
||||
|
case OperationMode::NewBare: |
||||
|
{ |
||||
|
if (m_lock.empty()) |
||||
|
m_lock = createPassword("Enter a password with which to secure this account: "); |
||||
|
auto k = makeKey(); |
||||
|
store.importSecret(k.secret().asBytes(), m_lock); |
||||
|
cout << "Created key " << k.address().abridged() << endl; |
||||
|
cout << "Address: " << k.address().hex() << endl; |
||||
|
cout << "ICAP: " << ICAP(k.address()).encoded() << endl; |
||||
|
break; |
||||
|
} |
||||
|
case OperationMode::ImportBare: |
||||
|
for (string const& i: m_inputs) |
||||
|
{ |
||||
|
h128 u; |
||||
|
bytes b; |
||||
|
b = fromHex(i); |
||||
|
if (b.size() != 32) |
||||
|
{ |
||||
|
std::string s = contentsString(i); |
||||
|
b = fromHex(s); |
||||
|
if (b.size() != 32) |
||||
|
u = store.importKey(i); |
||||
|
} |
||||
|
if (!u && b.size() == 32) |
||||
|
u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); |
||||
|
else |
||||
|
{ |
||||
|
cerr << "Cannot import " << i << " not a file or secret." << endl; |
||||
|
continue; |
||||
|
} |
||||
|
cout << "Successfully imported " << i << " as " << toUUID(u); |
||||
|
} |
||||
|
break; |
||||
|
case OperationMode::ExportBare: break; |
||||
|
case OperationMode::RecodeBare: |
||||
|
for (auto const& i: m_inputs) |
||||
|
{ |
||||
|
h128 u = fromUUID(i); |
||||
|
if (u) |
||||
|
if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) |
||||
|
cerr << "Re-encoded " << toUUID(u) << endl; |
||||
|
else |
||||
|
cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; |
||||
|
else |
||||
|
cerr << "Couldn't re-encode " << toUUID(u) << "; not found." << endl; |
||||
|
} |
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
KeyManager wallet(m_walletPath, m_secretsPath); |
||||
|
if (wallet.exists()) |
||||
|
while (true) |
||||
|
{ |
||||
|
if (wallet.load(m_masterPassword)) |
||||
|
break; |
||||
|
if (!m_masterPassword.empty()) |
||||
|
{ |
||||
|
cout << "Password invalid. Try again." << endl; |
||||
|
m_masterPassword.clear(); |
||||
|
} |
||||
|
m_masterPassword = getPassword("Please enter your MASTER password: "); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
cerr << "Couldn't open wallet. Does it exist?" << endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string lockPassword(std::string const& _accountName) |
||||
|
{ |
||||
|
return m_lock.empty() ? createPassword("Enter a password with which to secure account " + _accountName + ": ") : m_lock; |
||||
|
} |
||||
|
|
||||
|
static void streamHelp(ostream& _out) |
||||
|
{ |
||||
|
_out |
||||
|
<< "Secret-store (\"bare\") operation modes:" << endl |
||||
|
<< " --list-bare List all secret available in secret-store." << endl |
||||
|
<< " --new-bare Generate and output a key without interacting with wallet and dump the JSON." << endl |
||||
|
<< " --import-bare [ <file>|<secret-hex> , ... ] Import keys from given sources." << endl |
||||
|
<< " --recode-bare [ <uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl |
||||
|
// << " --export-bare [ <uuid> , ... ] Export given keys." << endl
|
||||
|
<< "Secret-store configuration:" << endl |
||||
|
<< " --secrets-path <path> Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl |
||||
|
<< endl |
||||
|
<< "Wallet operating modes:" << endl |
||||
|
<< " -l,--list List all keys available in wallet." << endl |
||||
|
<< " -n,--new <name> Create a new key with given name and add it in the wallet." << endl |
||||
|
<< " -i,--import [<uuid>|<file>|<secret-hex>] <name> Import keys from given source and place in wallet." << endl |
||||
|
<< " -e,--export [ <address>|<uuid> , ... ] Export given keys." << endl |
||||
|
<< " -r,--recode [ <address>|<uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl |
||||
|
<< "Wallet configuration:" << endl |
||||
|
<< " --create-wallet Create an Ethereum master wallet." << endl |
||||
|
<< " --wallet-path <path> Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl |
||||
|
<< " -m, --master <password> Specify wallet (master) password." << endl |
||||
|
<< endl |
||||
|
<< "Encryption configuration:" << endl |
||||
|
<< " --kdf <kdfname> Specify KDF to use when encrypting (default: sc rypt)" << endl |
||||
|
<< " --kdf-param <name> <value> Specify a parameter for the KDF." << endl |
||||
|
// << " --cipher <ciphername> Specify cipher to use when encrypting (default: aes-128-ctr)" << endl
|
||||
|
// << " --cipher-param <name> <value> Specify a parameter for the cipher." << endl
|
||||
|
<< " --lock <password> <hint> Specify password for when encrypting a (the) key." << endl |
||||
|
<< endl |
||||
|
<< "Decryption configuration:" << endl |
||||
|
<< " --unlock <password> Specify password for a (the) key." << endl |
||||
|
<< "Key generation configuration:" << endl |
||||
|
<< " --no-icap Don't bother to make a direct-ICAP capable key." << endl |
||||
|
; |
||||
|
} |
||||
|
|
||||
|
static bool isTrue(std::string const& _m) |
||||
|
{ |
||||
|
return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; |
||||
|
} |
||||
|
|
||||
|
static bool isFalse(std::string const& _m) |
||||
|
{ |
||||
|
return _m == "off" || _m == "no" || _m == "false" || _m == "0"; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; } |
||||
|
|
||||
|
/// Operating mode.
|
||||
|
OperationMode m_mode; |
||||
|
|
||||
|
/// Wallet stuff
|
||||
|
string m_secretsPath = SecretStore::defaultPath(); |
||||
|
string m_walletPath = KeyManager::defaultPath(); |
||||
|
|
||||
|
/// Wallet password stuff
|
||||
|
string m_masterPassword; |
||||
|
strings m_unlocks; |
||||
|
string m_lock; |
||||
|
bool m_icap = true; |
||||
|
|
||||
|
/// Creating
|
||||
|
string m_name; |
||||
|
|
||||
|
/// Importing
|
||||
|
strings m_inputs; |
||||
|
|
||||
|
string m_kdf = "scrypt"; |
||||
|
map<string, string> m_kdfParams; |
||||
|
// string m_cipher;
|
||||
|
// map<string, string> m_cipherParams;
|
||||
|
}; |
@ -0,0 +1,84 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum is free software: you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation, either version 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
cpp-ethereum is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License |
||||
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/** @file main.cpp
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2014 |
||||
|
* Ethereum client. |
||||
|
*/ |
||||
|
|
||||
|
#include <thread> |
||||
|
#include <chrono> |
||||
|
#include <fstream> |
||||
|
#include <iostream> |
||||
|
#include <libdevcore/FileSystem.h> |
||||
|
#include <libdevcore/Log.h> |
||||
|
#include <libethcore/KeyManager.h> |
||||
|
#include "BuildInfo.h" |
||||
|
#include "KeyAux.h" |
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
|
||||
|
void help() |
||||
|
{ |
||||
|
cout |
||||
|
<< "Usage ethkey [OPTIONS]" << endl |
||||
|
<< "Options:" << endl << endl; |
||||
|
KeyCLI::streamHelp(cout); |
||||
|
cout |
||||
|
<< "General Options:" << endl |
||||
|
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl |
||||
|
<< " -V,--version Show the version and exit." << endl |
||||
|
<< " -h,--help Show this help message and exit." << endl |
||||
|
; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
void version() |
||||
|
{ |
||||
|
cout << "ethkey version " << dev::Version << endl; |
||||
|
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char** argv) |
||||
|
{ |
||||
|
KeyCLI m(KeyCLI::OperationMode::ListBare); |
||||
|
g_logVerbosity = 0; |
||||
|
|
||||
|
for (int i = 1; i < argc; ++i) |
||||
|
{ |
||||
|
string arg = argv[i]; |
||||
|
if (m.interpretOption(i, argc, argv)) {} |
||||
|
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) |
||||
|
g_logVerbosity = atoi(argv[++i]); |
||||
|
else if (arg == "-h" || arg == "--help") |
||||
|
help(); |
||||
|
else if (arg == "-V" || arg == "--version") |
||||
|
version(); |
||||
|
else |
||||
|
{ |
||||
|
cerr << "Invalid argument: " << arg << endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
m.execute(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
Loading…
Reference in new issue