1use alloc::string::ToString;
8use alloc::vec::Vec;
9
10use crate::artifacts::{PublicKey, UserSecretKey, VerifyingKey};
11use crate::client::*;
12use crate::error::Error;
13use crate::identity::EncryptionPolicy;
14
15use aead::{Aead, KeyInit};
16use aes_gcm::{Aes128Gcm, Nonce};
17use ibe::kem::cgw_kv::CGWKV;
18use ibs::gg::Signer;
19use rand::{CryptoRng, RngCore};
20
21#[cfg(feature = "stream")]
22pub mod stream;
23
24#[derive(Debug)]
26pub struct SealerMemoryConfig {
27 key: [u8; KEY_SIZE],
28 nonce: [u8; IV_SIZE],
29}
30
31#[derive(Debug)]
33pub struct UnsealerMemoryConfig {
34 message_len: usize,
35}
36
37impl SealerConfig for SealerMemoryConfig {}
38impl super::sealed::SealerConfig for SealerMemoryConfig {}
39
40impl UnsealerConfig for UnsealerMemoryConfig {}
41impl super::sealed::UnsealerConfig for UnsealerMemoryConfig {}
42
43impl From<aead::Error> for Error {
44 fn from(_: aead::Error) -> Self {
45 Self::Symmetric
46 }
47}
48
49impl From<aes_gcm::aes::cipher::InvalidLength> for Error {
50 fn from(_: aes_gcm::aes::cipher::InvalidLength) -> Self {
51 Self::Symmetric
52 }
53}
54
55#[derive(Debug, Serialize, Deserialize)]
56struct MessageAndSignature {
57 message: Vec<u8>,
58 sig: SignatureExt,
59}
60
61impl<'r, R: RngCore + CryptoRng> Sealer<'r, R, SealerMemoryConfig> {
62 pub fn new(
64 mpk: &PublicKey<CGWKV>,
65 policies: &EncryptionPolicy,
66 pub_sign_key: &SigningKeyExt,
67 rng: &'r mut R,
68 ) -> Result<Self, Error> {
69 let (header, ss) = Header::new(mpk, policies, rng)?;
70 let Algorithm::Aes128Gcm(iv) = header.algo;
71
72 let mut key = [0u8; KEY_SIZE];
73 let mut nonce = [0u8; IV_SIZE];
74 key.copy_from_slice(&ss.0[..KEY_SIZE]);
75 nonce.copy_from_slice(&iv.0[..IV_SIZE]);
76
77 Ok(Self {
78 rng,
79 header,
80 pub_sign_key: pub_sign_key.clone(),
81 priv_sign_key: None,
82 config: SealerMemoryConfig { key, nonce },
83 })
84 }
85
86 pub fn seal(mut self, message: impl AsRef<[u8]>) -> Result<Vec<u8>, Error> {
88 let mut out = Vec::with_capacity(message.as_ref().len() + 1024);
89
90 out.extend_from_slice(&PRELUDE);
91 out.extend_from_slice(&VERSION_V3.to_be_bytes());
92
93 self.header = self.header.with_mode(Mode::InMemory {
94 size: message.as_ref().len().try_into()?,
95 });
96
97 let header_buf = crate::bincode_compat::serialize(&self.header)?;
98 out.extend_from_slice(&u32::try_from(header_buf.len())?.to_be_bytes());
99 out.extend_from_slice(&header_buf);
100
101 let signer = Signer::new().chain(header_buf);
102 let h_sig = signer.clone().sign(&self.pub_sign_key.key.0, self.rng);
103
104 let h_sig_ext = SignatureExt {
105 sig: h_sig,
106 pol: self.pub_sign_key.policy.clone(),
107 };
108
109 let h_sig_ext_bytes = crate::bincode_compat::serialize(&h_sig_ext)?;
110 out.extend_from_slice(&u32::try_from(h_sig_ext_bytes.len())?.to_be_bytes());
111 out.extend_from_slice(&h_sig_ext_bytes);
112
113 let m_sig_key = self.priv_sign_key.unwrap_or(self.pub_sign_key);
114 let m_sig = signer.chain(&message).sign(&m_sig_key.key.0, self.rng);
115
116 let aead = Aes128Gcm::new_from_slice(&self.config.key)?;
117 let nonce = Nonce::from(self.config.nonce);
118
119 let enc_input = crate::bincode_compat::serialize(&MessageAndSignature {
120 message: message.as_ref().to_vec(),
121 sig: SignatureExt {
122 sig: m_sig,
123 pol: m_sig_key.policy,
124 },
125 })?;
126
127 let ciphertext = aead.encrypt(&nonce, enc_input.as_ref())?;
128
129 out.extend_from_slice(&ciphertext);
130
131 Ok(out)
132 }
133}
134
135impl Unsealer<Vec<u8>, UnsealerMemoryConfig> {
136 pub fn new(input: impl AsRef<[u8]>, vk: &VerifyingKey) -> Result<Self, Error> {
138 let b = input.as_ref();
139 let (preamble_bytes, b) = try_split_at(b, PREAMBLE_SIZE, "preamble")?;
140 let (version, header_len) = preamble_checked(preamble_bytes)?;
141
142 let (header_bytes, b) = try_split_at(b, header_len, "header")?;
143 let (h_sig_len_bytes, b) = try_split_at(b, SIG_SIZE_SIZE, "header signature length")?;
144 let h_sig_len = u32::from_be_bytes(h_sig_len_bytes.try_into()?);
145 let (h_sig_bytes, ct) = try_split_at(b, h_sig_len as usize, "header signature")?;
146
147 let h_sig_ext: SignatureExt = crate::bincode_compat::deserialize(h_sig_bytes)?;
148 let id = h_sig_ext.pol.derive_ibs()?;
149
150 let verifier = Verifier::default().chain(header_bytes);
151
152 if !verifier.clone().verify(&vk.0, &h_sig_ext.sig, &id) {
153 return Err(Error::IncorrectSignature);
154 }
155
156 let header: Header = crate::bincode_compat::deserialize(header_bytes)?;
157 let message_len = match header.mode {
158 Mode::InMemory { size } => size as usize,
159 _ => return Err(Error::ModeNotSupported(header.mode)),
160 };
161
162 Ok(Self {
163 version,
164 header,
165 pub_id: h_sig_ext.pol,
166 r: ct.to_vec(),
167 verifier,
168 vk: vk.clone(),
169 config: UnsealerMemoryConfig { message_len },
170 })
171 }
172
173 pub fn unseal(
175 self,
176 ident: &str,
177 usk: &UserSecretKey<CGWKV>,
178 ) -> Result<(Vec<u8>, VerificationResult), Error> {
179 let rec_info = self
180 .header
181 .recipients
182 .get(ident)
183 .ok_or_else(|| Error::UnknownIdentifier(ident.to_string()))?;
184
185 let ss = rec_info.decaps(usk)?;
186 let key = &ss.0[..KEY_SIZE];
187
188 let Algorithm::Aes128Gcm(iv) = self.header.algo;
189
190 let aead = Aes128Gcm::new_from_slice(key)?;
191 let nonce = Nonce::from(iv.0);
192
193 let plain = aead.decrypt(&nonce, &*self.r)?;
194
195 let msg: MessageAndSignature = crate::bincode_compat::deserialize(&plain)?;
196 let id = msg.sig.pol.derive_ibs()?;
197
198 if !self
199 .verifier
200 .chain(&msg.message)
201 .verify(&self.vk.0, &msg.sig.sig, &id)
202 {
203 return Err(Error::IncorrectSignature);
204 }
205
206 debug_assert_eq!(self.config.message_len, msg.message.len());
207
208 let private = if self.pub_id == msg.sig.pol {
209 None
210 } else {
211 Some(msg.sig.pol)
212 };
213
214 Ok((
215 msg.message,
216 VerificationResult {
217 public: self.pub_id,
218 private,
219 },
220 ))
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227 use crate::test::TestSetup;
228
229 #[test]
230 fn test_seal_memory() {
231 let mut rng = rand::thread_rng();
232 let setup = TestSetup::new(&mut rng);
233
234 let pub_sign_key = &setup.signing_keys[0];
236 let priv_sign_key = &setup.signing_keys[1];
238
239 let input = b"SECRET DATA";
240 let sealed = Sealer::<_, SealerMemoryConfig>::new(
241 &setup.ibe_pk,
242 &setup.policy,
243 &pub_sign_key,
244 &mut rng,
245 )
246 .unwrap()
247 .with_priv_signing_key(priv_sign_key.clone())
248 .seal(input)
249 .unwrap();
250
251 let usk = &setup.usks[2];
253 let (original, verified_policy) =
254 Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
255 .unwrap()
256 .unseal("Bob", &usk)
257 .unwrap();
258
259 assert_eq!(&input.to_vec(), &original);
260
261 let expected = VerificationResult {
262 public: setup.policies[0].clone(),
263 private: Some(setup.policies[1].clone()),
264 };
265
266 assert_eq!(&verified_policy, &expected);
267 }
268
269 #[test]
270 fn test_seal_unseal_wrong_usk() {
271 let mut rng = rand::thread_rng();
272 let setup = TestSetup::new(&mut rng);
273
274 let pub_sign_key = &setup.signing_keys[0];
275 let priv_sign_key = &setup.signing_keys[1];
276
277 let input = b"SECRET DATA";
278 let sealed = Sealer::<_, SealerMemoryConfig>::new(
279 &setup.ibe_pk,
280 &setup.policy,
281 &pub_sign_key,
282 &mut rng,
283 )
284 .unwrap()
285 .with_priv_signing_key(priv_sign_key.clone())
286 .seal(input)
287 .unwrap();
288
289 let usk = &setup.usks[4];
291 let res = Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
292 .unwrap()
293 .unseal("Charlie", &usk);
294
295 assert!(matches!(res, Err(Error::KEM)));
296 }
297
298 #[test]
299 fn test_seal_unseal_wrong_id() {
300 let mut rng = rand::thread_rng();
301 let setup = TestSetup::new(&mut rng);
302
303 let pub_sign_key = &setup.signing_keys[0];
304 let priv_sign_key = &setup.signing_keys[1];
305
306 let input = b"SECRET DATA";
307 let sealed = Sealer::<_, SealerMemoryConfig>::new(
308 &setup.ibe_pk,
309 &setup.policy,
310 &pub_sign_key,
311 &mut rng,
312 )
313 .unwrap()
314 .with_priv_signing_key(priv_sign_key.clone())
315 .seal(input)
316 .unwrap();
317
318 let usk = &setup.usks[4];
319 let res = Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
320 .unwrap()
321 .unseal("Daniel", &usk);
322
323 assert!(matches!(res, Err(Error::UnknownIdentifier(_))));
324 }
325
326 #[test]
327 fn test_unseal_rejects_empty_input() {
328 let mut rng = rand::thread_rng();
329 let setup = TestSetup::new(&mut rng);
330 let res = Unsealer::<_, UnsealerMemoryConfig>::new(&[] as &[u8], &setup.ibs_pk);
331 assert!(res.is_err());
333 }
334
335 #[test]
336 fn test_unseal_rejects_truncated_after_preamble() {
337 let mut rng = rand::thread_rng();
338 let setup = TestSetup::new(&mut rng);
339
340 let pub_sign_key = &setup.signing_keys[0];
341 let priv_sign_key = &setup.signing_keys[1];
342
343 let sealed = Sealer::<_, SealerMemoryConfig>::new(
344 &setup.ibe_pk,
345 &setup.policy,
346 &pub_sign_key,
347 &mut rng,
348 )
349 .unwrap()
350 .with_priv_signing_key(priv_sign_key.clone())
351 .seal(b"SECRET DATA")
352 .unwrap();
353
354 let mut truncated = sealed;
356 truncated.truncate(PREAMBLE_SIZE + 1);
357
358 let res = Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk);
359 match res {
360 Err(Error::FormatViolation(_)) => {}
361 other => panic!("expected FormatViolation, got {:?}", other),
362 }
363 }
364
365 #[test]
366 fn test_unseal_rejects_garbage_input() {
367 let mut rng = rand::thread_rng();
368 let setup = TestSetup::new(&mut rng);
369 let garbage = vec![0u8; 1024];
371 let res = Unsealer::<_, UnsealerMemoryConfig>::new(garbage, &setup.ibs_pk);
372 assert!(res.is_err());
373 }
374
375 fn seal_memory<R: rand::RngCore + rand::CryptoRng>(setup: &TestSetup, rng: &mut R) -> Vec<u8> {
376 let pub_sign_key = &setup.signing_keys[0];
377 let priv_sign_key = &setup.signing_keys[1];
378 Sealer::<_, SealerMemoryConfig>::new(&setup.ibe_pk, &setup.policy, pub_sign_key, rng)
379 .unwrap()
380 .with_priv_signing_key(priv_sign_key.clone())
381 .seal(b"SECRET DATA")
382 .unwrap()
383 }
384
385 #[test]
386 fn test_unseal_rejects_input_shorter_than_preamble() {
387 let mut rng = rand::thread_rng();
388 let setup = TestSetup::new(&mut rng);
389 let buf = vec![0u8; PREAMBLE_SIZE - 1];
391 match Unsealer::<_, UnsealerMemoryConfig>::new(buf, &setup.ibs_pk) {
392 Err(Error::FormatViolation(msg)) => assert!(msg.contains("preamble")),
393 other => panic!("expected FormatViolation(preamble), got {:?}", other),
394 }
395 }
396
397 #[test]
398 fn test_unseal_rejects_truncated_inside_header() {
399 let mut rng = rand::thread_rng();
400 let setup = TestSetup::new(&mut rng);
401 let sealed = seal_memory(&setup, &mut rng);
402
403 let mut truncated = sealed;
405 truncated.truncate(PREAMBLE_SIZE + 4);
406
407 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
408 Err(Error::FormatViolation(msg)) => assert!(msg.contains("header")),
409 other => panic!("expected FormatViolation(header), got {:?}", other),
410 }
411 }
412
413 #[test]
414 fn test_unseal_rejects_truncated_before_sig_len() {
415 let mut rng = rand::thread_rng();
416 let setup = TestSetup::new(&mut rng);
417 let sealed = seal_memory(&setup, &mut rng);
418
419 let (_, header_len) =
422 preamble_checked(&sealed[..PREAMBLE_SIZE]).expect("preamble should parse");
423 let cut = PREAMBLE_SIZE + header_len;
424
425 assert!(cut + SIG_SIZE_SIZE <= sealed.len());
427
428 let truncated = sealed[..cut + 1].to_vec();
429
430 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
431 Err(Error::FormatViolation(msg)) => {
432 assert!(msg.contains("header signature length"))
433 }
434 other => panic!(
435 "expected FormatViolation(header signature length), got {:?}",
436 other
437 ),
438 }
439 }
440
441 #[test]
442 fn test_unseal_rejects_truncated_inside_sig_bytes() {
443 let mut rng = rand::thread_rng();
444 let setup = TestSetup::new(&mut rng);
445 let sealed = seal_memory(&setup, &mut rng);
446
447 let (_, header_len) =
448 preamble_checked(&sealed[..PREAMBLE_SIZE]).expect("preamble should parse");
449 let cut = PREAMBLE_SIZE + header_len + SIG_SIZE_SIZE + 1;
451 assert!(cut < sealed.len(), "sealed output unexpectedly short");
452
453 let truncated = sealed[..cut].to_vec();
454
455 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
456 Err(Error::FormatViolation(msg)) => {
457 assert!(msg.contains("header signature") && !msg.contains("length"))
458 }
459 other => panic!(
460 "expected FormatViolation(header signature), got {:?}",
461 other
462 ),
463 }
464 }
465
466 #[test]
467 fn test_unseal_rejects_wrong_prelude() {
468 let mut rng = rand::thread_rng();
469 let setup = TestSetup::new(&mut rng);
470 let mut sealed = seal_memory(&setup, &mut rng);
471
472 sealed[0] = sealed[0].wrapping_add(1);
475
476 match Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk) {
477 Err(Error::NotPostGuard) => {}
478 other => panic!("expected NotPostGuard, got {:?}", other),
479 }
480 }
481}