chamber_core/
secrets.rs

1use crate::errors::DatabaseError;
2use num_traits::cast::ToPrimitive;
3use ring::rand::SecureRandom;
4use ring::rand::SystemRandom;
5use ring::{
6    aead::{Aad, BoundKey, Nonce, NonceSequence, OpeningKey, SealingKey},
7    error::Unspecified,
8};
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use serde_bytes::ByteBuf;
11use sqlx::types::BigDecimal;
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14use crate::consts::KEYFILE_PATH;
15
16#[derive(sqlx::FromRow, Zeroize, ZeroizeOnDrop)]
17pub struct EncryptedSecret {
18    pub key: String,
19    #[sqlx(try_from = "BigDecimal")]
20    pub nonce: U64Wrapper,
21    pub ciphertext: Vec<u8>,
22    tags: Vec<String>,
23    access_level: i32,
24    role_whitelist: Vec<String>,
25}
26
27#[derive(Default)]
28pub struct EncryptedSecretBuilder {
29    pub key: String,
30    value: String,
31    tags: Option<Vec<String>>,
32    access_level: Option<i32>,
33    role_whitelist: Option<Vec<String>>,
34}
35
36impl EncryptedSecretBuilder {
37    pub fn new(key: String, value: String) -> Self {
38        Self {
39            key,
40            value,
41            ..Default::default()
42        }
43    }
44
45    pub fn with_tags(mut self, tags: Option<Vec<String>>) -> Self {
46        if let Some(tags) = tags {
47            self.tags = Some(tags);
48        }
49        self
50    }
51
52    pub fn with_access_level(mut self, access_level: Option<i32>) -> Self {
53        if let Some(access_level) = access_level {
54            self.access_level = Some(access_level);
55        }
56        self
57    }
58
59    pub fn with_whitelist(mut self, role_whitelist: Option<Vec<String>>) -> Self {
60        if let Some(role_whitelist) = role_whitelist {
61            self.role_whitelist = Some(role_whitelist);
62        }
63        self
64    }
65
66    pub fn build(
67        self,
68        mut sealing_key: SealingKey<NonceCounter>,
69        nonce_num: u64,
70    ) -> EncryptedSecret {
71        let aad = Aad::empty();
72
73        let mut transformed_in_place: Vec<u8> = self.value.into_bytes();
74
75        sealing_key
76            .seal_in_place_append_tag(aad, &mut transformed_in_place)
77            .unwrap();
78
79        EncryptedSecret {
80            key: self.key,
81            nonce: U64Wrapper(nonce_num),
82            ciphertext: transformed_in_place,
83            tags: if let Some(tags) = self.tags {
84                tags
85            } else {
86                Vec::new()
87            },
88            access_level: if let Some(access_level) = self.access_level {
89                access_level
90            } else {
91                0
92            },
93            role_whitelist: if let Some(whitelist) = self.role_whitelist {
94                whitelist
95            } else {
96                Vec::new()
97            },
98        }
99    }
100}
101
102#[derive(sqlx::FromRow)]
103pub struct Secret {
104    #[sqlx(try_from = "BigDecimal")]
105    pub nonce: U64Wrapper,
106    pub ciphertext: Vec<u8>,
107}
108
109impl Secret {
110    pub fn decrypt(&self, mut seq: OpeningKey<NonceCounter>) -> String {
111        let aad = Aad::empty();
112
113        let mut tag = self.ciphertext.clone();
114
115        let plaintext = seq.open_in_place(aad, &mut tag).unwrap();
116
117        String::from_utf8(plaintext.to_vec()).unwrap()
118    }
119}
120
121#[derive(sqlx::FromRow, Clone, Serialize, Deserialize, Debug)]
122pub struct SecretInfo {
123    pub key: String,
124    pub tags: Vec<String>,
125    pub access_level: i32,
126    pub role_whitelist: Vec<String>,
127}
128
129impl<'a> EncryptedSecret {
130    pub fn key(&'a self) -> &'a str {
131        &self.key
132    }
133
134    pub fn nonce(&self) -> u64 {
135        self.nonce.0
136    }
137
138    pub fn ciphertext(&self) -> &[u8] {
139        &self.ciphertext
140    }
141
142    pub fn tags(&'a self) -> Vec<&'a str> {
143        self.tags.iter().map(AsRef::as_ref).collect()
144    }
145
146    pub fn remove_all_tags(mut self) {
147        self.tags = Vec::new();
148    }
149
150    pub fn add_tag(mut self, string: &str) {
151        self.tags.push(string.to_owned());
152    }
153
154    pub fn replace_tags(&mut self, tags: Vec<String>) {
155        self.tags = tags;
156    }
157
158    pub fn remove_tag(mut self, tag: &str) {
159        self.tags.retain(|x| x == tag);
160    }
161
162    pub fn access_level(&self) -> i32 {
163        self.access_level
164    }
165
166    pub fn set_access_level(&mut self, level: Option<i32>) {
167        if let Some(level) = level {
168            self.access_level = level;
169        }
170    }
171
172    pub fn role_whitelist(&'a self) -> Vec<&'a str> {
173        self.role_whitelist.iter().map(AsRef::as_ref).collect()
174    }
175
176    pub fn set_role_whitelist(&mut self, whitelist: Option<Vec<String>>) {
177        if let Some(mut whitelist) = whitelist {
178            self.role_whitelist.append(&mut whitelist);
179        }
180    }
181
182    pub fn add_role_to_whitelist(&mut self, role: String) {
183        self.role_whitelist.push(role);
184    }
185
186    pub fn remove_role_from_whitelist(&mut self, role: String) {
187        self.role_whitelist.retain(|x| x != &role);
188    }
189
190    pub fn reencrypt(
191        &mut self,
192        mut open_key: OpeningKey<NonceCounter>,
193        mut sealing_key: SealingKey<NonceCounter>
194        ) {
195        let aad = Aad::empty();
196
197        let mut tag = self.ciphertext.clone();
198
199        let key = open_key.open_in_place(aad, &mut tag).unwrap();
200
201        let plaintext = String::from_utf8(key.to_vec()).unwrap();
202        
203        let mut transformed_in_place: Vec<u8> = plaintext.into_bytes();
204
205        sealing_key
206            .seal_in_place_append_tag(aad, &mut transformed_in_place)
207            .unwrap();
208
209        self.ciphertext = transformed_in_place;
210
211    }
212}
213
214#[derive(Zeroize, ZeroizeOnDrop)]
215pub struct SerializeKey(pub Vec<u8>);
216
217impl SerializeKey {
218    pub fn new() -> Self {
219        let rand = SystemRandom::new();
220        let mut key: [u8; 32] = [0u8; 32];
221        let _ = rand.fill(&mut key);
222        Self(key.to_vec())
223    }
224
225    pub fn make_key(&self) -> ring::aead::UnboundKey {
226        ring::aead::UnboundKey::new(&ring::aead::AES_256_GCM, &self.0).unwrap()
227    }
228}
229
230impl Default for SerializeKey {
231    fn default() -> Self {
232        Self::new()
233    }
234}
235
236impl Serialize for SerializeKey {
237    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238    where
239        S: Serializer,
240    {
241        let vec = self.0.to_vec();
242        serializer.serialize_bytes(&vec)
243    }
244}
245
246impl<'de> Deserialize<'de> for SerializeKey {
247    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
248    where
249        D: Deserializer<'de>,
250    {
251        let bytes = Deserialize::deserialize(deserializer)
252            .map(ByteBuf::into_vec)
253            .unwrap();
254
255        Ok(Self(bytes))
256    }
257}
258
259#[derive(Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
260pub struct KeyFile {
261    unlock_key: String,
262    crypto_key: SerializeKey,
263    pub nonce_number: u64,
264}
265
266impl<'b> KeyFile {
267    pub fn new() -> Self {
268        Self {
269            unlock_key: nanoid::nanoid!(100),
270            crypto_key: SerializeKey::new(),
271            nonce_number: 1,
272        }
273    }
274
275    pub fn crypto_key(&'b self) -> &'b SerializeKey {
276        &self.crypto_key
277    }
278
279    pub fn from_key(string: &str) -> Self {
280        Self {
281            unlock_key: string.to_owned(),
282            crypto_key: SerializeKey::new(),
283            nonce_number: 1,
284        }
285    }
286
287    pub fn unseal_key(&'b self) -> &'b str {
288        &self.unlock_key
289    }
290
291    pub fn save(&self) -> Result<(), DatabaseError> {
292        let _thing = self;
293        let encoded = bincode::serialize(&self).unwrap();
294
295        match std::fs::write(KEYFILE_PATH, encoded) {
296            Ok(res) => res,
297            Err(e) => return Err(DatabaseError::IoError(e)),
298        };
299        Ok(())
300    }
301
302    pub fn get_crypto_seal_key(&mut self) -> SealingKey<NonceCounter> {
303        let nonce_sequence = NonceCounter(self.nonce_number);
304
305        let unbound_key = self.crypto_key.make_key();
306        self.nonce_number += 1;
307
308        let _ = self.save();
309        SealingKey::new(unbound_key, nonce_sequence)
310    }
311
312    pub fn get_crypto_open_key(&self, num: u64) -> OpeningKey<NonceCounter> {
313        let nonce_sequence = NonceCounter(num);
314
315        let unbound_key = self.crypto_key.make_key();
316        OpeningKey::new(unbound_key, nonce_sequence)
317    }
318}
319
320impl Default for KeyFile {
321    fn default() -> Self {
322        Self::new()
323    }
324}
325
326#[derive(Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
327pub struct U64Wrapper(pub u64);
328
329impl U64Wrapper {
330    pub fn inner(&self) -> u64 {
331        self.0
332    }
333}
334
335impl From<BigDecimal> for U64Wrapper {
336    fn from(decimal: BigDecimal) -> Self {
337        Self(decimal.to_u64().unwrap())
338    }
339}
340
341pub struct NonceCounter(u64);
342
343impl Default for NonceCounter {
344    fn default() -> Self {
345        Self::new()
346    }
347}
348
349impl NonceCounter {
350    pub fn new() -> Self {
351        Self(1)
352    }
353
354    pub fn from_num(num: u64) -> Self {
355        Self(num)
356    }
357}
358
359impl NonceSequence for NonceCounter {
360    // called once for each seal operation
361    fn advance(&mut self) -> Result<Nonce, Unspecified> {
362        let mut nonce_bytes: [u8; 12] = [0; 12];
363
364        let bytes = self.0.to_be_bytes();
365        nonce_bytes[4..].copy_from_slice(&bytes);
366
367        self.0 += 1; // advance the counter
368        Ok(Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap())
369    }
370}