@@ -6,16 +6,16 @@ use std::io;
66use std:: io:: { Error , ErrorKind } ;
77
88/// [`StorableBuilder`] is a utility to build and deconstruct [`Storable`] objects.
9+ ///
910/// It provides client-side Encrypt-then-MAC using ChaCha20-Poly1305.
1011pub struct StorableBuilder < T : EntropySource > {
11- data_encryption_key : [ u8 ; 32 ] ,
1212 entropy_source : T ,
1313}
1414
1515impl < T : EntropySource > StorableBuilder < T > {
1616 /// Constructs a new instance.
17- pub fn new ( data_encryption_key : [ u8 ; 32 ] , entropy_source : T ) -> StorableBuilder < T > {
18- Self { data_encryption_key , entropy_source }
17+ pub fn new ( entropy_source : T ) -> StorableBuilder < T > {
18+ Self { entropy_source }
1919 }
2020}
2121
@@ -34,18 +34,21 @@ const CHACHA20_CIPHER_NAME: &'static str = "ChaCha20Poly1305";
3434impl < T : EntropySource > StorableBuilder < T > {
3535 /// Creates a [`Storable`] that can be serialized and stored as `value` in [`PutObjectRequest`].
3636 ///
37- /// Uses ChaCha20 for encrypting `input` and Poly1305 for generating a mac/tag.
37+ /// Uses ChaCha20 for encrypting `input` and Poly1305 for generating a mac/tag with associated
38+ /// data `aad` (usually the storage key).
3839 ///
3940 /// Refer to docs on [`Storable`] for more information.
4041 ///
4142 /// [`PutObjectRequest`]: crate::types::PutObjectRequest
42- pub fn build ( & self , input : Vec < u8 > , version : i64 ) -> Storable {
43+ pub fn build (
44+ & self , input : Vec < u8 > , version : i64 , data_encryption_key : & [ u8 ; 32 ] , aad : & [ u8 ] ,
45+ ) -> Storable {
4346 let mut nonce = vec ! [ 0u8 ; 12 ] ;
4447 self . entropy_source . fill_bytes ( & mut nonce[ 4 ..] ) ;
4548
4649 let mut data_blob = PlaintextBlob { value : input, version } . encode_to_vec ( ) ;
4750
48- let mut cipher = ChaCha20Poly1305 :: new ( & self . data_encryption_key , & nonce, & [ ] ) ;
51+ let mut cipher = ChaCha20Poly1305 :: new ( data_encryption_key, & nonce, aad ) ;
4952 let mut tag = vec ! [ 0u8 ; 16 ] ;
5053 cipher. encrypt_inplace ( & mut data_blob, & mut tag) ;
5154 Storable {
@@ -62,10 +65,14 @@ impl<T: EntropySource> StorableBuilder<T> {
6265 /// corresponding version as stored at the time of [`PutObjectRequest`].
6366 ///
6467 /// [`PutObjectRequest`]: crate::types::PutObjectRequest
65- pub fn deconstruct ( & self , mut storable : Storable ) -> io:: Result < ( Vec < u8 > , i64 ) > {
66- let encryption_metadata = storable. encryption_metadata . unwrap ( ) ;
68+ pub fn deconstruct (
69+ & self , mut storable : Storable , data_encryption_key : & [ u8 ; 32 ] , aad : & [ u8 ] ,
70+ ) -> io:: Result < ( Vec < u8 > , i64 ) > {
71+ let encryption_metadata = storable
72+ . encryption_metadata
73+ . ok_or_else ( || Error :: new ( ErrorKind :: InvalidData , "Invalid Metadata" ) ) ?;
6774 let mut cipher =
68- ChaCha20Poly1305 :: new ( & self . data_encryption_key , & encryption_metadata. nonce , & [ ] ) ;
75+ ChaCha20Poly1305 :: new ( data_encryption_key, & encryption_metadata. nonce , aad ) ;
6976
7077 cipher
7178 . decrypt_inplace ( & mut storable. data , encryption_metadata. tag . borrow ( ) )
@@ -97,16 +104,42 @@ mod tests {
97104 let test_entropy_provider = TestEntropyProvider ;
98105 let mut data_key = [ 0u8 ; 32 ] ;
99106 test_entropy_provider. fill_bytes ( & mut data_key) ;
100- let storable_builder = StorableBuilder {
101- data_encryption_key : data_key,
102- entropy_source : test_entropy_provider,
103- } ;
107+ let storable_builder = StorableBuilder :: new ( test_entropy_provider) ;
104108 let expected_data = b"secret" . to_vec ( ) ;
105109 let expected_version = 8 ;
106- let storable = storable_builder. build ( expected_data. clone ( ) , expected_version) ;
110+ let aad = b"A" ;
111+ let storable =
112+ storable_builder. build ( expected_data. clone ( ) , expected_version, & data_key, aad) ;
107113
108- let ( actual_data, actual_version) = storable_builder. deconstruct ( storable) . unwrap ( ) ;
114+ let ( actual_data, actual_version) =
115+ storable_builder. deconstruct ( storable, & data_key, aad) . unwrap ( ) ;
109116 assert_eq ! ( actual_data, expected_data) ;
110117 assert_eq ! ( actual_version, expected_version) ;
111118 }
119+
120+ #[ test]
121+ fn decrypt_key_mismatch_fails ( ) {
122+ let test_entropy_provider = TestEntropyProvider ;
123+ let mut data_key = [ 0u8 ; 32 ] ;
124+ test_entropy_provider. fill_bytes ( & mut data_key) ;
125+ let storable_builder = StorableBuilder :: new ( test_entropy_provider) ;
126+
127+ let expected_data_a = b"secret_a" . to_vec ( ) ;
128+ let expected_version_a = 8 ;
129+ let aad_a = b"A" ;
130+ let storable_a =
131+ storable_builder. build ( expected_data_a. clone ( ) , expected_version_a, & data_key, aad_a) ;
132+
133+ let expected_data_b = b"secret_b" . to_vec ( ) ;
134+ let expected_version_b = 8 ;
135+ let aad_b = b"B" ;
136+ let storable_b =
137+ storable_builder. build ( expected_data_b. clone ( ) , expected_version_b, & data_key, aad_b) ;
138+
139+ let ( actual_data, actual_version) =
140+ storable_builder. deconstruct ( storable_a, & data_key, aad_a) . unwrap ( ) ;
141+ assert_eq ! ( actual_data, expected_data_a) ;
142+ assert_eq ! ( actual_version, expected_version_a) ;
143+ assert ! ( storable_builder. deconstruct( storable_b, & data_key, aad_a) . is_err( ) ) ;
144+ }
112145}
0 commit comments