bc_components/symmetric/
encrypted_message.rs1use std::borrow::Cow;
2use bc_ur::prelude::*;
3use crate::{ Nonce, Digest, DigestProvider, tags, AuthenticationTag };
4use anyhow::{ bail, Result, Error };
5
6#[derive(Clone, Eq, PartialEq)]
25pub struct EncryptedMessage {
26 ciphertext: Vec<u8>,
27 aad: Vec<u8>, nonce: Nonce,
29 auth: AuthenticationTag,
30}
31
32impl EncryptedMessage {
33 pub fn new(
37 ciphertext: impl Into<Vec<u8>>,
38 aad: impl Into<Vec<u8>>,
39 nonce: Nonce,
40 auth: AuthenticationTag
41 ) -> Self {
42 Self {
43 ciphertext: ciphertext.into(),
44 aad: aad.into(),
45 nonce,
46 auth,
47 }
48 }
49
50 pub fn ciphertext(&self) -> &Vec<u8> {
52 &self.ciphertext
53 }
54
55 pub fn aad(&self) -> &Vec<u8> {
57 &self.aad
58 }
59
60 pub fn nonce(&self) -> &Nonce {
62 &self.nonce
63 }
64
65 pub fn authentication_tag(&self) -> &AuthenticationTag {
67 &self.auth
68 }
69
70 pub fn opt_digest(&self) -> Option<Digest> {
72 CBOR::try_from_data(self.aad())
73 .ok()
74 .and_then(|data| Digest::try_from(data).ok())
75 }
76
77 pub fn has_digest(&self) -> bool {
79 self.opt_digest().is_some()
80 }
81}
82
83impl std::fmt::Debug for EncryptedMessage {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 f.debug_struct("EncryptedMessage")
87 .field("ciphertext", &hex::encode(&self.ciphertext))
88 .field("aad", &hex::encode(&self.aad))
89 .field("nonce", &self.nonce)
90 .field("auth", &self.auth)
91 .finish()
92 }
93}
94
95impl AsRef<EncryptedMessage> for EncryptedMessage {
97 fn as_ref(&self) -> &EncryptedMessage {
98 self
99 }
100}
101
102impl DigestProvider for EncryptedMessage {
104 fn digest(&self) -> Cow<'_, Digest> {
105 let a = self.opt_digest().unwrap();
106 Cow::Owned(a)
107 }
108}
109
110impl CBORTagged for EncryptedMessage {
112 fn cbor_tags() -> Vec<Tag> {
113 tags_for_values(&[tags::TAG_ENCRYPTED])
114 }
115}
116
117impl From<EncryptedMessage> for CBOR {
119 fn from(value: EncryptedMessage) -> Self {
120 value.tagged_cbor()
121 }
122}
123
124impl TryFrom<CBOR> for EncryptedMessage {
126 type Error = Error;
127
128 fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
129 Self::from_tagged_cbor(cbor)
130 }
131}
132
133impl CBORTaggedEncodable for EncryptedMessage {
135 fn untagged_cbor(&self) -> CBOR {
136 let mut a = vec![
137 CBOR::to_byte_string(&self.ciphertext),
138 CBOR::to_byte_string(self.nonce.data()),
139 CBOR::to_byte_string(self.auth.data())
140 ];
141
142 if !self.aad.is_empty() {
143 a.push(CBOR::to_byte_string(&self.aad));
144 }
145
146 a.into()
147 }
148}
149
150impl CBORTaggedDecodable for EncryptedMessage {
152 fn from_untagged_cbor(cbor: CBOR) -> Result<Self> {
153 match cbor.as_case() {
154 CBORCase::Array(elements) => {
155 if elements.len() < 3 {
156 bail!("EncryptedMessage must have at least 3 elements");
157 }
158 let ciphertext = CBOR::try_into_byte_string(elements[0].clone())?;
159 let nonce_data = CBOR::try_into_byte_string(elements[1].clone())?;
160 let nonce = Nonce::from_data_ref(nonce_data)?;
161 let auth_data = CBOR::try_into_byte_string(elements[2].clone())?;
162 let auth = AuthenticationTag::from_data_ref(auth_data)?;
163 let aad = if elements.len() > 3 {
164 CBOR::try_into_byte_string(elements[3].clone())?
165 } else {
166 Vec::new()
167 };
168 Ok(Self::new(ciphertext, aad, nonce, auth))
169 }
170 _ => bail!("EncryptedMessage must be an array"),
171 }
172 }
173}