burrito_secrets/waiters/
burrito_box_sym.rs

1/*
2 * Copyright (c) 2024.
3 *
4 * Licensed under the MIT license <http://opensource.org/licenses/MIT>.
5 */
6use crate::database::{Entry, Metadata};
7use crate::encryption::EncryptionWaiterSymmetric;
8use crate::waiters::Waiter;
9use bson::spec::BinarySubtype;
10use dryoc::dryocbox::protected::SecretKey;
11use dryoc::dryocsecretbox::Nonce;
12use dryoc::types::NewByteArray;
13use serde::{Deserialize, Serialize};
14use std::collections::BTreeMap;
15
16#[derive(Serialize, Deserialize)]
17#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
18pub struct BurritoBoxSym {
19    pub encrypted: bson::Binary,
20    pub mac: bson::Binary,
21    pub nonce: bson::Binary,
22    #[serde(flatten)]
23    pub additional_fields: BTreeMap<String, bson::Bson>,
24}
25
26impl BurritoBoxSym {
27    pub fn of_password(entry: Entry, mut password: String) -> Self {
28        use dryoc::dryocbox::protected::SecretKey;
29        use dryoc::dryocbox::protected::PublicKey;
30        use dryoc::keypair::KeyPair;
31        use dryoc::dryocsecretbox::VecBox;
32
33        let nonce = Nonce::gen();
34        let salt = nonce.to_vec();
35        let config = dryoc::pwhash::Config::interactive();
36        let keypair: KeyPair<PublicKey, SecretKey> = dryoc::pwhash::PwHash::derive_keypair(unsafe { password.as_mut_vec() }, salt, config).unwrap();
37        let secret_key = &keypair.secret_key;
38
39        let entry_bytes = bson::to_vec(&entry).unwrap();
40        let encrypted = VecBox::encrypt(&entry_bytes, &nonce, secret_key);
41        let (mac, encrypted) = encrypted.into_parts();
42
43        let encrypted = bson::Binary {
44            subtype: BinarySubtype::Encrypted,
45            bytes: encrypted,
46        };
47
48        let mac = bson::Binary {
49            subtype: BinarySubtype::Sensitive,
50            bytes: mac.to_vec(),
51        };
52
53        let nonce = bson::Binary {
54            subtype: BinarySubtype::Sensitive,
55            bytes: nonce.to_vec(),
56        };
57
58        Self {
59            encrypted,
60            mac,
61            nonce,
62            additional_fields: BTreeMap::new(),
63        }
64            .and_defaults::<Self>()
65    }
66
67    pub fn decrypt_password(self, mut password: String) -> anyhow::Result<Entry> {
68        use dryoc::dryocbox::protected::SecretKey;
69        use dryoc::dryocbox::protected::PublicKey;
70        use dryoc::keypair::KeyPair;
71        use dryoc::dryocsecretbox::VecBox;
72        use dryoc::dryocsecretbox::Mac;
73
74        let salt = self.nonce.bytes;
75        let nonce = Nonce::try_from(salt.as_slice())?;
76
77
78        let config = dryoc::pwhash::Config::interactive();
79        let keypair: KeyPair<PublicKey, SecretKey> = dryoc::pwhash::PwHash::derive_keypair(unsafe { password.as_mut_vec() }, salt, config)?;
80
81        let mac = Mac::try_from(self.mac.bytes.as_slice())?;
82
83        let encrypted = VecBox::from_parts(mac, self.encrypted.bytes);
84
85        let decrypted = encrypted.decrypt_to_vec(&nonce, &keypair.secret_key)?;
86        let entry = bson::from_slice(&decrypted)?;
87
88        Ok(entry)
89    }
90}
91
92impl Waiter for BurritoBoxSym {
93    fn name() -> String {
94        "burrito_symmetric_box".to_string()
95    }
96
97    fn version() -> String {
98        "0.0.0".to_string()
99    }
100
101    fn into_entry(self) -> Entry {
102        bson::to_document(&self)
103            .unwrap()
104            .and_defaults::<Self>()
105    }
106
107    fn from_entry(entry: Entry) -> anyhow::Result<Self> {
108        Self::verify_version(&entry)?;
109
110        let burrito = bson::from_document(entry)?;
111
112        Ok(burrito)
113    }
114}
115
116impl Metadata for BurritoBoxSym {
117    fn get_meta(&self, key: &str) -> Option<&bson::Bson> {
118        self.additional_fields.get(key)
119    }
120
121    fn set_meta(&mut self, metadata: (&str, impl Serialize)) {
122        self.additional_fields.insert(metadata.0.to_string(), bson::to_bson(&metadata.1).unwrap());
123    }
124}
125
126impl EncryptionWaiterSymmetric for BurritoBoxSym {
127    fn encrypt_sym(entry: Entry, key: SecretKey) -> anyhow::Result<Self> {
128        use dryoc::dryocsecretbox::VecBox;
129        use dryoc::dryocsecretbox::Nonce;
130
131        let entry_bytes = bson::to_vec(&entry)?;
132        let nonce = Nonce::gen();
133        let encrypted = VecBox::encrypt(&entry_bytes, &nonce, &key);
134        let (mac, encrypted) = encrypted.into_parts();
135
136        let encrypted = bson::Binary {
137            subtype: BinarySubtype::Encrypted,
138            bytes: encrypted,
139        };
140
141        let mac = bson::Binary {
142            subtype: BinarySubtype::Sensitive,
143            bytes: mac.to_vec(),
144        };
145
146        let nonce = bson::Binary {
147            subtype: BinarySubtype::Sensitive,
148            bytes: nonce.to_vec(),
149        };
150
151        Ok(
152            Self {
153                encrypted,
154                mac,
155                nonce,
156                additional_fields: BTreeMap::new(),
157            }
158                .and_defaults::<Self>()
159        )
160    }
161
162    fn decrypt_sym(self, key: SecretKey) -> anyhow::Result<Entry> {
163        use dryoc::dryocsecretbox::VecBox;
164        use dryoc::dryocsecretbox::Mac;
165
166        let mac = Mac::try_from(self.mac.bytes.as_slice())?;
167        let encrypted = self.encrypted.bytes;
168        let nonce = self.nonce.bytes;
169
170        let encrypted = VecBox::from_parts(mac, encrypted);
171        let decrypted = encrypted.decrypt_to_vec(&nonce, &key)?;
172
173        let entry = bson::from_slice(&decrypted)?;
174
175        Ok(entry)
176    }
177}