Skip to content

Commit 434fe5d

Browse files
committed
feat: allow convenient decrypt function
1 parent de5e5ac commit 434fe5d

2 files changed

Lines changed: 27 additions & 32 deletions

File tree

wallet/src/bmp_wallet.rs

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ impl ProtocolWalletApi for BMPWallet<Connection> {
319319
}
320320
}
321321
pub trait WalletApi {
322-
const DB_PATH: &str;
322+
const DB_NAME: &str;
323+
const ENC_DB_NAME: &str;
323324
const SEEDS_TABLE_NAME: &'static str;
324325
const IMPORTED_KEYS_TABLE_NAME: &'static str;
325326

@@ -339,7 +340,7 @@ pub trait WalletApi {
339340
fn balance(&self) -> Amount;
340341

341342
fn encrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>>;
342-
fn decrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>>;
343+
fn decrypt(&self, password: &str) -> anyhow::Result<()>;
343344

344345
fn persist(&mut self) -> anyhow::Result<bool>;
345346

@@ -369,7 +370,8 @@ pub trait WalletApi {
369370
impl WalletApi for BMPWallet<Connection> {
370371
const SEEDS_TABLE_NAME: &'static str = "bmp_seeds";
371372
const IMPORTED_KEYS_TABLE_NAME: &'static str = "bmp_imported_keys";
372-
const DB_PATH: &str = "bmp_bdk_wallet.db3";
373+
const DB_NAME: &str = "bmp_bdk_wallet.db3";
374+
const ENC_DB_NAME: &str = "bmp_bdk_encrypted.db3";
373375

374376
fn persist(&mut self) -> anyhow::Result<bool> {
375377
// Persist imported keys and then persist staged changes from ChangeSet
@@ -606,7 +608,7 @@ impl WalletApi for BMPWallet<Connection> {
606608
.build(network)
607609
.expect("Internal description generation should not fail");
608610

609-
let mut db = Connection::new(Self::DB_PATH)?;
611+
let mut db = Connection::new(Self::DB_NAME)?;
610612

611613
let wallet = Wallet::create(descriptor, change_descriptor)
612614
.network(network)
@@ -637,13 +639,13 @@ impl WalletApi for BMPWallet<Connection> {
637639
// This will also load the imported keys
638640
fn load_wallet(network: Network, password: Option<&str>) -> anyhow::Result<Self> {
639641
let mut db = if let Some(password) = password {
640-
let salt = get_salt(Self::DB_PATH)?;
642+
let salt = get_salt(Self::DB_NAME)?;
641643
let decrypt_key = derive_key_from_password(password, &salt)?;
642-
let conn = Connection::open(Self::DB_PATH)?;
644+
let conn = Connection::open(Self::ENC_DB_NAME)?;
643645
conn.pragma_update(None, "key", decrypt_key)?;
644646
conn
645647
} else {
646-
Connection::open(Self::DB_PATH)?
648+
Connection::open(Self::DB_NAME)?
647649
};
648650

649651
let wallet_opt = Wallet::load().check_network(network).load_wallet(&mut db)?;
@@ -684,47 +686,39 @@ impl WalletApi for BMPWallet<Connection> {
684686
Connection::get_seed_phrase(&self.db, Self::SEEDS_TABLE_NAME)
685687
}
686688

687-
fn decrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>> {
688-
let salt = get_salt(Self::DB_PATH)?;
689-
689+
/// The decryption is done on the active connection which holds the decryption key in memory.
690+
/// Without setting the right `pragma` value when connected to the database, an attacker
691+
/// will not be able to access the database. Even when the active connection has decrypted the
692+
/// file, on file system the database is still encrypted and can't be accessed.
693+
/// The decryption is done only to the active connection
694+
fn decrypt(&self, password: &str) -> anyhow::Result<()> {
695+
let salt = get_salt(Self::DB_NAME)?;
690696
let decrypt_key = derive_key_from_password(password, &salt)?;
691-
692-
let encrypted_conn = Connection::open(Self::DB_PATH)?;
693-
encrypted_conn.pragma_update(None, "key", decrypt_key)?;
694-
695-
Ok(Self {
696-
wallet: self.wallet,
697-
imported_keys: self.imported_keys,
698-
imported_balance: self.imported_balance,
699-
signers_loaded: false,
700-
db: encrypted_conn,
701-
})
697+
self.db.pragma_update(None, "key", &decrypt_key)?;
698+
Ok(())
702699
}
703700

704701
fn encrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>> {
705702
// Derive encryption key from password
706-
let salt_path = format!("{}.salt", Self::DB_PATH);
703+
let salt_path = format!("{}.salt", Self::DB_NAME);
707704

708705
let mut salt = [0u8; 16];
709706
rand::rng().fill_bytes(&mut salt);
710707

711708
fs::write(&salt_path, general_purpose::STANDARD.encode(salt))?;
712709
let enc_key = derive_key_from_password(password, &salt)?;
713710

714-
let encrypted_conn = Connection::open("bmp_encrypted.db3")?;
711+
let encrypted_conn = Connection::open(Self::ENC_DB_NAME)?;
715712
encrypted_conn.pragma_update(None, "key", &enc_key)?;
716713

717714
let mut sql = format!(
718715
"ATTACH DATABASE '{}' AS encrypted_db KEY '{}';",
719-
"bmp_encrypted.db3", enc_key
716+
Self::ENC_DB_NAME, enc_key
720717
);
721718
sql += " SELECT sqlcipher_export('encrypted_db'); DETACH DATABASE encrypted_db;";
722719

723720
self.db.execute_batch(&sql)?;
724-
725-
// Rename the bmp_encrypted.db3 to bmp_wallet.db3
726-
fs::remove_file(Self::DB_PATH)?;
727-
fs::rename("bmp_encrypted.db3", Self::DB_PATH)?;
721+
fs::remove_file(Self::DB_NAME)?;
728722

729723
Ok(Self {
730724
wallet: self.wallet,

wallet/tests/wallet_integration_test.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,9 @@ fn test_broadcast_transaction_three() -> anyhow::Result<()> {
197197
assert_eq!(wallet.balance(), new_balance);
198198

199199
// Reload the wallet by encrypting it to make sure the state changes are persisted
200-
let enc_wallet = wallet.encrypt("hello")?;
201-
let mut enc_wallet = enc_wallet.decrypt("hello")?;
200+
let mut enc_wallet = wallet.encrypt("hello")?;
201+
enc_wallet.decrypt("hello")?;
202+
202203
env.fund_address(&main_wallet_addr, Amount::from_sat(10_000))?;
203204
env.mine_block()?;
204205
enc_wallet.sync_all(data_source)?;
@@ -308,8 +309,8 @@ async fn test_cbf_persistence() -> anyhow::Result<()> {
308309
assert_eq!(loaded_wallet.balance(), Amount::from_sat(230_000));
309310

310311
// Encrypt the wallet then reload it and check for balance state
311-
let encrypted_wallet = loaded_wallet.encrypt("secret123")?;
312-
let mut encrypted_wallet = encrypted_wallet.decrypt("secret123")?;
312+
let mut encrypted_wallet = loaded_wallet.encrypt("secret123")?;
313+
encrypted_wallet.decrypt("secret123")?;
313314

314315
env.fund_address(&addr, Amount::from_sat(70_000))?;
315316
env.mine_block()?;

0 commit comments

Comments
 (0)