vss_client/util/
storable_builder.rs1use crate::crypto::chacha20poly1305::ChaCha20Poly1305;
2use crate::types::{EncryptionMetadata, PlaintextBlob, Storable};
3use ::prost::Message;
4use std::borrow::Borrow;
5use std::io;
6use std::io::{Error, ErrorKind};
7
8pub struct StorableBuilder<T: EntropySource> {
11 data_encryption_key: [u8; 32],
12 entropy_source: T,
13}
14
15impl<T: EntropySource> StorableBuilder<T> {
16 pub fn new(data_encryption_key: [u8; 32], entropy_source: T) -> StorableBuilder<T> {
18 Self { data_encryption_key, entropy_source }
19 }
20}
21
22pub trait EntropySource {
24 fn fill_bytes(&self, buffer: &mut [u8]);
30}
31
32const CHACHA20_CIPHER_NAME: &'static str = "ChaCha20Poly1305";
33
34impl<T: EntropySource> StorableBuilder<T> {
35 pub fn build(&self, input: Vec<u8>, version: i64) -> Storable {
43 let mut nonce = vec![0u8; 12];
44 self.entropy_source.fill_bytes(&mut nonce[4..]);
45
46 let mut data_blob = PlaintextBlob { value: input, version }.encode_to_vec();
47
48 let mut cipher = ChaCha20Poly1305::new(&self.data_encryption_key, &nonce, &[]);
49 let mut tag = vec![0u8; 16];
50 cipher.encrypt_inplace(&mut data_blob, &mut tag);
51 Storable {
52 data: data_blob,
53 encryption_metadata: Some(EncryptionMetadata {
54 nonce,
55 tag,
56 cipher_format: CHACHA20_CIPHER_NAME.to_string(),
57 }),
58 }
59 }
60
61 pub fn deconstruct(&self, mut storable: Storable) -> io::Result<(Vec<u8>, i64)> {
66 let encryption_metadata = storable.encryption_metadata.unwrap();
67 let mut cipher =
68 ChaCha20Poly1305::new(&self.data_encryption_key, &encryption_metadata.nonce, &[]);
69
70 cipher
71 .decrypt_inplace(&mut storable.data, encryption_metadata.tag.borrow())
72 .map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid Tag"))?;
73
74 let data_blob = PlaintextBlob::decode(&storable.data[..])
75 .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
76 Ok((data_blob.value, data_blob.version))
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 pub struct TestEntropyProvider;
85 impl EntropySource for TestEntropyProvider {
86 fn fill_bytes(&self, buffer: &mut [u8]) {
89 for (i, byte) in buffer.iter_mut().enumerate() {
90 *byte = (i % 256) as u8;
91 }
92 }
93 }
94
95 #[test]
96 fn encrypt_decrypt() {
97 let test_entropy_provider = TestEntropyProvider;
98 let mut data_key = [0u8; 32];
99 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 };
104 let expected_data = b"secret".to_vec();
105 let expected_version = 8;
106 let storable = storable_builder.build(expected_data.clone(), expected_version);
107
108 let (actual_data, actual_version) = storable_builder.deconstruct(storable).unwrap();
109 assert_eq!(actual_data, expected_data);
110 assert_eq!(actual_version, expected_version);
111 }
112}