Skip to content

Commit ce7b3d0

Browse files
committed
Use KeyObfuscator in VssStore.
For client-side key obfuscation, improving privacy and security.
1 parent 06d0d2c commit ce7b3d0

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

src/builder.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,15 +466,19 @@ impl NodeBuilder {
466466

467467
let vss_seed_bytes: [u8; 32] = vss_xprv.private_key.secret_bytes();
468468

469-
let vss_store = Arc::new(VssStore::new(vss_url, store_id, vss_seed_bytes, header_provider));
469+
let vss_store =
470+
VssStore::new(vss_url, store_id, vss_seed_bytes, header_provider).map_err(|e| {
471+
log_error!(logger, "Failed to setup VssStore: {}", e);
472+
BuildError::KVStoreSetupFailed
473+
})?;
470474
build_with_store_internal(
471475
config,
472476
self.chain_data_source_config.as_ref(),
473477
self.gossip_source_config.as_ref(),
474478
self.liquidity_source_config.as_ref(),
475479
seed_bytes,
476480
logger,
477-
vss_store,
481+
Arc::new(vss_store),
478482
)
479483
}
480484

src/io/vss_store.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8+
use crate::io::utils::check_namespace_key_validity;
9+
use bitcoin::bip32::{ChildNumber, Xpriv};
10+
use bitcoin::secp256k1::Secp256k1;
11+
use bitcoin::Network;
812
use lightning::io::{self, Error, ErrorKind};
13+
use lightning::util::persist::KVStore;
14+
use prost::Message;
15+
use rand::RngCore;
916
#[cfg(test)]
1017
use std::panic::RefUnwindSafe;
1118
use std::sync::Arc;
1219
use std::time::Duration;
13-
14-
use crate::io::utils::check_namespace_key_validity;
15-
use lightning::util::persist::KVStore;
16-
use prost::Message;
17-
use rand::RngCore;
1820
use tokio::runtime::Runtime;
1921
use vss_client::client::VssClient;
2022
use vss_client::error::VssError;
@@ -23,6 +25,7 @@ use vss_client::types::{
2325
DeleteObjectRequest, GetObjectRequest, KeyValue, ListKeyVersionsRequest, PutObjectRequest,
2426
Storable,
2527
};
28+
use vss_client::util::key_obfuscator::KeyObfuscator;
2629
use vss_client::util::retry::{
2730
ExponentialBackoffRetryPolicy, FilteredRetryPolicy, JitteredRetryPolicy,
2831
MaxAttemptsRetryPolicy, MaxTotalDelayRetryPolicy, RetryPolicy,
@@ -42,14 +45,23 @@ pub struct VssStore {
4245
store_id: String,
4346
runtime: Runtime,
4447
storable_builder: StorableBuilder<RandEntropySource>,
48+
key_obfuscator: KeyObfuscator,
4549
}
50+
const DATA_ENCRYPTION_KEY_DERIVATION_INDEX: u32 = 1;
51+
const OBFUSCATION_KEY_DERIVATION_INDEX: u32 = 2;
4652

4753
impl VssStore {
4854
pub(crate) fn new(
49-
base_url: String, store_id: String, data_encryption_key: [u8; 32],
55+
base_url: String, store_id: String, vss_seed: [u8; 32],
5056
header_provider: Arc<dyn VssHeaderProvider>,
51-
) -> Self {
52-
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
57+
) -> io::Result<Self> {
58+
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
59+
let vss_master_xprv = Xpriv::new_master(Network::Bitcoin, &vss_seed).unwrap();
60+
let data_encryption_key =
61+
derive_hardened_key(&vss_master_xprv, DATA_ENCRYPTION_KEY_DERIVATION_INDEX)?;
62+
let obfuscation_master_key =
63+
derive_hardened_key(&vss_master_xprv, OBFUSCATION_KEY_DERIVATION_INDEX)?;
64+
let key_obfuscator = KeyObfuscator::new(obfuscation_master_key);
5365
let storable_builder = StorableBuilder::new(data_encryption_key, RandEntropySource);
5466
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100))
5567
.with_max_attempts(3)
@@ -65,24 +77,28 @@ impl VssStore {
6577
}) as _);
6678

6779
let client = VssClient::new_with_headers(base_url, retry_policy, header_provider);
68-
Self { client, store_id, runtime, storable_builder }
80+
Ok(Self { client, store_id, runtime, storable_builder, key_obfuscator })
6981
}
7082

7183
fn build_key(
7284
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
7385
) -> io::Result<String> {
86+
let obfuscated_key = self.key_obfuscator.obfuscate(key);
7487
if primary_namespace.is_empty() {
75-
Ok(key.to_string())
88+
Ok(obfuscated_key)
7689
} else {
77-
Ok(format!("{}#{}#{}", primary_namespace, secondary_namespace, key))
90+
Ok(format!("{}#{}#{}", primary_namespace, secondary_namespace, obfuscated_key))
7891
}
7992
}
8093

8194
fn extract_key(&self, unified_key: &str) -> io::Result<String> {
8295
let mut parts = unified_key.splitn(3, '#');
8396
let (_primary_namespace, _secondary_namespace) = (parts.next(), parts.next());
8497
match parts.next() {
85-
Some(actual_key) => Ok(actual_key.to_string()),
98+
Some(obfuscated_key) => {
99+
let actual_key = self.key_obfuscator.deobfuscate(obfuscated_key)?;
100+
Ok(actual_key)
101+
},
86102
None => Err(Error::new(ErrorKind::InvalidData, "Invalid key format")),
87103
}
88104
}
@@ -224,6 +240,20 @@ impl KVStore for VssStore {
224240
}
225241
}
226242

243+
fn derive_hardened_key(vss_seed: &Xpriv, index: u32) -> io::Result<[u8; 32]> {
244+
let derived_key_xprv = vss_seed
245+
.derive_priv(&Secp256k1::new(), &[ChildNumber::Hardened { index }])
246+
.map_err(|e| {
247+
let msg = format!(
248+
"Failed to derive an extended private key from VSS seed with index: {}, error: {}",
249+
index, e
250+
);
251+
Error::new(ErrorKind::Other, msg)
252+
})?;
253+
let derived_key = derived_key_xprv.private_key.secret_bytes();
254+
Ok(derived_key)
255+
}
256+
227257
/// A source for generating entropy/randomness using [`rand`].
228258
pub(crate) struct RandEntropySource;
229259

@@ -251,11 +281,11 @@ mod tests {
251281
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
252282
let mut rng = thread_rng();
253283
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
254-
let mut data_encryption_key = [0u8; 32];
255-
rng.fill_bytes(&mut data_encryption_key);
284+
let mut vss_seed = [0u8; 32];
285+
rng.fill_bytes(&mut vss_seed);
256286
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
257287
let vss_store =
258-
VssStore::new(vss_base_url, rand_store_id, data_encryption_key, header_provider);
288+
VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap();
259289

260290
do_read_write_remove_list_persist(&vss_store);
261291
}

0 commit comments

Comments
 (0)