1use chacha20poly1305::{
2 aead::{AeadCore, KeyInit},
3 XChaCha20Poly1305, XNonce,
4};
5use ed25519_dalek::{Signature, SigningKey};
6
7use indexmap::IndexMap;
8
9use rand_core::{OsRng, RngCore};
10
11use zeroize::Zeroizing;
12
13use std::io::Read;
14use std::sync::Arc;
15
16use crate::cert::Cert;
17use crate::crypto;
18use crate::error::{CryptoError, Result};
19use crate::Fingerprint;
20
21use super::header::*;
22use super::Message;
23
24pub struct MessageBuilder<'a> {
62 pub(super) issuer: &'a Cert,
63 pub(super) payload: Vec<u8>,
64}
65
66impl<'a> MessageBuilder<'a> {
67 pub fn write<R: Read>(mut self, mut content: R) -> Result<Self> {
74 content
75 .read_to_end(&mut self.payload)
76 .map_err(|_| CryptoError::Unknown)?;
77 Ok(self)
78 }
79
80 pub fn sign(self) -> SignedMessage<'a> {
82 let key = SigningKey::from_bytes(self.issuer.signing_secret().unwrap());
83 let signature = crypto::sign_message(&key, &self.payload);
84 SignedMessage {
85 issuer: self.issuer,
86 signature,
87 payload: self.payload,
88 }
89 }
90
91 pub fn encrypt_with(self, passphrase: impl AsRef<[u8]>) -> Result<SymEncryptedMessage<'a>> {
93 let salt = {
94 let mut s = [0; 32];
95 OsRng.fill_bytes(&mut s);
96 s
97 };
98 let key = crypto::derive_key(passphrase.as_ref(), &salt[..])?;
99 let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
100
101 Ok(SymEncryptedMessage {
102 issuer: self.issuer,
103 signature: None,
104 salt,
105 nonce,
106 key,
107 payload: self.payload,
108 })
109 }
110
111 pub fn encrypt_for(self, recipients: &'a [Arc<Cert>]) -> Result<AsmEncryptedMessage<'a>> {
113 let key: Zeroizing<[u8; 32]> =
114 Zeroizing::new(XChaCha20Poly1305::generate_key(&mut OsRng).into());
115 let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
116
117 let mut rec_list = IndexMap::new();
118 for recipient in recipients {
119 let shared_secret = Zeroizing::new(
120 self.issuer
121 .encryption_secret()
122 .unwrap()
123 .diffie_hellman(recipient.encryption_public()),
124 );
125 let encrypted_key = crypto::encrypt_key(&key[..], &nonce, &shared_secret)?;
126 rec_list.insert(*recipient.fingerprint(), encrypted_key);
127 }
128 Ok(AsmEncryptedMessage {
129 issuer: self.issuer,
130 signature: None,
131 recipients: rec_list,
132 nonce,
133 key,
134 payload: self.payload,
135 })
136 }
137}
138
139pub struct SignedMessage<'a> {
140 issuer: &'a Cert,
141 signature: Signature,
142 payload: Vec<u8>,
143}
144
145impl<'a> SignedMessage<'a> {
146 pub fn encrypt_with(self, passphrase: impl AsRef<[u8]>) -> Result<SymEncryptedMessage<'a>> {
147 let salt = {
148 let mut s = [0; 32];
149 OsRng.fill_bytes(&mut s);
150 s
151 };
152 let key = crypto::derive_key(passphrase.as_ref(), &salt[..])?;
153 let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
154
155 Ok(SymEncryptedMessage {
156 issuer: self.issuer,
157 signature: Some(self.signature),
158 salt,
159 nonce,
160 key,
161 payload: self.payload,
162 })
163 }
164
165 pub fn encrypt_for(self, recipients: &'a [Arc<Cert>]) -> Result<AsmEncryptedMessage<'a>> {
166 let key: Zeroizing<[u8; 32]> =
167 Zeroizing::new(XChaCha20Poly1305::generate_key(&mut OsRng).into());
168 let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
169
170 let mut rec_list = IndexMap::new();
171 for recipient in recipients {
172 let shared_secret = Zeroizing::new(
173 self.issuer
174 .encryption_secret()
175 .unwrap()
176 .diffie_hellman(recipient.encryption_public()),
177 );
178 let encrypted_key = crypto::encrypt_key(&key[..], &nonce, &shared_secret)?;
179 rec_list.insert(*recipient.fingerprint(), encrypted_key);
180 }
181 Ok(AsmEncryptedMessage {
182 issuer: self.issuer,
183 signature: Some(self.signature),
184 recipients: rec_list,
185 nonce,
186 key,
187 payload: self.payload,
188 })
189 }
190}
191
192pub struct SymEncryptedMessage<'a> {
193 issuer: &'a Cert,
194 signature: Option<Signature>,
195 salt: [u8; 32],
196 nonce: XNonce,
197 key: Zeroizing<[u8; 32]>,
198 payload: Vec<u8>,
199}
200
201pub struct AsmEncryptedMessage<'a> {
202 issuer: &'a Cert,
203 signature: Option<Signature>,
204 recipients: IndexMap<Fingerprint, Vec<u8>>,
205 nonce: XNonce,
206 key: Zeroizing<[u8; 32]>,
207 payload: Vec<u8>,
208}
209
210pub trait MessageFinal {
218 type R;
222
223 fn finalize(self) -> Self::R;
225}
226
227impl MessageFinal for SignedMessage<'_> {
228 type R = Message;
229
230 fn finalize(self) -> Self::R {
231 let msg_type = MessageType::Signed {
232 signature: self.signature,
233 };
234 let header = Header {
235 msg_type,
236 issuer: *self.issuer.fingerprint(),
237 };
238 Message {
239 header,
240 payload: self.payload,
241 }
242 }
243}
244
245impl MessageFinal for SymEncryptedMessage<'_> {
246 type R = Result<Message>;
247
248 fn finalize(self) -> Self::R {
249 let msg_type = match self.signature {
250 Some(s) => MessageType::SignedEncryptedSym {
251 signature: s,
252 salt: self.salt,
253 nonce: self.nonce.into(),
254 },
255 None => MessageType::EncryptedSym {
256 salt: self.salt,
257 nonce: self.nonce.into(),
258 },
259 };
260 let header = Header {
261 msg_type,
262 issuer: *self.issuer.fingerprint(),
263 };
264
265 let aad = header.as_bytes()?;
266 let payload = crypto::encrypt_symmetric(&self.key, &self.nonce, &self.payload, &aad)?;
267 Ok(Message { header, payload })
268 }
269}
270
271impl MessageFinal for AsmEncryptedMessage<'_> {
272 type R = Result<Message>;
273
274 fn finalize(self) -> Self::R {
275 let msg_type = match self.signature {
276 Some(s) => MessageType::SignedEncryptedAsm {
277 signature: s,
278 keys: self.recipients,
279 nonce: self.nonce.into(),
280 },
281 None => MessageType::EncryptedAsm {
282 keys: self.recipients,
283 nonce: self.nonce.into(),
284 },
285 };
286 let header = Header {
287 msg_type,
288 issuer: *self.issuer.fingerprint(),
289 };
290
291 let aad = header.as_bytes()?;
292 let payload = crypto::encrypt_symmetric(&self.key, &self.nonce, &self.payload, &aad)?;
293 Ok(Message { header, payload })
294 }
295}