Skip to content

Commit

Permalink
[Floonet] Encrypt private slate data upon storage in DB (#2189)
Browse files Browse the repository at this point in the history
* xor encrypt stored nonce and blind sum in transaction data

* rustfmt

* stop doc tests splatting wallet files throughout
  • Loading branch information
yeastplume authored Dec 20, 2018
1 parent a422504 commit 7812a9e
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 6 deletions.
8 changes: 8 additions & 0 deletions wallet/src/libwallet/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ where
/// use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
///
/// let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
///
/// // A NodeClient must first be created to handle communication between
/// // the wallet and the node.
Expand Down Expand Up @@ -148,6 +149,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -203,6 +205,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -256,6 +259,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -313,6 +317,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -389,6 +394,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -462,6 +468,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down Expand Up @@ -575,6 +582,7 @@ where
/// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new(
Expand Down
66 changes: 60 additions & 6 deletions wallet/src/lmdb_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use serde_json;
use failure::ResultExt;
use uuid::Uuid;

use crate::blake2::blake2b::Blake2b;

use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
use crate::store::{self, option_to_not_found, to_key, to_key_u64};

Expand All @@ -35,6 +37,7 @@ use crate::libwallet::types::*;
use crate::libwallet::{internal, Error, ErrorKind};
use crate::types::{WalletConfig, WalletSeed};
use crate::util;
use crate::util::secp::constants::SECRET_KEY_SIZE;
use crate::util::secp::pedersen;

pub const DB_DIR: &'static str = "db";
Expand Down Expand Up @@ -62,6 +65,39 @@ pub fn wallet_db_exists(config: WalletConfig) -> bool {
db_path.exists()
}

/// Helper to derive XOR keys for storing private transaction keys in the DB
/// (blind_xor_key, nonce_xor_key)
fn private_ctx_xor_keys<K>(
keychain: &K,
slate_id: &[u8],
) -> Result<([u8; SECRET_KEY_SIZE], [u8; SECRET_KEY_SIZE]), Error>
where
K: Keychain,
{
let root_key = keychain.derive_key(0, &K::root_key_id())?;

// derive XOR values for storing secret values in DB
// h(root_key|slate_id|"blind")
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
hasher.update(&root_key.0[..]);
hasher.update(&slate_id[..]);
hasher.update(&"blind".as_bytes()[..]);
let blind_xor_key = hasher.finalize();
let mut ret_blind = [0; SECRET_KEY_SIZE];
ret_blind.copy_from_slice(&blind_xor_key.as_bytes()[0..SECRET_KEY_SIZE]);

// h(root_key|slate_id|"nonce")
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
hasher.update(&root_key.0[..]);
hasher.update(&slate_id[..]);
hasher.update(&"nonce".as_bytes()[..]);
let nonce_xor_key = hasher.finalize();
let mut ret_nonce = [0; SECRET_KEY_SIZE];
ret_nonce.copy_from_slice(&nonce_xor_key.as_bytes()[0..SECRET_KEY_SIZE]);

Ok((ret_blind, ret_nonce))
}

pub struct LMDBBackend<C, K> {
db: store::Store,
config: WalletConfig,
Expand Down Expand Up @@ -232,11 +268,19 @@ where

fn get_private_context(&mut self, slate_id: &[u8]) -> Result<Context, Error> {
let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec());
option_to_not_found(
let (blind_xor_key, nonce_xor_key) = private_ctx_xor_keys(self.keychain(), slate_id)?;

let mut ctx: Context = option_to_not_found(
self.db.get_ser(&ctx_key),
&format!("Slate id: {:x?}", slate_id.to_vec()),
)
.map_err(|e| e.into())
)?;

for i in 0..SECRET_KEY_SIZE {
ctx.sec_key.0[i] = ctx.sec_key.0[i] ^ blind_xor_key[i];
ctx.sec_nonce.0[i] = ctx.sec_nonce.0[i] ^ nonce_xor_key[i];
}

Ok(ctx)
}

fn acct_path_iter<'a>(&'a self) -> Box<dyn Iterator<Item = AcctPathMapping> + 'a> {
Expand Down Expand Up @@ -501,11 +545,21 @@ where
self.save(out.clone())
}

//TODO: Keys stored unencrypted in DB.. not good
// should store keys as derivation paths instead
fn save_private_context(&mut self, slate_id: &[u8], ctx: &Context) -> Result<(), Error> {
let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec());
self.db.borrow().as_ref().unwrap().put_ser(&ctx_key, &ctx)?;
let (blind_xor_key, nonce_xor_key) = private_ctx_xor_keys(self.keychain(), slate_id)?;

let mut s_ctx = ctx.clone();
for i in 0..SECRET_KEY_SIZE {
s_ctx.sec_key.0[i] = s_ctx.sec_key.0[i] ^ blind_xor_key[i];
s_ctx.sec_nonce.0[i] = s_ctx.sec_nonce.0[i] ^ nonce_xor_key[i];
}

self.db
.borrow()
.as_ref()
.unwrap()
.put_ser(&ctx_key, &s_ctx)?;
Ok(())
}

Expand Down

0 comments on commit 7812a9e

Please sign in to comment.