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, Policy};
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)]
68struct MessageAndSignature {
69 message: Vec<u8>,
70 sig: SignatureExt,
71 pub_pol: Policy,
72}
73
74#[derive(Debug, Serialize, Deserialize)]
81struct MessageAndSignaturePrefix {
82 message: Vec<u8>,
83 sig: SignatureExt,
84}
85
86impl<'r, R: RngCore + CryptoRng> Sealer<'r, R, SealerMemoryConfig> {
87 pub fn new(
89 mpk: &PublicKey<CGWKV>,
90 policies: &EncryptionPolicy,
91 pub_sign_key: &SigningKeyExt,
92 rng: &'r mut R,
93 ) -> Result<Self, Error> {
94 let (header, ss) = Header::new(mpk, policies, rng)?;
95 let Algorithm::Aes128Gcm(iv) = header.algo;
96
97 let mut key = [0u8; KEY_SIZE];
98 let mut nonce = [0u8; IV_SIZE];
99 key.copy_from_slice(&ss.0[..KEY_SIZE]);
100 nonce.copy_from_slice(&iv.0[..IV_SIZE]);
101
102 Ok(Self {
103 rng,
104 header,
105 pub_sign_key: crate::client::canonical_signing_key(pub_sign_key),
106 priv_sign_key: None,
107 config: SealerMemoryConfig { key, nonce },
108 })
109 }
110
111 pub fn seal(mut self, message: impl AsRef<[u8]>) -> Result<Vec<u8>, Error> {
113 let mut out = Vec::with_capacity(message.as_ref().len() + 1024);
114
115 out.extend_from_slice(&PRELUDE);
116 out.extend_from_slice(&VERSION_2.to_be_bytes());
117
118 self.header = self.header.with_mode(Mode::InMemory {
119 size: message.as_ref().len().try_into()?,
120 });
121
122 let header_buf = crate::bincode_compat::serialize(&self.header)?;
123 out.extend_from_slice(&u32::try_from(header_buf.len())?.to_be_bytes());
124 out.extend_from_slice(&header_buf);
125
126 let signer = Signer::new().chain(header_buf);
127 let h_sig = signer.clone().sign(&self.pub_sign_key.key.0, self.rng);
128
129 let h_sig_ext = SignatureExt {
130 sig: h_sig,
131 pol: self.pub_sign_key.policy.clone(),
132 };
133
134 let h_sig_ext_bytes = crate::bincode_compat::serialize(&h_sig_ext)?;
135 out.extend_from_slice(&u32::try_from(h_sig_ext_bytes.len())?.to_be_bytes());
136 out.extend_from_slice(&h_sig_ext_bytes);
137
138 let pub_pol = self.pub_sign_key.policy.clone();
139 let m_sig_key = self.priv_sign_key.unwrap_or(self.pub_sign_key);
140 let m_sig = signer.chain(&message).sign(&m_sig_key.key.0, self.rng);
141
142 let aead = Aes128Gcm::new_from_slice(&self.config.key)?;
143 let nonce = Nonce::from(self.config.nonce);
144
145 let enc_input = crate::bincode_compat::serialize(&MessageAndSignature {
146 message: message.as_ref().to_vec(),
147 sig: SignatureExt {
148 sig: m_sig,
149 pol: m_sig_key.policy,
150 },
151 pub_pol,
152 })?;
153
154 let ciphertext = aead.encrypt(&nonce, enc_input.as_ref())?;
155
156 out.extend_from_slice(&ciphertext);
157
158 Ok(out)
159 }
160}
161
162impl Unsealer<Vec<u8>, UnsealerMemoryConfig> {
163 pub fn new(input: impl AsRef<[u8]>, vk: &VerifyingKey) -> Result<Self, Error> {
165 let b = input.as_ref();
166 let (preamble_bytes, b) = try_split_at(b, PREAMBLE_SIZE, "preamble")?;
167 let (version, header_len) = preamble_checked(preamble_bytes)?;
168
169 let (header_bytes, b) = try_split_at(b, header_len, "header")?;
170 let (h_sig_len_bytes, b) = try_split_at(b, SIG_SIZE_SIZE, "header signature length")?;
171 let h_sig_len = u32::from_be_bytes(h_sig_len_bytes.try_into()?);
172 let (h_sig_bytes, ct) = try_split_at(b, h_sig_len as usize, "header signature")?;
173
174 let h_sig_ext: SignatureExt = crate::bincode_compat::deserialize(h_sig_bytes)?;
175 let id = h_sig_ext.pol.derive_ibs()?;
176
177 let verifier = Verifier::default().chain(header_bytes);
178
179 if !verifier.clone().verify(&vk.0, &h_sig_ext.sig, &id) {
180 return Err(Error::IncorrectSignature);
181 }
182
183 let header: Header = crate::bincode_compat::deserialize(header_bytes)?;
184 let message_len = match header.mode {
185 Mode::InMemory { size } => size as usize,
186 _ => return Err(Error::ModeNotSupported(header.mode)),
187 };
188
189 Ok(Self {
190 version,
191 header,
192 pub_id: h_sig_ext.pol,
193 r: ct.to_vec(),
194 verifier,
195 vk: vk.clone(),
196 config: UnsealerMemoryConfig { message_len },
197 })
198 }
199
200 pub fn unseal(
202 self,
203 ident: &str,
204 usk: &UserSecretKey<CGWKV>,
205 ) -> Result<(Vec<u8>, VerificationResult), Error> {
206 let rec_info = self
207 .header
208 .recipients
209 .get(ident)
210 .ok_or_else(|| Error::UnknownIdentifier(ident.to_string()))?;
211
212 let ss = rec_info.decaps(usk)?;
213 let key = &ss.0[..KEY_SIZE];
214
215 let Algorithm::Aes128Gcm(iv) = self.header.algo;
216
217 let aead = Aes128Gcm::new_from_slice(key)?;
218 let nonce = Nonce::from(iv.0);
219
220 let plain = aead.decrypt(&nonce, &*self.r)?;
221
222 let (msg, read): (MessageAndSignaturePrefix, usize) =
223 crate::bincode_compat::deserialize_with_len(&plain)?;
224
225 if let Some(trailing) = plain.get(read..).filter(|t| !t.is_empty()) {
233 let sealed_pub_pol: Policy = crate::bincode_compat::deserialize(trailing)?;
234
235 if sealed_pub_pol != self.pub_id {
236 return Err(Error::IncorrectSignature);
237 }
238 }
239
240 let id = msg.sig.pol.derive_ibs()?;
241
242 if !self
243 .verifier
244 .chain(&msg.message)
245 .verify(&self.vk.0, &msg.sig.sig, &id)
246 {
247 return Err(Error::IncorrectSignature);
248 }
249
250 debug_assert_eq!(self.config.message_len, msg.message.len());
251
252 let private = if self.pub_id == msg.sig.pol {
253 None
254 } else {
255 Some(msg.sig.pol)
256 };
257
258 Ok((
259 msg.message,
260 VerificationResult {
261 public: self.pub_id,
262 private,
263 },
264 ))
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271 use crate::test::TestSetup;
272
273 #[test]
274 fn test_seal_memory() {
275 let mut rng = rand::thread_rng();
276 let setup = TestSetup::new(&mut rng);
277
278 let pub_sign_key = &setup.signing_keys[0];
280 let priv_sign_key = &setup.signing_keys[1];
282
283 let input = b"SECRET DATA";
284 let sealed = Sealer::<_, SealerMemoryConfig>::new(
285 &setup.ibe_pk,
286 &setup.policy,
287 pub_sign_key,
288 &mut rng,
289 )
290 .unwrap()
291 .with_priv_signing_key(priv_sign_key.clone())
292 .seal(input)
293 .unwrap();
294
295 let usk = &setup.usks[2];
297 let (original, verified_policy) =
298 Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
299 .unwrap()
300 .unseal("Bob", usk)
301 .unwrap();
302
303 assert_eq!(&input.to_vec(), &original);
304
305 let expected = VerificationResult {
306 public: setup.policies[0].clone(),
307 private: Some(setup.policies[1].clone()),
308 };
309
310 assert_eq!(&verified_policy, &expected);
311 }
312
313 #[test]
314 fn test_seal_unseal_wrong_usk() {
315 let mut rng = rand::thread_rng();
316 let setup = TestSetup::new(&mut rng);
317
318 let pub_sign_key = &setup.signing_keys[0];
319 let priv_sign_key = &setup.signing_keys[1];
320
321 let input = b"SECRET DATA";
322 let sealed = Sealer::<_, SealerMemoryConfig>::new(
323 &setup.ibe_pk,
324 &setup.policy,
325 pub_sign_key,
326 &mut rng,
327 )
328 .unwrap()
329 .with_priv_signing_key(priv_sign_key.clone())
330 .seal(input)
331 .unwrap();
332
333 let usk = &setup.usks[4];
335 let res = Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
336 .unwrap()
337 .unseal("Charlie", usk);
338
339 assert!(matches!(res, Err(Error::KEM)));
340 }
341
342 #[test]
343 fn test_seal_unseal_wrong_id() {
344 let mut rng = rand::thread_rng();
345 let setup = TestSetup::new(&mut rng);
346
347 let pub_sign_key = &setup.signing_keys[0];
348 let priv_sign_key = &setup.signing_keys[1];
349
350 let input = b"SECRET DATA";
351 let sealed = Sealer::<_, SealerMemoryConfig>::new(
352 &setup.ibe_pk,
353 &setup.policy,
354 pub_sign_key,
355 &mut rng,
356 )
357 .unwrap()
358 .with_priv_signing_key(priv_sign_key.clone())
359 .seal(input)
360 .unwrap();
361
362 let usk = &setup.usks[4];
363 let res = Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk)
364 .unwrap()
365 .unseal("Daniel", usk);
366
367 assert!(matches!(res, Err(Error::UnknownIdentifier(_))));
368 }
369
370 #[test]
371 fn test_unseal_rejects_empty_input() {
372 let mut rng = rand::thread_rng();
373 let setup = TestSetup::new(&mut rng);
374 let res = Unsealer::<_, UnsealerMemoryConfig>::new(&[] as &[u8], &setup.ibs_pk);
375 assert!(res.is_err());
377 }
378
379 #[test]
380 fn test_unseal_rejects_truncated_after_preamble() {
381 let mut rng = rand::thread_rng();
382 let setup = TestSetup::new(&mut rng);
383
384 let pub_sign_key = &setup.signing_keys[0];
385 let priv_sign_key = &setup.signing_keys[1];
386
387 let sealed = Sealer::<_, SealerMemoryConfig>::new(
388 &setup.ibe_pk,
389 &setup.policy,
390 pub_sign_key,
391 &mut rng,
392 )
393 .unwrap()
394 .with_priv_signing_key(priv_sign_key.clone())
395 .seal(b"SECRET DATA")
396 .unwrap();
397
398 let mut truncated = sealed;
400 truncated.truncate(PREAMBLE_SIZE + 1);
401
402 let res = Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk);
403 match res {
404 Err(Error::FormatViolation(_)) => {}
405 other => panic!("expected FormatViolation, got {:?}", other),
406 }
407 }
408
409 #[test]
410 fn test_unseal_rejects_garbage_input() {
411 let mut rng = rand::thread_rng();
412 let setup = TestSetup::new(&mut rng);
413 let garbage = vec![0u8; 1024];
415 let res = Unsealer::<_, UnsealerMemoryConfig>::new(garbage, &setup.ibs_pk);
416 assert!(res.is_err());
417 }
418
419 fn seal_memory<R: rand::RngCore + rand::CryptoRng>(setup: &TestSetup, rng: &mut R) -> Vec<u8> {
420 let pub_sign_key = &setup.signing_keys[0];
421 let priv_sign_key = &setup.signing_keys[1];
422 Sealer::<_, SealerMemoryConfig>::new(&setup.ibe_pk, &setup.policy, pub_sign_key, rng)
423 .unwrap()
424 .with_priv_signing_key(priv_sign_key.clone())
425 .seal(b"SECRET DATA")
426 .unwrap()
427 }
428
429 #[test]
430 fn test_unseal_rejects_input_shorter_than_preamble() {
431 let mut rng = rand::thread_rng();
432 let setup = TestSetup::new(&mut rng);
433 let buf = vec![0u8; PREAMBLE_SIZE - 1];
435 match Unsealer::<_, UnsealerMemoryConfig>::new(buf, &setup.ibs_pk) {
436 Err(Error::FormatViolation(msg)) => assert!(msg.contains("preamble")),
437 other => panic!("expected FormatViolation(preamble), got {:?}", other),
438 }
439 }
440
441 #[test]
442 fn test_unseal_rejects_truncated_inside_header() {
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 mut truncated = sealed;
449 truncated.truncate(PREAMBLE_SIZE + 4);
450
451 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
452 Err(Error::FormatViolation(msg)) => assert!(msg.contains("header")),
453 other => panic!("expected FormatViolation(header), got {:?}", other),
454 }
455 }
456
457 #[test]
458 fn test_unseal_rejects_truncated_before_sig_len() {
459 let mut rng = rand::thread_rng();
460 let setup = TestSetup::new(&mut rng);
461 let sealed = seal_memory(&setup, &mut rng);
462
463 let (_, header_len) =
466 preamble_checked(&sealed[..PREAMBLE_SIZE]).expect("preamble should parse");
467 let cut = PREAMBLE_SIZE + header_len;
468
469 assert!(cut + SIG_SIZE_SIZE <= sealed.len());
471
472 let truncated = sealed[..cut + 1].to_vec();
473
474 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
475 Err(Error::FormatViolation(msg)) => {
476 assert!(msg.contains("header signature length"))
477 }
478 other => panic!(
479 "expected FormatViolation(header signature length), got {:?}",
480 other
481 ),
482 }
483 }
484
485 #[test]
486 fn test_unseal_rejects_truncated_inside_sig_bytes() {
487 let mut rng = rand::thread_rng();
488 let setup = TestSetup::new(&mut rng);
489 let sealed = seal_memory(&setup, &mut rng);
490
491 let (_, header_len) =
492 preamble_checked(&sealed[..PREAMBLE_SIZE]).expect("preamble should parse");
493 let cut = PREAMBLE_SIZE + header_len + SIG_SIZE_SIZE + 1;
495 assert!(cut < sealed.len(), "sealed output unexpectedly short");
496
497 let truncated = sealed[..cut].to_vec();
498
499 match Unsealer::<_, UnsealerMemoryConfig>::new(truncated, &setup.ibs_pk) {
500 Err(Error::FormatViolation(msg)) => {
501 assert!(msg.contains("header signature") && !msg.contains("length"))
502 }
503 other => panic!(
504 "expected FormatViolation(header signature), got {:?}",
505 other
506 ),
507 }
508 }
509
510 fn split_container(sealed: &[u8]) -> (&[u8], &[u8], &[u8]) {
513 let (_, header_len) =
514 preamble_checked(&sealed[..PREAMBLE_SIZE]).expect("preamble should parse");
515 let sig_len_at = PREAMBLE_SIZE + header_len;
516 let sig_len = u32::from_be_bytes(
517 sealed[sig_len_at..sig_len_at + SIG_SIZE_SIZE]
518 .try_into()
519 .unwrap(),
520 ) as usize;
521 let sig_at = sig_len_at + SIG_SIZE_SIZE;
522
523 (
524 &sealed[PREAMBLE_SIZE..sig_len_at],
525 &sealed[sig_at..sig_at + sig_len],
526 &sealed[sig_at + sig_len..],
527 )
528 }
529
530 fn swap_header_signature<R: rand::RngCore + rand::CryptoRng>(
534 sealed: &[u8],
535 attacker: &crate::artifacts::SigningKeyExt,
536 rng: &mut R,
537 ) -> Vec<u8> {
538 let (header_bytes, _, ct) = split_container(sealed);
539
540 let h_sig_ext = SignatureExt {
541 sig: Signer::new().chain(header_bytes).sign(&attacker.key.0, rng),
542 pol: attacker.policy.clone(),
543 };
544 let h_sig_ext_bytes = crate::bincode_compat::serialize(&h_sig_ext).unwrap();
545
546 let mut out = sealed[..PREAMBLE_SIZE + header_bytes.len()].to_vec();
547 out.extend_from_slice(&(h_sig_ext_bytes.len() as u32).to_be_bytes());
548 out.extend_from_slice(&h_sig_ext_bytes);
549 out.extend_from_slice(ct);
550
551 out
552 }
553
554 fn strip_pub_pol(sealed: &[u8], ident: &str, usk: &UserSecretKey<CGWKV>) -> Vec<u8> {
558 let (header_bytes, _, ct) = split_container(sealed);
559 let header: Header = crate::bincode_compat::deserialize(header_bytes).unwrap();
560 let ss = header.recipients.get(ident).unwrap().decaps(usk).unwrap();
561
562 let Algorithm::Aes128Gcm(iv) = header.algo;
563 let aead = Aes128Gcm::new_from_slice(&ss.0[..KEY_SIZE]).unwrap();
564 let nonce = Nonce::from(iv.0);
565
566 let plain = aead.decrypt(&nonce, ct).unwrap();
567 let (_, read): (MessageAndSignaturePrefix, usize) =
568 crate::bincode_compat::deserialize_with_len(&plain).unwrap();
569 assert!(
570 read < plain.len(),
571 "the sealer wrote no appended policy — nothing to strip"
572 );
573
574 let mut out = sealed[..sealed.len() - ct.len()].to_vec();
575 out.extend_from_slice(&aead.encrypt(&nonce, &plain[..read]).unwrap());
576
577 out
578 }
579
580 #[test]
584 fn test_unseal_rejects_swapped_header_signature() {
585 let mut rng = rand::thread_rng();
586 let setup = TestSetup::new(&mut rng);
587 let sealed = seal_memory(&setup, &mut rng);
588
589 let swapped = swap_header_signature(&sealed, &setup.signing_keys[4], &mut rng);
592
593 let unsealer = Unsealer::<_, UnsealerMemoryConfig>::new(swapped, &setup.ibs_pk)
594 .expect("the swapped header signature still verifies — that is the attack");
595 assert_eq!(
596 unsealer.pub_id, setup.policies[4],
597 "the container now claims the attacker as public sender"
598 );
599
600 match unsealer.unseal("Bob", &setup.usks[2]) {
601 Err(Error::IncorrectSignature) => {}
602 other => panic!("expected IncorrectSignature, got {:?}", other),
603 }
604 }
605
606 #[test]
610 fn test_unseal_accepts_container_without_appended_policy() {
611 let mut rng = rand::thread_rng();
612 let setup = TestSetup::new(&mut rng);
613 let sealed = seal_memory(&setup, &mut rng);
614 let legacy = strip_pub_pol(&sealed, "Bob", &setup.usks[2]);
615
616 let (plain, verified) = Unsealer::<_, UnsealerMemoryConfig>::new(legacy, &setup.ibs_pk)
617 .unwrap()
618 .unseal("Bob", &setup.usks[2])
619 .expect("a container without the appended policy must still open");
620
621 assert_eq!(&plain, b"SECRET DATA");
622 assert_eq!(
623 verified,
624 VerificationResult {
625 public: setup.policies[0].clone(),
626 private: Some(setup.policies[1].clone()),
627 }
628 );
629 }
630
631 #[test]
632 fn test_unseal_rejects_wrong_prelude() {
633 let mut rng = rand::thread_rng();
634 let setup = TestSetup::new(&mut rng);
635 let mut sealed = seal_memory(&setup, &mut rng);
636
637 sealed[0] = sealed[0].wrapping_add(1);
640
641 match Unsealer::<_, UnsealerMemoryConfig>::new(sealed, &setup.ibs_pk) {
642 Err(Error::NotPostGuard) => {}
643 other => panic!("expected NotPostGuard, got {:?}", other),
644 }
645 }
646}