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 } ;
810use lightning:: io:: { self , Error , ErrorKind } ;
11+ use lightning:: util:: persist:: KVStore ;
12+ use prost:: Message ;
13+ use rand:: RngCore ;
914#[ cfg( test) ]
1015use std:: panic:: RefUnwindSafe ;
1116use std:: sync:: Arc ;
1217use 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 ;
1818use tokio:: runtime:: Runtime ;
1919use vss_client:: client:: VssClient ;
2020use 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 ;
2627use 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
4749impl 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 > ,
51- ) -> Self {
52- let runtime = tokio:: runtime:: Builder :: new_multi_thread ( ) . enable_all ( ) . build ( ) . unwrap ( ) ;
53+ ) -> io:: Result < Self > {
54+ let runtime = tokio:: runtime:: Builder :: new_multi_thread ( ) . enable_all ( ) . build ( ) ?;
55+ let ( data_encryption_key, obfuscation_master_key) =
56+ derive_data_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 ( 10 ) )
5560 . with_max_attempts ( 10 )
@@ -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+ Ok ( 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+ fn derive_data_encryption_and_obfuscation_keys ( vss_seed : & [ u8 ; 32 ] ) -> ( [ u8 ; 32 ] , [ u8 ; 32 ] ) {
237+ let hkdf = |initial_key_material : & [ u8 ] , salt : & [ u8 ] | -> [ u8 ; 32 ] {
238+ let mut engine = HmacEngine :: < sha256:: Hash > :: new ( salt) ;
239+ engine. input ( initial_key_material) ;
240+ Hmac :: from_engine ( engine) . to_byte_array ( )
241+ } ;
242+
243+ let prk = hkdf ( vss_seed, b"pseudo_random_key" ) ;
244+ let k1 = hkdf ( & prk, b"data_encryption_key" ) ;
245+ let k2 = hkdf ( & prk, & [ & k1[ ..] , b"obfuscation_key" ] . concat ( ) ) ;
246+ ( k1, k2)
247+ }
248+
227249/// A source for generating entropy/randomness using [`rand`].
228250pub ( crate ) struct RandEntropySource ;
229251
@@ -251,11 +273,11 @@ 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 ( ) ) ) ;
257279 let vss_store =
258- VssStore :: new ( vss_base_url, rand_store_id, data_encryption_key , header_provider) ;
280+ VssStore :: new ( vss_base_url, rand_store_id, vss_seed , header_provider) . unwrap ( ) ;
259281
260282 do_read_write_remove_list_persist ( & vss_store) ;
261283 }
0 commit comments