Skip to main content

runar_serializer/
encryption.rs

1use crate::traits::{EnvelopeEncryptedData, KeyStore, LabelResolver};
2use anyhow::{anyhow, Result};
3use serde::{Deserialize, Serialize};
4use std::sync::Arc;
5
6/// Container for label-grouped encryption (one per label)
7#[derive(Serialize, Deserialize, Clone, Debug)]
8pub struct EncryptedLabelGroup {
9    /// The label this group was encrypted with
10    pub label: String,
11    /// Envelope-encrypted payload produced by runar-keys
12    pub envelope: Option<EnvelopeEncryptedData>,
13}
14
15impl EncryptedLabelGroup {
16    pub fn is_empty(&self) -> bool {
17        match &self.envelope {
18            Some(env) => env.encrypted_data.is_empty(),
19            None => true,
20        }
21    }
22}
23
24/// Encrypt a group of fields that share the same label ("user", "system", ...)
25pub fn encrypt_label_group<T: Serialize>(
26    label: &str,
27    fields_struct: &T,
28    keystore: &KeyStore,
29    resolver: &dyn LabelResolver,
30) -> Result<EncryptedLabelGroup> {
31    // Serialize the fields within this label group using serde_cbor
32    let plain_bytes = serde_cbor::to_vec(fields_struct)?;
33
34    // Resolve the label to key info (public key + scope)
35    let info = resolver
36        .resolve_label_info(label)?
37        .ok_or_else(|| anyhow!("Label '{label}' not available in current context"))?;
38
39    let envelope = keystore.encrypt_with_envelope(
40        &plain_bytes,
41        info.network_id.as_deref(),
42        info.profile_public_keys,
43    )?;
44
45    Ok(EncryptedLabelGroup {
46        label: label.to_string(),
47        envelope: Some(envelope),
48    })
49}
50
51/// Attempt to decrypt a label group back into its original struct.  
52/// Returns an error if decryption fails, allowing callers to ignore failures
53/// (e.g. when the current context lacks the required keys).
54pub fn decrypt_label_group<T: for<'de> Deserialize<'de> + Default>(
55    encrypted_group: &EncryptedLabelGroup,
56    keystore: &KeyStore,
57) -> Result<T> {
58    if encrypted_group.is_empty() {
59        return Err(anyhow!("Empty encrypted group"));
60    }
61
62    // Attempt decryption using the provided key manager
63    let env = encrypted_group
64        .envelope
65        .as_ref()
66        .ok_or_else(|| anyhow!("Empty encrypted group"))?;
67
68    let plaintext = keystore.decrypt_envelope_data(env)?;
69
70    // Deserialize the fields struct from plaintext using serde_cbor
71    let fields_struct: T = serde_cbor::from_slice(&plaintext)?;
72    Ok(fields_struct)
73}
74
75// Replace stubs with real implementations
76// pub fn encrypt_bytes(bytes: &[u8], keystore: &Arc<KeyStore>, network_id: Option<&String>, profile_ids: Vec<String>) -> anyhow::Result<Vec<u8>> {
77//     // Use network-agnostic envelope (empty network_id, no profile_ids)
78//     let env = keystore
79//         .encrypt_with_envelope(bytes, network_id, profile_ids)
80//         .map_err(|e| anyhow!(e))?;
81//     Ok(env.encode_to_vec())
82// }
83
84pub fn decrypt_bytes(bytes: &[u8], keystore: &Arc<KeyStore>) -> anyhow::Result<Vec<u8>> {
85    let env: EnvelopeEncryptedData = serde_cbor::from_slice(bytes).map_err(|e| anyhow!(e))?;
86    keystore.decrypt_envelope_data(&env).map_err(|e| anyhow!(e))
87}