diff --git a/programs/light_client/Wallet.cpp b/programs/light_client/Wallet.cpp index 9fd4e43c..ffaa7673 100644 --- a/programs/light_client/Wallet.cpp +++ b/programs/light_client/Wallet.cpp @@ -1,4 +1,6 @@ #include "Wallet.hpp" +#include +#include Wallet::Wallet() { @@ -11,52 +13,122 @@ Wallet::~Wallet() bool Wallet::open( QString file_path ) { - return false; + fc::path p( file_path.toStdString() ); + if( !fc::exists( p ) ) + { + ilog( "Unable to open wallet file '${f}', it does not exist", ("f",p) ); + return false; + } + _wallet_file_path = p; + return true; +} + +bool Wallet::isOpen()const +{ + return _wallet_file_path != fc::path(); } bool Wallet::close() { + if( !isOpen() ) return false; save(); + _wallet_file_path = fc::path(); return false; } bool Wallet::save() { + if( !isOpen() ) return false; + /// TODO: backup existing wallet file first. + fc::json::save_to_file( _data, _wallet_file_path ); return false; } bool Wallet::saveAs( QString file_path ) { + if( !isOpen() ) return false; return false; } -bool Wallet::create( QString file_path, QString brain_key ) +bool Wallet::create( QString file_path, QString password, QString brain_key ) { + if( isOpen() ) return false; + if( password == QString() ) return false; + + fc::path p( file_path.toStdString() ); + if( fc::exists( p ) ) + { + ilog( "Unable to create wallet file '${f}' because a file with that name already exists.", ("f",p) ); + return false; + } + + if( brain_key == QString() ) + { + auto key = fc::ecc::private_key::generate().get_secret(); + brain_key.fromStdString( fc::variant(key).as_string() ); + } + auto brainkey = brain_key.toStdString(); + auto pw_str = password.toStdString(); + + auto password_hash = fc::sha512::hash( pw_str.c_str(), pw_str.size() ); + _decrypted_master_key = fc::sha512::hash( fc::ecc::private_key::generate().get_secret() ); + _data.master_key_digest = fc::sha512::hash( _decrypted_master_key ); + _data.encrypted_master_key = fc::aes_encrypt( password_hash, fc::raw::pack(_decrypted_master_key) ); + + _data.brain_key_digest = fc::sha512::hash( brainkey.c_str(), brainkey.size() ); + _data.encrypted_brain_key = fc::aes_encrypt( _decrypted_master_key, fc::raw::pack( brainkey ) ); + + fc::json::save_to_file( _data, p ); + _wallet_file_path = p; + return false; } bool Wallet::loadBrainKey( QString brain_key ) { - return false; + if( !isOpen() ) return false; + + if( brain_key == QString() ) return false; + auto brainkey = brain_key.toStdString(); + + if( _data.brain_key_digest != fc::sha512::hash( brainkey.c_str(), brainkey.size() ) ) + return false; + + _brain_key = brain_key; + return true; } bool Wallet::purgeBrainKey() { - return false; + if( !isOpen() ) return false; + _data.encrypted_brain_key.resize(0); + _brain_key = QString(); + return save(); } bool Wallet::hasBrainKey()const { - return false; + if( !isOpen() ) return false; + return _brain_key != QString() || _data.encrypted_brain_key.size(); } -QString Wallet::getBrainKey()const +QString Wallet::getBrainKey() { - return QString(); + if( !isOpen() ) return QString(); + if( isLocked() ) return QString(); + + if( _brain_key != QString() ) + return _brain_key; + + auto dec_brain_key = fc::aes_decrypt( _decrypted_master_key, _data.encrypted_brain_key ); + auto dec_brain_key_str = fc::raw::unpack(dec_brain_key); + _brain_key.fromStdString( dec_brain_key_str ); + return _brain_key; } bool Wallet::isLocked()const { + if( !isOpen() ) return true; return false; } QString Wallet::unlock( QString password ) @@ -66,37 +138,46 @@ QString Wallet::unlock( QString password ) bool Wallet::lock() { - return false; + if( !isOpen() ) return false; + _brain_key = QString(); + _decrypted_master_key = fc::sha512(); + return true; } bool Wallet::changePassword( QString new_password ) { + if( !isOpen() ) return false; return false; } QString Wallet::getActivePrivateKey( QString owner_pub_key, uint32_t seq ) { + if( !isOpen() ) return QString(); return QString(); } QString Wallet::getOwnerPrivateKey( uint32_t seq ) { + if( !isOpen() ) return QString(); return QString(); } QString Wallet::getKeyLabel( QString pubkey ) { + if( !isOpen() ) return QString(); return QString(); } QString Wallet::getPublicKey( QString label ) { + if( !isOpen() ) return QString(); return QString(); } /** imports a public key and assigns it a label */ bool Wallet::importPublicKey( QString pubkey, QString label) { + if( !isOpen() ) return false; return false; } @@ -106,18 +187,21 @@ bool Wallet::importPublicKey( QString pubkey, QString label) **/ bool Wallet::importPrivateKey( QString wifkey, QString label ) { + if( !isOpen() ) return false; return false; } /** removes the key, its lablel and its private key */ bool Wallet::removePublicKey( QString pubkey ) { + if( !isOpen() ) return false; return false; } /** removes only the private key, keeping the public key and label */ bool Wallet::removePrivateKey( QString pubkey ) { + if( !isOpen() ) return false; return false; } diff --git a/programs/light_client/Wallet.hpp b/programs/light_client/Wallet.hpp index 3c229365..acc25838 100644 --- a/programs/light_client/Wallet.hpp +++ b/programs/light_client/Wallet.hpp @@ -23,14 +23,18 @@ FC_REFLECT( key_data, (label)(encrypted_private_key) ); struct wallet_file { - optional> encrypted_brain_key; - optional> encrypted_master_key; + vector encrypted_brain_key; + fc::sha512 brain_key_digest; + vector encrypted_master_key; + fc::sha512 master_key_digest; map encrypted_private_keys; }; FC_REFLECT( wallet_file, (encrypted_brain_key) + (brain_key_digest) (encrypted_master_key) + (master_key_digest) (encrypted_private_keys) ); @@ -49,9 +53,10 @@ class Wallet : public QObject Q_INVOKABLE bool open( QString file_path ); Q_INVOKABLE bool close(); + Q_INVOKABLE bool isOpen()const; Q_INVOKABLE bool save(); Q_INVOKABLE bool saveAs( QString file_path ); - Q_INVOKABLE bool create( QString file_path, QString brain_key = QString() ); + Q_INVOKABLE bool create( QString file_path, QString password, QString brain_key = QString() ); /** required to generate new owner keys */ Q_INVOKABLE bool loadBrainKey( QString brain_key ); @@ -61,7 +66,7 @@ class Wallet : public QObject Q_INVOKABLE bool hasBrainKey()const; /** @pre hasBrainKey() */ - Q_INVOKABLE QString getBrainKey()const; + Q_INVOKABLE QString getBrainKey(); Q_INVOKABLE bool isLocked()const; Q_INVOKABLE QString unlock( QString password ); @@ -113,9 +118,11 @@ class Wallet : public QObject private: fc::path _wallet_file_path; wallet_file _data; + /** used to decrypt all of the encrypted private keys */ fc::sha512 _decrypted_master_key; flat_set _available_private_keys; map _label_to_key; + QString _brain_key; };