burrito_secrets/
signing.rs

1/*
2 * Copyright (c) 2024.
3 *
4 * Licensed under the MIT license <http://opensource.org/licenses/MIT>.
5 */
6use crate::database::Metadata;
7use anyhow::bail;
8use bson::spec::BinarySubtype;
9use bson::Bson;
10use dryoc::auth::protected::Key;
11use dryoc::protected::HeapByteArray;
12use dryoc::sign::protected::{PublicKey, SecretKey};
13use serde::Serialize;
14
15pub trait Signing: Metadata + Serialize {
16    /// symmetrical signature
17    fn sign_sym(self, secret_key: Key) -> Self
18    {
19        use dryoc::auth::Auth;
20        use dryoc::constants::CRYPTO_AUTH_BYTES;
21
22        let out = self.with_meta(("modified", bson::DateTime::now()));
23
24        // If the entries are not always in the same order, the signature will be different!!!!
25        // I used a BTreeMap internally to make sure the entries are always in the same order
26        let self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
27        let signature: [u8; CRYPTO_AUTH_BYTES] = Auth::compute(secret_key, &self_bytes);
28        let signature = bson::Binary {
29            subtype: BinarySubtype::Sensitive,
30            bytes: Vec::from(signature),
31        };
32
33        out
34            .with_meta(("signature_sym", signature))
35    }
36
37    fn verify_sym(self, secret_key: Key) -> anyhow::Result<Self>
38    {
39        use dryoc::auth::Auth;
40
41        let mut self_entries = bson::to_document(&self)?;
42        let Some(Bson::Binary(signature)) = self_entries.remove("signature_sym") else { bail!("Entry does not contain valid signature") };
43        let signature = signature.bytes;
44        // If the entries are not always in the same order, the signature will be different!!!!
45        // I used a BTreeMap to make sure the entries are always in the same order
46        let self_bytes = bson::to_vec(&self_entries).expect("Failed to serialize entry");
47        Auth::compute_and_verify(&signature.as_slice(), secret_key, &self_bytes)?;
48
49        Ok(self)
50    }
51
52    fn sign(self, key: SecretKey) -> Self {
53        use dryoc::sign::SigningKeyPair;
54        use dryoc::sign::protected::PublicKey;
55        use dryoc::sign::protected::SecretKey;
56
57        let keypair: SigningKeyPair<PublicKey, SecretKey> = SigningKeyPair::from_secret_key(key);
58        let public_key = bson::Binary {
59            subtype: BinarySubtype::Sensitive,
60            bytes: keypair.public_key.to_vec(),
61        };
62
63        let out = self
64            .with_meta(("modified", bson::DateTime::now()))
65            .with_meta(("signing_public_key", public_key));
66
67        let self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
68        let (signature, _data): (HeapByteArray<64>, _) = keypair.sign(self_bytes).expect("Failed to sign entry").into_parts();
69        let signature = bson::Binary {
70            subtype: BinarySubtype::Sensitive,
71            bytes: signature.to_vec(),
72        };
73
74
75        out
76            .with_meta(("signature", signature))
77    }
78
79    fn verify(self) -> anyhow::Result<Self> {
80        let self_entries = bson::to_document(&self)?;
81
82        let Some(Bson::Binary(public_key)) = self_entries.get_meta("signing_public_key") else { bail!("Entry does not contain valid signature") };
83        let public_key = &public_key.bytes;
84        let public_key = PublicKey::try_from(public_key.as_slice())?;
85
86        self.verify_with(public_key)
87    }
88
89    fn verify_with(self, public_key: PublicKey) -> anyhow::Result<Self> {
90        use dryoc::sign::SignedMessage;
91
92        let mut self_entries = bson::to_document(&self)?;
93
94        let Some(Bson::Binary(signature)) = self_entries.remove("signature") else { bail!("Entry does not contain valid signature") };
95        let signature = signature.bytes;
96
97
98        let self_signed = bson::to_vec(&self_entries)?;
99        let self_signed = SignedMessage::from_parts(signature, self_signed);
100
101        self_signed.verify(&public_key)?;
102
103        Ok(self)
104    }
105
106    const SECURITY_PADDING: &'static [u8] = b"This is some extra data to ensure that the signature is different, instead of being simply copy-pastable if the owner of the document did not also sign the document BEFORE adding a security attestation.";
107
108    fn with_security(self, key: SecretKey) -> Self {
109        use dryoc::sign::SigningKeyPair;
110        use dryoc::sign::protected::PublicKey;
111        use dryoc::sign::protected::SecretKey;
112
113        let keypair: SigningKeyPair<PublicKey, SecretKey> = SigningKeyPair::from_secret_key(key);
114        let public_key = bson::Binary {
115            subtype: BinarySubtype::Sensitive,
116            bytes: keypair.public_key.to_vec(),
117        };
118
119        let out = self
120            .with_meta(("modified", bson::DateTime::now()))
121            .with_meta(("security_signing_public_key", public_key));
122
123        let mut self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
124        self_bytes.extend_from_slice(Self::SECURITY_PADDING);
125        let (signature, _data): (HeapByteArray<64>, _) = keypair.sign(self_bytes).expect("Failed to sign entry").into_parts();
126        let signature = bson::Binary {
127            subtype: BinarySubtype::Sensitive,
128            bytes: signature.to_vec(),
129        };
130
131
132        out
133            .with_meta(("assumed_secure", signature))
134    }
135
136    fn is_secure(&self) -> bool {
137        let Ok(self_entries) = bson::to_document(&self) else { return false };
138        let Some(Bson::Binary(public_key)) = self_entries.get("security_signing_public_key") else { return false };
139        let public_key = &public_key.bytes;
140        let Ok(public_key) = PublicKey::try_from(public_key.as_slice()) else { return false };
141
142        self.is_secure_with(public_key)
143    }
144
145    fn is_secure_with(&self, public_key: PublicKey) -> bool {
146        use dryoc::sign::SignedMessage;
147
148        let Ok(mut self_entries) = bson::to_document(&self) else { return false };
149        let Some(Bson::Binary(signature)) = self_entries.remove("assumed_secure") else { return false };
150        let signature = signature.bytes;
151
152        let Ok(mut self_bytes) = bson::to_vec(&self_entries) else { return false };
153        self_bytes.extend_from_slice(Self::SECURITY_PADDING);
154        let self_signed = SignedMessage::from_parts(signature, self_bytes);
155
156        let Ok(()) = self_signed.verify(&public_key) else { return false };
157
158        true
159    }
160}
161
162impl<T: Metadata + Serialize> Signing for T {}