Skip to content

Commit 823e002

Browse files
committed
feat!: wallet always encrypted
1 parent 434fe5d commit 823e002

2 files changed

Lines changed: 53 additions & 99 deletions

File tree

wallet/src/bmp_wallet.rs

Lines changed: 32 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -320,15 +320,14 @@ impl ProtocolWalletApi for BMPWallet<Connection> {
320320
}
321321
pub trait WalletApi {
322322
const DB_NAME: &str;
323-
const ENC_DB_NAME: &str;
324323
const SEEDS_TABLE_NAME: &'static str;
325324
const IMPORTED_KEYS_TABLE_NAME: &'static str;
326325

327-
fn new(network: Network) -> anyhow::Result<Self>
326+
fn new(password: &str, network: Network) -> anyhow::Result<Self>
328327
where
329328
Self: Sized;
330329

331-
fn load_wallet(network: Network, password: Option<&str>) -> anyhow::Result<Self>
330+
fn load_wallet(network: Network, password: &str) -> anyhow::Result<Self>
332331
where
333332
Self: Sized;
334333

@@ -339,7 +338,6 @@ pub trait WalletApi {
339338

340339
fn balance(&self) -> Amount;
341340

342-
fn encrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>>;
343341
fn decrypt(&self, password: &str) -> anyhow::Result<()>;
344342

345343
fn persist(&mut self) -> anyhow::Result<bool>;
@@ -371,7 +369,6 @@ impl WalletApi for BMPWallet<Connection> {
371369
const SEEDS_TABLE_NAME: &'static str = "bmp_seeds";
372370
const IMPORTED_KEYS_TABLE_NAME: &'static str = "bmp_imported_keys";
373371
const DB_NAME: &str = "bmp_bdk_wallet.db3";
374-
const ENC_DB_NAME: &str = "bmp_bdk_encrypted.db3";
375372

376373
fn persist(&mut self) -> anyhow::Result<bool> {
377374
// Persist imported keys and then persist staged changes from ChangeSet
@@ -590,7 +587,7 @@ impl WalletApi for BMPWallet<Connection> {
590587
self.persist()
591588
}
592589

593-
fn new(network: Network) -> anyhow::Result<Self>
590+
fn new(password: &str, network: Network) -> anyhow::Result<Self>
594591
where
595592
Self: Sized,
596593
{
@@ -610,6 +607,14 @@ impl WalletApi for BMPWallet<Connection> {
610607

611608
let mut db = Connection::new(Self::DB_NAME)?;
612609

610+
// Derive encryption key
611+
let salt_path = format!("{}.salt", Self::DB_NAME);
612+
let mut salt = [0u8; 16];
613+
rand::rng().fill_bytes(&mut salt);
614+
fs::write(&salt_path, general_purpose::STANDARD.encode(salt))?;
615+
let enc_key = derive_key_from_password(password, &salt)?;
616+
db.pragma_update(None, "key", enc_key)?;
617+
613618
let wallet = Wallet::create(descriptor, change_descriptor)
614619
.network(network)
615620
.keymap(KeychainKind::External, external_map)
@@ -637,16 +642,11 @@ impl WalletApi for BMPWallet<Connection> {
637642

638643
// For already created wallets this will load stored data
639644
// This will also load the imported keys
640-
fn load_wallet(network: Network, password: Option<&str>) -> anyhow::Result<Self> {
641-
let mut db = if let Some(password) = password {
642-
let salt = get_salt(Self::DB_NAME)?;
643-
let decrypt_key = derive_key_from_password(password, &salt)?;
644-
let conn = Connection::open(Self::ENC_DB_NAME)?;
645-
conn.pragma_update(None, "key", decrypt_key)?;
646-
conn
647-
} else {
648-
Connection::open(Self::DB_NAME)?
649-
};
645+
fn load_wallet(network: Network, password: &str) -> anyhow::Result<Self> {
646+
let salt = get_salt(Self::DB_NAME)?;
647+
let decrypt_key = derive_key_from_password(password, &salt)?;
648+
let mut db = Connection::open(Self::DB_NAME)?;
649+
db.pragma_update(None, "key", decrypt_key)?;
650650

651651
let wallet_opt = Wallet::load().check_network(network).load_wallet(&mut db)?;
652652

@@ -698,37 +698,6 @@ impl WalletApi for BMPWallet<Connection> {
698698
Ok(())
699699
}
700700

701-
fn encrypt(self, password: &str) -> anyhow::Result<BMPWallet<Connection>> {
702-
// Derive encryption key from password
703-
let salt_path = format!("{}.salt", Self::DB_NAME);
704-
705-
let mut salt = [0u8; 16];
706-
rand::rng().fill_bytes(&mut salt);
707-
708-
fs::write(&salt_path, general_purpose::STANDARD.encode(salt))?;
709-
let enc_key = derive_key_from_password(password, &salt)?;
710-
711-
let encrypted_conn = Connection::open(Self::ENC_DB_NAME)?;
712-
encrypted_conn.pragma_update(None, "key", &enc_key)?;
713-
714-
let mut sql = format!(
715-
"ATTACH DATABASE '{}' AS encrypted_db KEY '{}';",
716-
Self::ENC_DB_NAME, enc_key
717-
);
718-
sql += " SELECT sqlcipher_export('encrypted_db'); DETACH DATABASE encrypted_db;";
719-
720-
self.db.execute_batch(&sql)?;
721-
fs::remove_file(Self::DB_NAME)?;
722-
723-
Ok(Self {
724-
wallet: self.wallet,
725-
imported_keys: self.imported_keys,
726-
imported_balance: self.imported_balance,
727-
signers_loaded: false,
728-
db: encrypted_conn,
729-
})
730-
}
731-
732701
fn drain_imported_balance(&mut self, fee_rate: FeeRate) -> anyhow::Result<Psbt> {
733702
let drain_to_address = self.next_address(KeychainKind::Internal)?;
734703
let imported_balance = self.imported_balance.trusted_spendable();
@@ -821,7 +790,7 @@ mod tests {
821790
let _permit = SEMAPHORE.acquire();
822791
let _tmp_dir = tear_up();
823792

824-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
793+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
825794
assert_eq!(bmp_wallet.imported_keys.len(), 0);
826795
assert_eq!(bmp_wallet.balance(), Amount::from_sat(0));
827796

@@ -860,7 +829,7 @@ mod tests {
860829
let last_generated_addr: AddressInfo;
861830

862831
{
863-
let mut wallet = BMPWallet::new(Network::Regtest)?;
832+
let mut wallet = BMPWallet::new("", Network::Regtest)?;
864833
assert_eq!(wallet.imported_keys.len(), 0);
865834
stored_balance = wallet.balance();
866835
stored_seed = wallet.get_seed_phrase().unwrap();
@@ -882,7 +851,7 @@ mod tests {
882851
wallet.persist()?;
883852
}
884853

885-
let mut wallet = BMPWallet::load_wallet(Network::Regtest, None)?;
854+
let mut wallet = BMPWallet::load_wallet(Network::Regtest, "")?;
886855
let loaded_seed = wallet.get_seed_phrase()?;
887856

888857
let new_receiving_addr = wallet.get_new_address()?;
@@ -902,7 +871,7 @@ mod tests {
902871
let _permit = SEMAPHORE.acquire();
903872
let _tmp_dir = tear_up();
904873

905-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
874+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
906875
let pk1 = new_private_key();
907876
let pk2 = new_private_key();
908877

@@ -914,7 +883,7 @@ mod tests {
914883
// Persist
915884
bmp_wallet.persist()?;
916885

917-
let loaded_wallet = BMPWallet::load_wallet(Network::Regtest, None)?;
886+
let loaded_wallet = BMPWallet::load_wallet(Network::Regtest, "")?;
918887

919888
assert_eq!(loaded_wallet.imported_keys, bmp_wallet.imported_keys);
920889
Ok(())
@@ -925,7 +894,7 @@ mod tests {
925894
let _permit = SEMAPHORE.acquire();
926895
let _tmp_dir = tear_up();
927896

928-
let mut bmp_wallet = BMPWallet::new(Network::Bitcoin)?;
897+
let mut bmp_wallet = BMPWallet::new("", Network::Bitcoin)?;
929898
let client = MockedBDKElectrum {};
930899

931900
tracing::info!("Wallet balance before syncing {}", bmp_wallet.balance());
@@ -949,7 +918,7 @@ mod tests {
949918
let pk1 = new_private_key();
950919
let pk2 = new_private_key();
951920

952-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
921+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
953922

954923
bmp_wallet.import_private_key(pk1);
955924
bmp_wallet.import_private_key(pk2);
@@ -975,7 +944,7 @@ mod tests {
975944
let _tmp_dir = tear_up();
976945

977946
let client = MockedBDKElectrum {};
978-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
947+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
979948

980949
tracing::info!("Wallet balance before syncing {}", bmp_wallet.balance());
981950
assert_eq!(bmp_wallet.balance(), Amount::from_int_btc(0));
@@ -1009,7 +978,7 @@ mod tests {
1009978
let _tmp_dir = tear_up();
1010979

1011980
let client = MockedBDKElectrum {};
1012-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
981+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
1013982

1014983
let keys_to_import = [new_private_key(), new_private_key()];
1015984
keys_to_import
@@ -1079,7 +1048,7 @@ mod tests {
10791048
let _tmp_dir = tear_up();
10801049

10811050
let client = MockedBDKElectrum {};
1082-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
1051+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
10831052

10841053
let pk1: [u8; 32] = [
10851054
180, 143, 139, 78, 9, 248, 73, 139, 169, 173, 99, 191, 248, 54, 50, 207, 137, 222, 85,
@@ -1117,27 +1086,22 @@ mod tests {
11171086
}
11181087

11191088
#[test]
1120-
#[should_panic = "value: file is not a database"]
1089+
#[should_panic = "file is not a database"]
11211090
fn encrypted_wallet() {
11221091
let _permit = SEMAPHORE.acquire();
11231092
let _tmp_dir = tear_up();
11241093

1125-
let bmp_wallet = BMPWallet::new(Network::Regtest).unwrap();
1126-
// bmp_wallet database is unencrypted by default, reading from it should be fine
1094+
let bmp_wallet = BMPWallet::new("secret12", Network::Regtest).unwrap();
11271095
let seed = bmp_wallet.get_seed_phrase().unwrap();
11281096

11291097
assert!(!seed.is_empty());
11301098
assert_eq!(seed.split_whitespace().count(), 24);
11311099

1132-
// Encrypt the wallet
1133-
let enc_wallet = bmp_wallet.encrypt("secret123").unwrap();
1134-
let seed = enc_wallet.get_seed_phrase().unwrap();
1135-
11361100
assert!(!seed.is_empty());
11371101
assert_eq!(seed.split_whitespace().count(), 24);
11381102

11391103
// Try loading the wallet with wrong decryption key should panic
1140-
let lw = BMPWallet::load_wallet(Network::Regtest, Some("secet123")).unwrap();
1104+
let lw = BMPWallet::load_wallet(Network::Regtest, "secret123").unwrap();
11411105
lw.get_seed_phrase().unwrap();
11421106
}
11431107

@@ -1146,22 +1110,17 @@ mod tests {
11461110
let _permit = SEMAPHORE.acquire();
11471111
let _tmp_dir = tear_up();
11481112

1149-
let bmp_wallet = BMPWallet::new(Network::Regtest).unwrap();
1150-
// bmp_wallet database is unencrypted by default, reading from it should be fine
1113+
let bmp_wallet = BMPWallet::new("secret123", Network::Regtest).unwrap();
11511114
let seed = bmp_wallet.get_seed_phrase().unwrap();
11521115

11531116
assert!(!seed.is_empty());
11541117
assert_eq!(seed.split_whitespace().count(), 24);
11551118

1156-
// Encrypt the wallet and then decrypt and try reading from it
1157-
let enc_wallet = bmp_wallet.encrypt("secret123").unwrap();
1158-
let seed = enc_wallet.get_seed_phrase().unwrap();
1159-
11601119
assert!(!seed.is_empty());
11611120
assert_eq!(seed.split_whitespace().count(), 24);
11621121

11631122
// Load the wallet with right decryption key
1164-
let lw = BMPWallet::load_wallet(Network::Regtest, Some("secret123")).unwrap();
1123+
let lw = BMPWallet::load_wallet(Network::Regtest, "secret123").unwrap();
11651124

11661125
assert_eq!(lw.get_seed_phrase().unwrap(), seed);
11671126
}
@@ -1174,7 +1133,7 @@ mod tests {
11741133
let pk1 = new_private_key();
11751134
let pk2 = new_private_key();
11761135

1177-
let mut bmp_wallet = BMPWallet::new(Network::Regtest)?;
1136+
let mut bmp_wallet = BMPWallet::new("", Network::Regtest)?;
11781137

11791138
bmp_wallet.import_private_key(pk1);
11801139
bmp_wallet.import_private_key(pk2);

0 commit comments

Comments
 (0)