1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use alloc::boxed::Box;
use alloc::string::String;

use serde::{Deserialize, Serialize};
use umbral_pre::{
    decrypt_original, decrypt_reencrypted, encrypt, serde_bytes, Capsule, DecryptionError,
    EncryptionError, PublicKey, ReencryptionError, SecretKey, VerifiedCapsuleFrag,
};

use crate::conditions::Conditions;
use crate::versioning::{
    messagepack_deserialize, messagepack_serialize, ProtocolObject, ProtocolObjectInner,
};

/// Encrypted message prepared for re-encryption.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct MessageKit {
    /// Encapsulated symmetric key for this message.
    pub capsule: Capsule,
    #[serde(with = "serde_bytes::as_base64")]
    ciphertext: Box<[u8]>,
    /// Decryption conditions for this message.
    pub conditions: Option<Conditions>,
}

impl MessageKit {
    /// Creates a new encrypted message for the given policy key.
    pub fn new(
        policy_encrypting_key: &PublicKey,
        plaintext: &[u8],
        conditions: Option<&Conditions>,
    ) -> Self {
        let (capsule, ciphertext) = match encrypt(policy_encrypting_key, plaintext) {
            Ok(result) => result,
            Err(err) => match err {
                // For now this is the only error that can happen during encryption,
                // and there's really no point in propagating it.
                EncryptionError::PlaintextTooLarge => panic!("encryption failed - out of memory?"),
            },
        };
        Self {
            capsule,
            ciphertext,
            conditions: conditions.cloned(),
        }
    }

    /// Decrypts the message using the original (Alice's) key.
    pub fn decrypt(&self, sk: &SecretKey) -> Result<Box<[u8]>, DecryptionError> {
        decrypt_original(sk, &self.capsule, &self.ciphertext)
    }

    /// Decrypts the message using the Bob's key and re-encrypted capsule frags.
    pub fn decrypt_reencrypted(
        &self,
        sk: &SecretKey,
        policy_encrypting_key: &PublicKey,
        vcfrags: impl IntoIterator<Item = VerifiedCapsuleFrag>,
    ) -> Result<Box<[u8]>, ReencryptionError> {
        decrypt_reencrypted(
            sk,
            policy_encrypting_key,
            &self.capsule,
            vcfrags,
            self.ciphertext.clone(),
        )
    }
}

impl<'a> ProtocolObjectInner<'a> for MessageKit {
    fn brand() -> [u8; 4] {
        *b"MKit"
    }

    fn version() -> (u16, u16) {
        (3, 0)
    }

    fn unversioned_to_bytes(&self) -> Box<[u8]> {
        messagepack_serialize(&self)
    }

    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
        if minor_version == 0 {
            Some(messagepack_deserialize(bytes))
        } else {
            None
        }
    }
}

impl<'a> ProtocolObject<'a> for MessageKit {}