Skip to content

Commit 5396a44

Browse files
committed
Use KeyObfuscator in VssStore.
For client-side key obfuscation, improving privacy and security.
1 parent d9c3f39 commit 5396a44

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

src/io/vss_store.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
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::hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine};
810
use lightning::io::{self, Error, ErrorKind};
11+
use lightning::util::persist::KVStore;
12+
use prost::Message;
13+
use rand::RngCore;
914
#[cfg(test)]
1015
use std::panic::RefUnwindSafe;
1116
use std::sync::Arc;
1217
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;
1818
use tokio::runtime::Runtime;
1919
use vss_client::client::VssClient;
2020
use vss_client::error::VssError;
@@ -23,6 +23,7 @@ use vss_client::types::{
2323
DeleteObjectRequest, GetObjectRequest, KeyValue, ListKeyVersionsRequest, PutObjectRequest,
2424
Storable,
2525
};
26+
use vss_client::util::key_obfuscator::KeyObfuscator;
2627
use vss_client::util::retry::{
2728
ExponentialBackoffRetryPolicy, FilteredRetryPolicy, JitteredRetryPolicy,
2829
MaxAttemptsRetryPolicy, MaxTotalDelayRetryPolicy, RetryPolicy,
@@ -42,14 +43,18 @@ pub struct VssStore {
4243
store_id: String,
4344
runtime: Runtime,
4445
storable_builder: StorableBuilder<RandEntropySource>,
46+
key_obfuscator: KeyObfuscator,
4547
}
4648

4749
impl VssStore {
4850
pub(crate) fn new(
49-
base_url: String, store_id: String, data_encryption_key: [u8; 32],
51+
base_url: String, store_id: String, vss_seed: [u8; 32],
5052
header_provider: Arc<dyn VssHeaderProvider>,
5153
) -> Self {
5254
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
55+
let (data_encryption_key, obfuscation_master_key) =
56+
derive_encryption_and_obfuscation_keys(&vss_seed);
57+
let key_obfuscator = KeyObfuscator::new(obfuscation_master_key);
5358
let storable_builder = StorableBuilder::new(data_encryption_key, RandEntropySource);
5459
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100))
5560
.with_max_attempts(3)
@@ -65,24 +70,28 @@ impl VssStore {
6570
}) as _);
6671

6772
let client = VssClient::new_with_headers(base_url, retry_policy, header_provider);
68-
Self { client, store_id, runtime, storable_builder }
73+
Self { client, store_id, runtime, storable_builder, key_obfuscator }
6974
}
7075

7176
fn build_key(
7277
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
7378
) -> io::Result<String> {
79+
let obfuscated_key = self.key_obfuscator.obfuscate(key);
7480
if primary_namespace.is_empty() {
75-
Ok(key.to_string())
81+
Ok(obfuscated_key)
7682
} else {
77-
Ok(format!("{}#{}#{}", primary_namespace, secondary_namespace, key))
83+
Ok(format!("{}#{}#{}", primary_namespace, secondary_namespace, obfuscated_key))
7884
}
7985
}
8086

8187
fn extract_key(&self, unified_key: &str) -> io::Result<String> {
8288
let mut parts = unified_key.splitn(3, '#');
8389
let (_primary_namespace, _secondary_namespace) = (parts.next(), parts.next());
8490
match parts.next() {
85-
Some(actual_key) => Ok(actual_key.to_string()),
91+
Some(obfuscated_key) => {
92+
let actual_key = self.key_obfuscator.deobfuscate(obfuscated_key)?;
93+
Ok(actual_key)
94+
},
8695
None => Err(Error::new(ErrorKind::InvalidData, "Invalid key format")),
8796
}
8897
}
@@ -224,6 +233,19 @@ impl KVStore for VssStore {
224233
}
225234
}
226235

236+
/// Derives the data encryption and obfuscation keys from the vss master key.
237+
fn derive_encryption_and_obfuscation_keys(vss_seed: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
238+
let prk = hkdf(vss_seed, "pseudo_random_key".as_bytes());
239+
let k1 = hkdf(&prk, "data_encryption_key".as_bytes());
240+
let k2 = hkdf(&prk, &[&k1[..], "obfuscation_master_key".as_bytes()].concat());
241+
(k1, k2)
242+
}
243+
fn hkdf(initial_key_material: &[u8], salt: &[u8]) -> [u8; 32] {
244+
let mut engine = HmacEngine::<sha256::Hash>::new(salt);
245+
engine.input(initial_key_material);
246+
Hmac::from_engine(engine).to_byte_array()
247+
}
248+
227249
/// A source for generating entropy/randomness using [`rand`].
228250
pub(crate) struct RandEntropySource;
229251

@@ -251,11 +273,10 @@ mod tests {
251273
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
252274
let mut rng = thread_rng();
253275
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);
276+
let mut vss_seed = [0u8; 32];
277+
rng.fill_bytes(&mut vss_seed);
256278
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
257-
let vss_store =
258-
VssStore::new(vss_base_url, rand_store_id, data_encryption_key, header_provider);
279+
let vss_store = VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider);
259280

260281
do_read_write_remove_list_persist(&vss_store);
261282
}

0 commit comments

Comments
 (0)