lightning_storage_server/
util.rs1#[cfg(feature = "crypt")]
2use crate::chacha20::ChaCha20;
3use crate::Value;
4use bitcoin_hashes::sha256::Hash as Sha256Hash;
5use bitcoin_hashes::{Hash, HashEngine, Hmac, HmacEngine};
6use log::error;
7
8pub fn prepare_value_for_put(secret: &[u8], key: &str, value: &mut Value) {
9 append_hmac_to_value(secret, key, value.version, &mut value.value);
10 #[cfg(feature = "crypt")]
11 crypt_value(secret, key, value.version, &mut value.value);
12}
13
14pub fn append_hmac_to_value(secret: &[u8], key: &str, version: i64, value: &mut Vec<u8>) {
15 let hmac = compute_hmac(secret, key, &version, &value);
16 value.append(&mut hmac.to_vec());
17}
18
19#[cfg(feature = "crypt")]
20pub fn crypt_value(secret: &[u8], key: &str, version: i64, value: &mut [u8]) {
21 let mut engine = Sha256Hash::engine();
22 engine.input(key.as_bytes());
23 engine.input(&version.to_be_bytes());
24 let hash = Sha256Hash::from_engine(engine);
25 let mut nonce = [0u8; 12];
26 nonce[0..12].copy_from_slice(&hash[0..12]);
27
28 let mut chacha = ChaCha20::new(secret, &nonce);
29 chacha.process_in_place(value);
30}
31
32pub fn process_value_from_get(secret: &[u8], key: &str, value: &mut Value) -> Result<(), ()> {
33 #[cfg(feature = "crypt")]
34 crypt_value(secret, key, value.version, &mut value.value);
35 remove_and_check_hmac(secret, key, value.version, &mut value.value)?;
36 Ok(())
37}
38
39pub fn remove_and_check_hmac(
40 secret: &[u8],
41 key: &str,
42 version: i64,
43 value: &mut Vec<u8>,
44) -> Result<(), ()> {
45 if value.len() < 32 {
46 error!("value too short to have an HMAC");
47 return Err(());
48 }
49 let expected_hmac = value.split_off(value.len() - 32);
50 let hmac = compute_hmac(secret, key, &version, &value);
51 if hmac == expected_hmac.as_slice() {
52 Ok(())
53 } else {
54 Err(())
55 }
56}
57
58fn compute_hmac(secret: &[u8], key: &str, version: &i64, value: &[u8]) -> [u8; 32] {
59 let mut hmac = HmacEngine::<Sha256Hash>::new(secret);
60 add_to_hmac(key, version, value, &mut hmac);
61 Hmac::from_engine(hmac).into_inner()
62}
63
64pub fn add_to_hmac(key: &str, version: &i64, value: &[u8], hmac: &mut HmacEngine<Sha256Hash>) {
66 hmac.input(key.as_bytes());
67 hmac.input(&version.to_be_bytes());
68 hmac.input(&value);
69}
70
71pub fn compute_shared_hmac(secret: &[u8], nonce: &[u8], kvs: &[(String, Value)]) -> Vec<u8> {
74 let mut hmac_engine = HmacEngine::<Sha256Hash>::new(&secret);
75 hmac_engine.input(secret);
76 hmac_engine.input(nonce);
77 for (key, value) in kvs {
78 add_to_hmac(&key, &value.version, &value.value, &mut hmac_engine);
79 }
80 Hmac::from_engine(hmac_engine).into_inner().to_vec()
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn put_get_processing_test() {
89 let secret = [3u8; 32];
90 let key = "test/key";
91 let value = Value { version: 12, value: "test value".as_bytes().to_vec() };
92 let mut v = Value { version: value.version, value: value.value.clone() };
93 prepare_value_for_put(&secret, key, &mut v);
94 assert_ne!(v.value, value.value);
95 process_value_from_get(&secret, key, &mut v).unwrap();
96 assert_eq!(v.value, value.value);
97 }
98
99 #[test]
100 fn test_hmac() {
101 let key = [11u8; 32];
102 let orig_value = vec![1u8, 2, 3];
103 let mut value = orig_value.clone();
104 append_hmac_to_value(&key, "x", 123, &mut value);
105 remove_and_check_hmac(&key, "x", 123, &mut value).expect("hmac check failed");
106 assert_eq!(value, orig_value);
107
108 let mut value = orig_value.clone();
109 append_hmac_to_value(&key, "x", 123, &mut value);
110 value[0] = 0;
111 remove_and_check_hmac(&key, "x", 123, &mut value).expect_err("hmac check should fail");
112
113 let mut value = orig_value.clone();
114 append_hmac_to_value(&key, "x", 123, &mut value);
115 remove_and_check_hmac(&key, "x", 122, &mut value).expect_err("hmac check should fail");
116
117 let mut value = orig_value.clone();
118 append_hmac_to_value(&key, "x", 123, &mut value);
119 remove_and_check_hmac(&key, "x1", 123, &mut value).expect_err("hmac check should fail");
120 }
121}