1use alloc::string::ToString;
4
5use crate::artifacts::{PublicKey, SigningKeyExt, UserSecretKey, VerifyingKey};
6use crate::client::*;
7use crate::error::Error;
8use crate::identity::{EncryptionPolicy, Policy};
9use ibe::kem::cgw_kv::CGWKV;
10use ibs::gg::{Identity, Signature, Signer, Verifier, SIG_BYTES};
11
12use aead::stream::{DecryptorBE32, EncryptorBE32};
13use aead::KeyInit;
14use aes_gcm::Aes128Gcm;
15use alloc::vec::Vec;
16use futures::io::{AsyncRead, AsyncWrite};
17use futures::io::{AsyncReadExt, AsyncWriteExt};
18use futures::TryFutureExt;
19use rand::{CryptoRng, RngCore};
20
21#[derive(Debug)]
23pub struct SealerStreamConfig {
24 segment_size: u32,
26 key: [u8; KEY_SIZE],
28 nonce: [u8; STREAM_NONCE_SIZE],
30}
31
32#[derive(Debug)]
34pub struct UnsealerStreamConfig {
35 segment_size: u32,
36}
37
38impl SealerConfig for SealerStreamConfig {}
39impl UnsealerConfig for UnsealerStreamConfig {}
40impl crate::client::sealed::SealerConfig for SealerStreamConfig {}
41impl crate::client::sealed::UnsealerConfig for UnsealerStreamConfig {}
42
43impl<'r, Rng: RngCore + CryptoRng> Sealer<'r, Rng, SealerStreamConfig> {
44 pub fn new(
46 pk: &PublicKey<CGWKV>,
47 policies: &EncryptionPolicy,
48 pub_sign_key: &SigningKeyExt,
49 rng: &'r mut Rng,
50 ) -> Result<Self, Error> {
51 let (header, ss) = Header::new(pk, policies, rng)?;
52
53 let (segment_size, _) = stream_mode_checked(&header)?;
54 let Algorithm::Aes128Gcm(iv) = header.algo;
55
56 let mut key = [0u8; KEY_SIZE];
57 let mut nonce = [0u8; STREAM_NONCE_SIZE];
58
59 key.copy_from_slice(&ss.0[..KEY_SIZE]);
60 nonce.copy_from_slice(&iv.0[..STREAM_NONCE_SIZE]);
61
62 Ok(Sealer {
63 rng,
64 header,
65 pub_sign_key: crate::client::canonical_signing_key(pub_sign_key),
66 priv_sign_key: None,
67 config: SealerStreamConfig {
68 segment_size,
69 key,
70 nonce,
71 },
72 })
73 }
74
75 pub fn with_size_hint(mut self, size_hint: (u64, Option<u64>)) -> Self {
79 self.header.mode = Mode::Streaming {
80 segment_size: self.config.segment_size,
81 size_hint,
82 };
83
84 self
85 }
86
87 pub async fn seal<R, W>(self, mut r: R, mut w: W) -> Result<(), Error>
89 where
90 R: AsyncRead + Unpin,
91 W: AsyncWrite + Unpin,
92 {
93 w.write_all(&PRELUDE).await?;
94 w.write_all(&VERSION_2.to_be_bytes()).await?;
95
96 let header_vec = crate::bincode_compat::serialize(&self.header)?;
97 w.write_all(&u32::try_from(header_vec.len())?.to_be_bytes())
98 .await?;
99 w.write_all(&header_vec).await?;
100
101 let mut signer = Signer::default().chain(&header_vec);
102 let header_sig = signer.clone().sign(&self.pub_sign_key.key.0, self.rng);
103 let header_sig_ext = SignatureExt {
104 sig: header_sig,
105 pol: self.pub_sign_key.policy.clone(),
106 };
107 let header_sig_bytes = crate::bincode_compat::serialize(&header_sig_ext)?;
108
109 w.write_all(&u32::try_from(header_sig_bytes.len())?.to_be_bytes())
110 .await?;
111 w.write_all(&header_sig_bytes).await?;
112
113 let aead = Aes128Gcm::new_from_slice(&self.config.key)?;
114 let mut enc = EncryptorBE32::from_aead(aead, &self.config.nonce.into());
115
116 let pub_pol_bytes = crate::bincode_compat::serialize(&self.pub_sign_key.policy)?;
118 let signing_key = self.priv_sign_key.unwrap_or(self.pub_sign_key);
119
120 let pol_bytes = crate::bincode_compat::serialize(&signing_key.policy)?;
121 let pol_len = pol_bytes.len() + pub_pol_bytes.len();
122
123 if pol_len + POL_SIZE_SIZE > self.config.segment_size as usize {
124 return Err(Error::ConstraintViolation);
125 }
126
127 let mut buf = vec![0; self.config.segment_size as usize + TAG_SIZE];
128
129 buf[..POL_SIZE_SIZE].copy_from_slice(&u32::try_from(pol_len)?.to_be_bytes());
130 buf[POL_SIZE_SIZE..POL_SIZE_SIZE + pol_bytes.len()].copy_from_slice(&pol_bytes);
131 buf[POL_SIZE_SIZE + pol_bytes.len()..POL_SIZE_SIZE + pol_len]
132 .copy_from_slice(&pub_pol_bytes);
133
134 let mut buf_tail = POL_SIZE_SIZE + pol_len;
135 let mut start = buf_tail;
136
137 let mut counter: u32 = 0;
150
151 loop {
152 let read = r
153 .read(&mut buf[buf_tail..self.config.segment_size as usize])
154 .await?;
155 buf_tail += read;
156
157 if buf_tail == self.config.segment_size as usize {
158 buf.truncate(buf_tail);
159
160 signer.update(&buf[start..]);
161 let sig = signer
162 .clone()
163 .chain(counter.to_be_bytes())
164 .chain([0x00])
165 .sign(&signing_key.key.0, self.rng);
166 crate::bincode_compat::serialize_into_vec(&mut buf, &sig)?;
167
168 enc.encrypt_next_in_place(b"", &mut buf)?;
169
170 w.write_all(&buf).await?;
171
172 buf_tail = 0;
173 start = 0;
174 counter = counter.checked_add(1).unwrap(); } else if read == 0 {
178 buf.truncate(buf_tail);
179
180 signer.update(&buf[start..]);
181 let sig_final = signer
182 .chain(counter.to_be_bytes())
183 .chain([0x01])
184 .sign(&signing_key.key.0, self.rng);
185 crate::bincode_compat::serialize_into_vec(&mut buf, &sig_final)?;
186
187 enc.encrypt_last_in_place(b"", &mut buf)?;
188
189 w.write_all(&buf).await?;
190 break;
191 }
192 }
193
194 w.flush().await?;
195 w.close().await?;
196
197 Ok(())
198 }
199}
200
201impl<R> Unsealer<R, UnsealerStreamConfig>
202where
203 R: AsyncRead + Unpin,
204{
205 pub async fn new(mut r: R, pk: &VerifyingKey) -> Result<Self, Error> {
209 let mut preamble = [0u8; PREAMBLE_SIZE];
210 r.read_exact(&mut preamble)
211 .map_err(|_e| Error::NotPostGuard)
212 .await?;
213
214 let (version, header_len) = preamble_checked(&preamble)?;
215 let mut header_raw = Vec::with_capacity(header_len);
216
217 let mut r = r.take(header_len as u64);
219
220 r.read_to_end(&mut header_raw)
221 .map_err(|_e| Error::ConstraintViolation)
222 .await?;
223
224 let mut r = r.into_inner();
225
226 let mut header_sig_len_bytes = [0u8; SIG_SIZE_SIZE];
227 r.read_exact(&mut header_sig_len_bytes)
228 .map_err(|_e| Error::FormatViolation("no header signature length".to_string()))
229 .await?;
230 let header_sig_len = u32::from_be_bytes(header_sig_len_bytes) as usize;
231
232 if header_sig_len > MAX_SIG_SIZE {
235 return Err(Error::ConstraintViolation);
236 }
237
238 let mut header_sig_raw = Vec::with_capacity(header_sig_len);
239 let mut r = r.take(header_sig_len as u64);
240
241 r.read_to_end(&mut header_sig_raw).await?;
242
243 let h_sig_ext: SignatureExt = crate::bincode_compat::deserialize(&header_sig_raw)?;
244
245 let verifier = Verifier::default().chain(&header_raw);
246 let pub_id = h_sig_ext.pol.derive_ibs()?;
247
248 if !verifier.clone().verify(&pk.0, &h_sig_ext.sig, &pub_id) {
249 return Err(Error::IncorrectSignature);
250 }
251
252 let header: Header = crate::bincode_compat::deserialize(&header_raw)?;
253 let (segment_size, _) = stream_mode_checked(&header)?;
254
255 Ok(Unsealer {
256 version,
257 header,
258 pub_id: h_sig_ext.pol,
259 config: UnsealerStreamConfig { segment_size },
260 r: r.into_inner(), verifier,
262 vk: pk.clone(),
263 })
264 }
265
266 pub async fn unseal<W: AsyncWrite + Unpin>(
268 mut self,
269 ident: &str,
270 usk: &UserSecretKey<CGWKV>,
271 mut w: W,
272 ) -> Result<VerificationResult, Error> {
273 let rec_info = self
274 .header
275 .recipients
276 .get(ident)
277 .ok_or_else(|| Error::UnknownIdentifier(ident.to_string()))?;
278
279 let ss = rec_info.decaps(usk)?;
280 let key = &ss.0[..KEY_SIZE];
281 let aead = Aes128Gcm::new_from_slice(key)?;
282
283 let Algorithm::Aes128Gcm(iv) = self.header.algo;
284 let nonce = &iv.0[..STREAM_NONCE_SIZE];
285
286 let mut dec = DecryptorBE32::from_aead(aead, nonce.into());
287
288 let bufsize: usize = self.config.segment_size as usize + SIG_BYTES + TAG_SIZE;
289 let mut buf = vec![0u8; bufsize];
290 let mut buf_tail = 0;
291 let mut counter: u32 = 0;
292 let mut pol_id: Option<(Policy, Identity)> = None;
293
294 fn extract_policy(
295 buf: &mut Vec<u8>,
296 pub_id: &Policy,
297 ) -> Result<Option<(Policy, Identity)>, Error> {
298 if buf.len() < POL_SIZE_SIZE {
299 return Err(Error::FormatViolation(alloc::string::String::from(
300 "policy length",
301 )));
302 }
303 let pol_len = u32::from_be_bytes(buf[..POL_SIZE_SIZE].try_into()?) as usize;
304 let pol_end = POL_SIZE_SIZE.checked_add(pol_len).ok_or_else(|| {
305 Error::FormatViolation(alloc::string::String::from("policy length overflow"))
306 })?;
307 if buf.len() < pol_end {
308 return Err(Error::FormatViolation(alloc::string::String::from(
309 "policy truncated",
310 )));
311 }
312 let pol_bytes = &buf[POL_SIZE_SIZE..pol_end];
313 let (pol, read): (Policy, usize) =
314 crate::bincode_compat::deserialize_with_len(pol_bytes)?;
315
316 if read < pol_bytes.len() {
324 let sealed_pub_pol: Policy =
325 crate::bincode_compat::deserialize(&pol_bytes[read..])?;
326
327 if &sealed_pub_pol != pub_id {
328 return Err(Error::IncorrectSignature);
329 }
330 }
331
332 let id = pol.derive_ibs()?;
333
334 buf.drain(..pol_end);
335
336 Ok(Some((pol, id)))
337 }
338
339 fn verify_segment<'a>(
340 seg: &'a [u8],
341 verifier: &mut Verifier,
342 vk: &VerifyingKey,
343 id: &Identity,
344 counter: u32,
345 is_last: bool,
346 ) -> Result<&'a [u8], Error> {
347 if seg.len() < SIG_BYTES {
348 return Err(Error::FormatViolation(alloc::string::String::from(
349 "segment too short for signature",
350 )));
351 }
352
353 let (m, sig_bytes) = seg.split_at(seg.len() - SIG_BYTES);
354 let sig: Signature = crate::bincode_compat::deserialize(sig_bytes)?;
355 verifier.update(m);
356
357 if !verifier
358 .clone()
359 .chain(counter.to_be_bytes())
360 .chain([is_last as u8])
361 .verify(&vk.0, &sig, id)
362 {
363 return Err(Error::IncorrectSignature);
364 }
365
366 Ok(m)
367 }
368
369 loop {
370 let read = self.r.read(&mut buf[buf_tail..bufsize]).await?;
371 buf_tail += read;
372
373 if buf_tail == bufsize {
374 dec.decrypt_next_in_place(b"", &mut buf)?;
375
376 if counter == 0 {
377 pol_id = extract_policy(&mut buf, &self.pub_id)?;
378 }
379
380 let m = verify_segment(
381 &buf,
382 &mut self.verifier,
383 &self.vk,
384 &pol_id.as_ref().unwrap().1,
385 counter,
386 false,
387 )?;
388
389 w.write_all(m).await?;
390
391 buf_tail = 0;
392 buf.resize(bufsize, 0);
393 counter += 1;
394 } else if read == 0 {
395 buf.truncate(buf_tail);
396 dec.decrypt_last_in_place(b"", &mut buf)?;
397
398 if counter == 0 {
399 pol_id = extract_policy(&mut buf, &self.pub_id)?;
400 }
401
402 let m = verify_segment(
403 &buf,
404 &mut self.verifier,
405 &self.vk,
406 &pol_id.as_ref().unwrap().1,
407 counter,
408 true,
409 )?;
410
411 w.write_all(m).await?;
412
413 break;
414 }
415 }
416
417 w.close().await?;
418
419 let private_id = pol_id.unwrap().0;
420 let private = if self.pub_id == private_id {
421 None
422 } else {
423 Some(private_id)
424 };
425
426 Ok(VerificationResult {
427 public: self.pub_id,
428 private,
429 })
430 }
431}
432
433#[cfg(test)]
434mod tests {
435 use super::{Sealer, SealerStreamConfig, Unsealer, UnsealerStreamConfig};
436 use crate::client::VerificationResult;
437 use crate::error::Error;
438 use crate::test::TestSetup;
439 use crate::{PREAMBLE_SIZE, SYMMETRIC_CRYPTO_DEFAULT_CHUNK, TAG_SIZE};
440 use aead::stream::{DecryptorBE32, EncryptorBE32};
441 use aead::KeyInit;
442 use aes_gcm::Aes128Gcm;
443 use alloc::string::String;
444 use alloc::vec::Vec;
445 use futures::{executor::block_on, io::AllowStdIo};
446 use ibe::kem::cgw_kv::CGWKV;
447 use rand::{thread_rng, Rng, RngCore};
448 use std::io::Cursor;
449 use tokio::io::AsyncReadExt;
450
451 const LENGTHS: &[u32] = &[
452 1,
453 512,
454 SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 3,
455 SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
456 SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 3,
457 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
458 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 16,
459 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 17,
460 ];
461
462 fn seal_helper(setup: &TestSetup, plain: &[u8]) -> Vec<u8> {
463 let mut rng = rand::thread_rng();
464
465 let mut input = AllowStdIo::new(Cursor::new(plain));
466 let mut output = AllowStdIo::new(Vec::new());
467
468 let signing_key = &setup.signing_keys[0];
469
470 block_on(async {
471 Sealer::<_, SealerStreamConfig>::new(
472 &setup.ibe_pk,
473 &setup.policy,
474 signing_key,
475 &mut rng,
476 )
477 .unwrap()
478 .seal(&mut input, &mut output)
479 .await
480 .unwrap();
481 });
482
483 output.into_inner()
484 }
485
486 fn unseal_helper(setup: &TestSetup, ct: &[u8]) -> (Vec<u8>, VerificationResult) {
487 let mut input = AllowStdIo::new(Cursor::new(ct));
488 let mut output = AllowStdIo::new(Vec::new());
489
490 let (id, usk_id) = if thread_rng().gen::<bool>() {
492 ("Bob", setup.usks[2].clone())
493 } else {
494 ("Charlie", setup.usks[3].clone())
495 };
496
497 let vr = block_on(async {
498 let unsealer = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk)
499 .await
500 .unwrap();
501
502 unsealer.unseal(id, &usk_id, &mut output).await.unwrap()
505 });
506
507 (output.into_inner(), vr)
508 }
509
510 fn seal_and_unseal(setup: &TestSetup, plain: Vec<u8>) {
511 let ct = seal_helper(setup, &plain);
512 let (plain2, vr) = unseal_helper(setup, &ct);
513
514 assert_eq!(&plain, &plain2);
515 assert_eq!(&vr.public, &setup.signing_keys[0].policy);
516 assert_eq!(vr.private, None);
517 }
518
519 fn rand_vec(length: usize) -> Vec<u8> {
520 let mut vec = vec![0u8; length];
521 rand::thread_rng().fill_bytes(&mut vec);
522 vec
523 }
524
525 #[test]
526 fn test_reflection_seal_unsealer() {
527 let mut rng = rand::thread_rng();
528 let setup = TestSetup::new(&mut rng);
529
530 for l in LENGTHS {
531 seal_and_unseal(&setup, rand_vec(*l as usize));
532 }
533 }
534
535 #[test]
536 #[should_panic]
537 fn test_corrupt_header() {
538 let mut rng = rand::thread_rng();
539 let setup = TestSetup::new(&mut rng);
540
541 let plain = rand_vec(100);
542 let mut ct = seal_helper(&setup, &plain);
543
544 ct[PREAMBLE_SIZE + 2] = !ct[PREAMBLE_SIZE + 2];
546
547 let _plain2 = unseal_helper(&setup, &ct);
549 }
550
551 #[test]
552 #[should_panic]
553 fn test_corrupt_payload() {
554 let mut rng = rand::thread_rng();
555 let setup = TestSetup::new(&mut rng);
556
557 let plain = rand_vec(100);
558 let mut ct = seal_helper(&setup, &plain);
559
560 let ct_len = ct.len();
562 ct[ct_len - TAG_SIZE - 5] = !ct[ct_len - TAG_SIZE - 5];
563
564 let _plain2 = unseal_helper(&setup, &ct);
566 }
567
568 #[test]
569 #[should_panic]
570 fn test_corrupt_tag() {
571 let mut rng = rand::thread_rng();
572 let setup = TestSetup::new(&mut rng);
573
574 let plain = rand_vec(100);
575 let mut ct = seal_helper(&setup, &plain);
576
577 let len = ct.len();
578 ct[len - 5] = !ct[len - 5];
579
580 let _plain2 = unseal_helper(&setup, &ct);
582 }
583
584 #[tokio::test]
585 async fn test_tokio_file() -> Result<(), Error> {
586 use futures::AsyncWriteExt;
587 use tokio::fs::{File, OpenOptions};
588 use tokio_util::compat::TokioAsyncReadCompatExt;
589
590 let mut rng = rand::thread_rng();
591 let setup = TestSetup::new(&mut rng);
592
593 let signing_key = &setup.signing_keys[0];
594
595 let in_name = std::env::temp_dir().join("foo.txt");
596 let out_name = std::env::temp_dir().join("foo.enc");
597 let orig_name = std::env::temp_dir().join("foo2.txt");
598
599 let mut file = OpenOptions::new()
600 .create(true)
601 .write(true)
602 .truncate(true)
603 .open(&in_name)
604 .await?
605 .compat();
606
607 file.write_all(b"SECRET DATA").await?;
608 file.close().await?;
609
610 let mut in_file = File::open(&in_name).await?.compat();
611 let mut out_file = OpenOptions::new()
612 .create(true)
613 .write(true)
614 .truncate(true)
615 .open(&out_name)
616 .await?
617 .compat();
618
619 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
620 .seal(&mut in_file, &mut out_file)
621 .await?;
622
623 in_file.close().await?;
624 out_file.close().await?;
625
626 let mut out_file = File::open(&out_name).await?.compat();
627 let mut orig_file = OpenOptions::new()
628 .create(true)
629 .write(true)
630 .truncate(true)
631 .open(&orig_name)
632 .await?
633 .compat();
634
635 let id = "Bob";
636 let usk = &setup.usks[2];
637
638 Unsealer::<_, UnsealerStreamConfig>::new(&mut out_file, &setup.ibs_pk)
639 .await?
640 .unseal(id, usk, &mut orig_file)
641 .await?;
642
643 out_file.close().await?;
644 orig_file.close().await?;
645
646 let mut buf = String::new();
647 File::open(&orig_name)
648 .await?
649 .read_to_string(&mut buf)
650 .await?;
651
652 assert_eq!(buf.as_bytes(), b"SECRET DATA");
653
654 Ok(())
655 }
656
657 #[tokio::test]
658 async fn test_cursor() -> Result<(), Error> {
659 use futures::io::Cursor;
660
661 let mut rng = rand::thread_rng();
662 let setup = TestSetup::new(&mut rng);
663
664 let signing_key = &setup.signing_keys[0];
665
666 let mut input = Cursor::new(b"SECRET DATA");
667 let mut encrypted = Vec::new();
668
669 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
670 .seal(&mut input, &mut encrypted)
671 .await?;
672
673 let mut original = Vec::new();
674 let id = "Bob";
675 let usk = &setup.usks[2];
676 Unsealer::<_, UnsealerStreamConfig>::new(&mut Cursor::new(encrypted), &setup.ibs_pk)
677 .await?
678 .unseal(id, usk, &mut original)
679 .await?;
680
681 assert_eq!(input.into_inner().to_vec(), original);
682 Ok(())
683 }
684
685 #[tokio::test]
686 async fn test_stream_unseal_rejects_empty_input() {
687 use futures::io::Cursor;
688
689 let mut rng = rand::thread_rng();
690 let setup = TestSetup::new(&mut rng);
691
692 let mut input = Cursor::new(Vec::<u8>::new());
694 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
695 assert!(matches!(res, Err(Error::NotPostGuard)));
696 }
697
698 #[tokio::test]
699 async fn test_stream_unseal_rejects_truncated_preamble() {
700 use futures::io::Cursor;
701
702 let mut rng = rand::thread_rng();
703 let setup = TestSetup::new(&mut rng);
704
705 let mut input = Cursor::new(vec![0u8; PREAMBLE_SIZE - 1]);
708 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
709 assert!(matches!(res, Err(Error::NotPostGuard)));
710 }
711
712 #[tokio::test]
713 async fn test_stream_unseal_rejects_garbage_input() {
714 use futures::io::Cursor;
715
716 let mut rng = rand::thread_rng();
717 let setup = TestSetup::new(&mut rng);
718
719 let mut input = Cursor::new(vec![0u8; 4096]);
722 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
723 assert!(res.is_err());
724 }
725
726 #[tokio::test]
727 async fn test_stream_unseal_rejects_flipped_prelude() {
728 use futures::io::Cursor;
729
730 let mut rng = rand::thread_rng();
731 let setup = TestSetup::new(&mut rng);
732 let mut ct = seal_helper(&setup, b"SECRET DATA");
733
734 ct[0] = ct[0].wrapping_add(1);
737
738 let mut input = Cursor::new(ct);
739 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
740 assert!(matches!(res, Err(Error::NotPostGuard)));
741 }
742
743 fn split_container(ct: &[u8]) -> (&[u8], &[u8], &[u8]) {
746 use crate::util::preamble_checked;
747 use crate::SIG_SIZE_SIZE;
748
749 let (_, header_len) =
750 preamble_checked(&ct[..PREAMBLE_SIZE]).expect("preamble should parse");
751 let sig_len_at = PREAMBLE_SIZE + header_len;
752 let sig_len = u32::from_be_bytes(
753 ct[sig_len_at..sig_len_at + SIG_SIZE_SIZE]
754 .try_into()
755 .unwrap(),
756 ) as usize;
757 let sig_at = sig_len_at + SIG_SIZE_SIZE;
758
759 (
760 &ct[PREAMBLE_SIZE..sig_len_at],
761 &ct[sig_at..sig_at + sig_len],
762 &ct[sig_at + sig_len..],
763 )
764 }
765
766 fn swap_header_signature(
770 ct: &[u8],
771 attacker: &crate::artifacts::SigningKeyExt,
772 rng: &mut (impl rand::RngCore + rand::CryptoRng),
773 ) -> Vec<u8> {
774 use crate::client::header::SignatureExt;
775 use ibs::gg::Signer;
776
777 let (header_bytes, _, payload) = split_container(ct);
778
779 let h_sig_ext = SignatureExt {
780 sig: Signer::default()
781 .chain(header_bytes)
782 .sign(&attacker.key.0, rng),
783 pol: attacker.policy.clone(),
784 };
785 let h_sig_ext_bytes = crate::bincode_compat::serialize(&h_sig_ext).unwrap();
786
787 let mut out = ct[..PREAMBLE_SIZE + header_bytes.len()].to_vec();
788 out.extend_from_slice(&(h_sig_ext_bytes.len() as u32).to_be_bytes());
789 out.extend_from_slice(&h_sig_ext_bytes);
790 out.extend_from_slice(payload);
791
792 out
793 }
794
795 fn strip_pub_pol(
799 ct: &[u8],
800 ident: &str,
801 usk: &crate::artifacts::UserSecretKey<CGWKV>,
802 ) -> Vec<u8> {
803 use crate::client::{Algorithm, Header};
804 use crate::identity::Policy;
805 use crate::{KEY_SIZE, POL_SIZE_SIZE, STREAM_NONCE_SIZE};
806
807 let (header_bytes, _, payload) = split_container(ct);
808 let header: Header = crate::bincode_compat::deserialize(header_bytes).unwrap();
809 let ss = header.recipients.get(ident).unwrap().decaps(usk).unwrap();
810
811 let Algorithm::Aes128Gcm(iv) = header.algo;
812 let aead = Aes128Gcm::new_from_slice(&ss.0[..KEY_SIZE]).unwrap();
813 let nonce = &iv.0[..STREAM_NONCE_SIZE];
814
815 let mut plain = payload.to_vec();
818 DecryptorBE32::from_aead(aead.clone(), nonce.into())
819 .decrypt_last_in_place(b"", &mut plain)
820 .unwrap();
821
822 let pol_len = u32::from_be_bytes(plain[..POL_SIZE_SIZE].try_into().unwrap()) as usize;
823 let region = &plain[POL_SIZE_SIZE..POL_SIZE_SIZE + pol_len];
824 let (_, read): (Policy, usize) =
825 crate::bincode_compat::deserialize_with_len(region).unwrap();
826 assert!(
827 read < pol_len,
828 "the sealer wrote no public policy into the region — nothing to strip"
829 );
830
831 let mut legacy = (read as u32).to_be_bytes().to_vec();
832 legacy.extend_from_slice(®ion[..read]);
833 legacy.extend_from_slice(&plain[POL_SIZE_SIZE + pol_len..]);
834
835 EncryptorBE32::from_aead(aead, nonce.into())
836 .encrypt_last_in_place(b"", &mut legacy)
837 .unwrap();
838
839 let mut out = ct[..ct.len() - payload.len()].to_vec();
840 out.extend_from_slice(&legacy);
841
842 out
843 }
844
845 fn try_unseal(setup: &TestSetup, ct: &[u8]) -> Result<(Vec<u8>, VerificationResult), Error> {
846 let mut input = AllowStdIo::new(Cursor::new(ct));
847 let mut output = AllowStdIo::new(Vec::new());
848
849 let vr = block_on(async {
850 Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk)
851 .await?
852 .unseal("Bob", &setup.usks[2], &mut output)
853 .await
854 })?;
855
856 Ok((output.into_inner(), vr))
857 }
858
859 #[test]
864 fn test_stream_unseal_rejects_swapped_header_signature() {
865 let mut rng = rand::thread_rng();
866 let setup = TestSetup::new(&mut rng);
867 let ct = seal_helper(&setup, b"SECRET DATA");
868
869 let swapped = swap_header_signature(&ct, &setup.signing_keys[4], &mut rng);
872
873 block_on(async {
874 let mut input = AllowStdIo::new(Cursor::new(&swapped));
875 let unsealer = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk)
876 .await
877 .expect("the swapped header signature still verifies — that is the attack");
878 assert_eq!(
879 unsealer.pub_id, setup.policies[4],
880 "the container now claims the attacker as public sender"
881 );
882 });
883
884 match try_unseal(&setup, &swapped) {
885 Err(Error::IncorrectSignature) => {}
886 other => panic!(
887 "expected IncorrectSignature, got {:?}",
888 other.map(|(m, vr)| (m.len(), vr))
889 ),
890 }
891 }
892
893 #[test]
897 fn test_stream_unseal_accepts_container_without_public_policy() {
898 let mut rng = rand::thread_rng();
899 let setup = TestSetup::new(&mut rng);
900 let ct = seal_helper(&setup, b"SECRET DATA");
901 let legacy = strip_pub_pol(&ct, "Bob", &setup.usks[2]);
902
903 let (plain, vr) = try_unseal(&setup, &legacy)
904 .expect("a container without the public policy must still open");
905
906 assert_eq!(&plain, b"SECRET DATA");
907 assert_eq!(&vr.public, &setup.signing_keys[0].policy);
908 assert_eq!(vr.private, None);
909 }
910
911 #[tokio::test]
912 async fn test_stream_unseal_rejects_oversized_sig_len() {
913 use crate::util::preamble_checked;
914 use crate::{MAX_SIG_SIZE, SIG_SIZE_SIZE};
915 use futures::io::Cursor;
916
917 let mut rng = rand::thread_rng();
918 let setup = TestSetup::new(&mut rng);
919 let mut ct = seal_helper(&setup, b"SECRET DATA");
920
921 let (_, header_len) =
925 preamble_checked(&ct[..PREAMBLE_SIZE]).expect("preamble should parse");
926 let sig_len_off = PREAMBLE_SIZE + header_len;
927 assert!(sig_len_off + SIG_SIZE_SIZE <= ct.len());
928 assert!((MAX_SIG_SIZE as u64) < u32::MAX as u64);
929 ct[sig_len_off..sig_len_off + SIG_SIZE_SIZE].copy_from_slice(&u32::MAX.to_be_bytes());
930
931 let mut input = Cursor::new(ct);
932 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
933 assert!(
934 matches!(res, Err(Error::ConstraintViolation)),
935 "expected ConstraintViolation, got {res:?}"
936 );
937 }
938}