bc_envelope/extension/
secret.rs

1use bc_components::{EncryptedKey, KeyDerivationMethod, SymmetricKey};
2use known_values;
3
4use crate::{Envelope, Error, Result};
5
6impl Envelope {
7    pub fn lock_subject(
8        &self,
9        method: KeyDerivationMethod,
10        secret: impl AsRef<[u8]>,
11    ) -> Result<Self> {
12        let content_key = SymmetricKey::new();
13        // Lock the content key using the specified derivation method
14        let encrypted_key = EncryptedKey::lock(method, secret, &content_key)?;
15        // Add a hasSecret assertion with the EncryptedKey
16        Ok(self
17            .encrypt_subject(&content_key)
18            .expect("Encrypt subject")
19            .add_assertion(known_values::HAS_SECRET, encrypted_key))
20    }
21
22    pub fn unlock_subject(&self, secret: impl AsRef<[u8]>) -> Result<Self> {
23        // Find and attempt to unlock each EncryptedKey in hasSecret assertions
24        for assertion in
25            self.assertions_with_predicate(known_values::HAS_SECRET)
26        {
27            let obj = assertion.as_object().unwrap();
28            if !obj.is_obscured() {
29                let encrypted_key = obj.extract_subject::<EncryptedKey>()?;
30                if let Ok(content_key) = encrypted_key.unlock(secret.as_ref()) {
31                    return self.decrypt_subject(&content_key);
32                }
33            }
34        }
35        // No matching secret unlock succeeded
36        Err(Error::UnknownSecret)
37    }
38
39    pub fn is_locked_with_password(&self) -> bool {
40        // Check if the envelope has a hasSecret assertion with a password-based
41        // key derivation method
42        self.assertions_with_predicate(known_values::HAS_SECRET)
43            .iter()
44            .any(|assertion| {
45                let obj = assertion.as_object().unwrap();
46                if let Ok(encrypted_key) = obj.extract_subject::<EncryptedKey>()
47                {
48                    encrypted_key.is_password_based()
49                } else {
50                    false
51                }
52            })
53    }
54
55    pub fn is_locked_with_ssh_agent(&self) -> bool {
56        // Check if the envelope has a hasSecret assertion with an SSH agent
57        // key derivation method
58        self.assertions_with_predicate(known_values::HAS_SECRET)
59            .iter()
60            .any(|assertion| {
61                let obj = assertion.as_object().unwrap();
62                if let Ok(encrypted_key) = obj.extract_subject::<EncryptedKey>()
63                {
64                    encrypted_key.is_ssh_agent()
65                } else {
66                    false
67                }
68            })
69    }
70
71    pub fn add_secret(
72        &self,
73        method: KeyDerivationMethod,
74        secret: impl AsRef<[u8]>,
75        content_key: &SymmetricKey,
76    ) -> Result<Self> {
77        // Lock the content key using the specified derivation method
78        let encrypted_key = EncryptedKey::lock(method, secret, content_key)?;
79        // Add a hasSecret assertion with the EncryptedKey
80        Ok(self.add_assertion(known_values::HAS_SECRET, encrypted_key))
81    }
82}
83
84impl Envelope {
85    pub fn lock(
86        &self,
87        method: KeyDerivationMethod,
88        secret: impl AsRef<[u8]>,
89    ) -> Result<Self> {
90        self.wrap().lock_subject(method, secret)
91    }
92
93    pub fn unlock(&self, secret: impl AsRef<[u8]>) -> Result<Self> {
94        self.unlock_subject(secret)?.try_unwrap()
95    }
96}