Skip to content

Commit 995ca70

Browse files
committed
Allow to set aad in StorableBuilder::{build,desconstruct}
Previously, we omitted setting `ChaCha20Poly1305RFC`'s `aad` field, which had the `tag` not commit to any particular key. This would allow a malicious VSS provider to substitute blobs stored under a different key without the client noticing. Here, we allow to set the `aad` (which usually should be the full key under which we expect the `Storable` to get stored). This change is backwards compatible if users provide a static `aad: &[]` argument. Otherwise, users will need to find an upgrade path client-side.
1 parent e2aab92 commit 995ca70

File tree

1 file changed

+36
-7
lines changed

1 file changed

+36
-7
lines changed

src/util/storable_builder.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,19 @@ const CHACHA20_CIPHER_NAME: &'static str = "ChaCha20Poly1305";
3434
impl<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

Comments
 (0)