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 > ,
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`].
228250pub ( 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