Skip to content

Commit 513f7d3

Browse files
committed
Add storable_builder helper
1 parent d7cf864 commit 513f7d3

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@ pub mod error;
1919
/// Contains request/response types generated from the API definition of VSS.
2020
pub mod types;
2121

22+
/// Contains helper utils for encryption, requests-retries etc.
23+
pub mod util;
24+
2225
// Encryption-Decryption related crate-only helpers.
2326
pub(crate) mod crypto;

src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod storable_builder;

src/util/storable_builder.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use crate::crypto::chacha20poly1305::ChaCha20Poly1305;
2+
use crate::types::{EncryptionMetadata, PlaintextBlob, Storable};
3+
use ::prost::Message;
4+
use rand::rngs::ThreadRng;
5+
use rand::RngCore;
6+
use std::borrow::Borrow;
7+
use std::io;
8+
use std::io::{Error, ErrorKind};
9+
10+
pub struct StorableBuilder {
11+
data_encryption_key: [u8; 32],
12+
}
13+
14+
const CHACHA20_CIPHER_NAME: &'static str = "ChaCha20Poly1305";
15+
16+
impl StorableBuilder {
17+
pub fn build(&self, input: Vec<u8>, version: i64) -> Storable {
18+
let mut rng = ThreadRng::default();
19+
let mut nonce = [0u8; 12];
20+
rng.fill_bytes(&mut nonce[4..]);
21+
22+
let mut data_blob = PlaintextBlob { value: input, version }.encode_to_vec();
23+
24+
let mut cipher = ChaCha20Poly1305::new(&self.data_encryption_key, &nonce, &vec![]);
25+
let mut tag = [0u8; 16];
26+
cipher.encrypt_inplace(&mut data_blob, &mut tag);
27+
Storable {
28+
data: data_blob,
29+
encryption_metadata: Option::from(EncryptionMetadata {
30+
nonce: nonce.to_vec(),
31+
tag: tag.to_vec(),
32+
cipher_format: CHACHA20_CIPHER_NAME.to_string(),
33+
}),
34+
}
35+
}
36+
37+
pub fn deconstruct(&self, mut storable: Storable) -> io::Result<(Vec<u8>, i64)> {
38+
let encryption_metadata = storable.encryption_metadata.unwrap();
39+
let mut cipher = ChaCha20Poly1305::new(&self.data_encryption_key, &encryption_metadata.nonce, &vec![]);
40+
let input_output = storable.data.as_mut();
41+
42+
if cipher.decrypt_inplace(input_output, encryption_metadata.tag.borrow()) {
43+
let data_blob = PlaintextBlob::decode(&*input_output).map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
44+
Ok((data_blob.value, data_blob.version))
45+
} else {
46+
Err(Error::new(ErrorKind::InvalidData, "Invalid Tag"))
47+
}
48+
}
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
use rand::thread_rng;
55+
56+
#[test]
57+
fn encrypt_decrypt() {
58+
let mut rng = thread_rng();
59+
let mut data_key = [0u8; 32];
60+
rng.fill_bytes(&mut data_key);
61+
62+
let storable_builder = StorableBuilder { data_encryption_key: data_key };
63+
let expected_data = b"secret".to_vec();
64+
let expected_version = 8;
65+
let storable = storable_builder.build(expected_data.clone(), expected_version);
66+
67+
let (actual_data, actual_version) = storable_builder.deconstruct(storable).unwrap();
68+
assert_eq!(actual_data, expected_data);
69+
assert_eq!(actual_version, expected_version);
70+
}
71+
}

0 commit comments

Comments
 (0)