burrito_secrets/waiters/
burrito_box.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::EncryptionWaiter;
8use bson::doc;
9use bson::spec::BinarySubtype;
10use dryoc::dryocbox::protected::{PublicKey, SecretKey};
11use serde::{Deserialize, Serialize};
12use std::collections::BTreeMap;
13use crate::waiters::Waiter;
14
15#[derive(Serialize, Deserialize)]
16#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
17pub struct BurritoBox {
18    encrypted: bson::Binary,
19    ephemeral_public_key: bson::Binary,
20    mac: bson::Binary,
21    #[serde(flatten)]
22    additional_fields: BTreeMap<String, bson::Bson>,
23}
24
25impl BurritoBox {
26    pub fn from_encrypted(encrypted: dryoc::dryocbox::VecBox) -> Self {
27        let (mac, encrypted, Some(key)) = encrypted.into_parts() else {
28            // we always expect an ephemeral public key to be encoded.
29            panic!("encrypted box is non-standard");
30        };
31
32        let encrypted = bson::Binary {
33            subtype: BinarySubtype::Encrypted,
34            bytes: encrypted,
35        };
36
37        let mac = bson::Binary {
38            subtype: BinarySubtype::Sensitive,
39            bytes: mac.to_vec(),
40        };
41
42        let ephemeral_public_key = bson::Binary {
43            subtype: BinarySubtype::Sensitive,
44            bytes: key.to_vec(),
45        };
46
47        Self {
48            encrypted,
49            mac,
50            ephemeral_public_key,
51            additional_fields: BTreeMap::new(),
52        }
53            .and_defaults::<Self>()
54    }
55}
56
57impl Waiter for BurritoBox {
58    fn name() -> String {
59        "burrito_asymmetric_box".to_string()
60    }
61
62    fn version() -> String {
63        "0.0.0".to_string()
64    }
65
66    fn into_entry(self) -> Entry {
67        bson::to_document(&self).unwrap().and_defaults::<Self>()
68    }
69
70    fn from_entry(entry: Entry) -> anyhow::Result<Self> {
71        Self::verify_version(&entry)?;
72
73        let burrito_box = bson::from_document(entry)?;
74
75        Ok(burrito_box)
76    }
77}
78
79impl Metadata for BurritoBox {
80    fn get_meta(&self, key: &str) -> Option<&bson::Bson> {
81        self.additional_fields.get(key)
82    }
83
84    fn set_meta(&mut self, metadata: (&str, impl Serialize)) {
85        self.additional_fields.insert(metadata.0.to_string(), bson::to_bson(&metadata.1).unwrap());
86    }
87}
88
89impl EncryptionWaiter for BurritoBox {
90    fn encrypt(entry: Entry, key: PublicKey) -> anyhow::Result<Self> {
91        use dryoc::dryocbox::VecBox;
92
93        let entry_bytes = bson::to_vec(&entry)?;
94        let secret_box = VecBox::seal(&entry_bytes, &key)?;
95
96        Ok(Self::from_encrypted(secret_box))
97    }
98
99    fn decrypt(self, key: SecretKey) -> anyhow::Result<Entry> {
100        use dryoc::dryocbox::VecBox;
101        use dryoc::dryocbox::protected::SecretKey;
102        use dryoc::dryocbox::PublicKey;
103        use dryoc::dryocbox::Mac;
104        use dryoc::keypair::KeyPair;
105
106        let keypair: KeyPair<PublicKey, SecretKey> = KeyPair::from_secret_key(key);
107
108        let mac = self.mac.bytes;
109        let mac = Mac::try_from(mac.as_slice())?;
110
111        let encrypted = self.encrypted.bytes;
112
113        let ephemeral_public_key = self.ephemeral_public_key.bytes;
114        let ephemeral_public_key = PublicKey::try_from(ephemeral_public_key.as_slice())?;
115
116        let encrypted = VecBox::from_parts(mac, encrypted, Some(ephemeral_public_key));
117
118        let unencrypted = encrypted.unseal_to_vec(&keypair)?;
119        let unencrypted = bson::from_slice(&unencrypted)?;
120
121
122        Ok(unencrypted)
123    }
124}