@@ -34,18 +34,19 @@ 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 ( & self , input : Vec < u8 > , version : i64 , aad : & [ u8 ] ) -> Storable {
4344 let mut nonce = vec ! [ 0u8 ; 12 ] ;
4445 self . entropy_source . fill_bytes ( & mut nonce[ 4 ..] ) ;
4546
4647 let mut data_blob = PlaintextBlob { value : input, version } . encode_to_vec ( ) ;
4748
48- let mut cipher = ChaCha20Poly1305 :: new ( & self . data_encryption_key , & nonce, & [ ] ) ;
49+ let mut cipher = ChaCha20Poly1305 :: new ( & self . data_encryption_key , & nonce, aad ) ;
4950 let mut tag = vec ! [ 0u8 ; 16 ] ;
5051 cipher. encrypt_inplace ( & mut data_blob, & mut tag) ;
5152 Storable {
@@ -62,10 +63,10 @@ impl<T: EntropySource> StorableBuilder<T> {
6263 /// corresponding version as stored at the time of [`PutObjectRequest`].
6364 ///
6465 /// [`PutObjectRequest`]: crate::types::PutObjectRequest
65- pub fn deconstruct ( & self , mut storable : Storable ) -> io:: Result < ( Vec < u8 > , i64 ) > {
66+ pub fn deconstruct ( & self , mut storable : Storable , aad : & [ u8 ] ) -> io:: Result < ( Vec < u8 > , i64 ) > {
6667 let encryption_metadata = storable. encryption_metadata . unwrap ( ) ;
6768 let mut cipher =
68- ChaCha20Poly1305 :: new ( & self . data_encryption_key , & encryption_metadata. nonce , & [ ] ) ;
69+ ChaCha20Poly1305 :: new ( & self . data_encryption_key , & encryption_metadata. nonce , aad ) ;
6970
7071 cipher
7172 . decrypt_inplace ( & mut storable. data , encryption_metadata. tag . borrow ( ) )
@@ -103,10 +104,38 @@ mod tests {
103104 } ;
104105 let expected_data = b"secret" . to_vec ( ) ;
105106 let expected_version = 8 ;
106- let storable = storable_builder. build ( expected_data. clone ( ) , expected_version) ;
107+ let aad = b"A" ;
108+ let storable = storable_builder. build ( expected_data. clone ( ) , expected_version, aad) ;
107109
108- let ( actual_data, actual_version) = storable_builder. deconstruct ( storable) . unwrap ( ) ;
110+ let ( actual_data, actual_version) = storable_builder. deconstruct ( storable, aad ) . unwrap ( ) ;
109111 assert_eq ! ( actual_data, expected_data) ;
110112 assert_eq ! ( actual_version, expected_version) ;
111113 }
114+
115+ #[ test]
116+ fn decrypt_key_mismatch_fails ( ) {
117+ let test_entropy_provider = TestEntropyProvider ;
118+ let mut data_key = [ 0u8 ; 32 ] ;
119+ test_entropy_provider. fill_bytes ( & mut data_key) ;
120+ let storable_builder = StorableBuilder {
121+ data_encryption_key : data_key,
122+ entropy_source : test_entropy_provider,
123+ } ;
124+
125+ let expected_data_a = b"secret_a" . to_vec ( ) ;
126+ let expected_version_a = 8 ;
127+ let aad_a = b"A" ;
128+ let storable_a = storable_builder. build ( expected_data_a. clone ( ) , expected_version_a, aad_a) ;
129+
130+ let expected_data_b = b"secret_b" . to_vec ( ) ;
131+ let expected_version_b = 8 ;
132+ let aad_b = b"B" ;
133+ let storable_b = storable_builder. build ( expected_data_b. clone ( ) , expected_version_b, aad_b) ;
134+
135+ let ( actual_data, actual_version) =
136+ storable_builder. deconstruct ( storable_a, aad_a) . unwrap ( ) ;
137+ assert_eq ! ( actual_data, expected_data_a) ;
138+ assert_eq ! ( actual_version, expected_version_a) ;
139+ assert ! ( storable_builder. deconstruct( storable_b, aad_a) . is_err( ) ) ;
140+ }
112141}
0 commit comments