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: pub_sign_key.clone(),
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_V3.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 signing_key = self.priv_sign_key.unwrap_or(self.pub_sign_key);
118
119 let pol_bytes = crate::bincode_compat::serialize(&signing_key.policy)?;
120 let pol_len = pol_bytes.len();
121
122 if pol_len + POL_SIZE_SIZE > self.config.segment_size as usize {
123 return Err(Error::ConstraintViolation);
124 }
125
126 let mut buf = vec![0; self.config.segment_size as usize + TAG_SIZE];
127
128 buf[..POL_SIZE_SIZE].copy_from_slice(&u32::try_from(pol_len)?.to_be_bytes());
129 buf[POL_SIZE_SIZE..POL_SIZE_SIZE + pol_len].copy_from_slice(&pol_bytes);
130
131 let mut buf_tail = POL_SIZE_SIZE + pol_len;
132 let mut start = buf_tail;
133
134 let mut counter: u32 = 0;
138
139 loop {
140 let read = r
141 .read(&mut buf[buf_tail..self.config.segment_size as usize])
142 .await?;
143 buf_tail += read;
144
145 if buf_tail == self.config.segment_size as usize {
146 buf.truncate(buf_tail);
147
148 signer.update(&buf[start..]);
149 let sig = signer
150 .clone()
151 .chain(counter.to_be_bytes())
152 .chain([0x00])
153 .sign(&signing_key.key.0, self.rng);
154 crate::bincode_compat::serialize_into_vec(&mut buf, &sig)?;
155
156 enc.encrypt_next_in_place(b"", &mut buf)?;
157
158 w.write_all(&buf).await?;
159
160 buf_tail = 0;
161 start = 0;
162 counter = counter.checked_add(1).unwrap(); } else if read == 0 {
166 buf.truncate(buf_tail);
167
168 signer.update(&buf[start..]);
169 let sig_final = signer
170 .chain(counter.to_be_bytes())
171 .chain([0x01])
172 .sign(&signing_key.key.0, self.rng);
173 crate::bincode_compat::serialize_into_vec(&mut buf, &sig_final)?;
174
175 enc.encrypt_last_in_place(b"", &mut buf)?;
176
177 w.write_all(&buf).await?;
178 break;
179 }
180 }
181
182 w.flush().await?;
183 w.close().await?;
184
185 Ok(())
186 }
187}
188
189impl<R> Unsealer<R, UnsealerStreamConfig>
190where
191 R: AsyncRead + Unpin,
192{
193 pub async fn new(mut r: R, pk: &VerifyingKey) -> Result<Self, Error> {
197 let mut preamble = [0u8; PREAMBLE_SIZE];
198 r.read_exact(&mut preamble)
199 .map_err(|_e| Error::NotPostGuard)
200 .await?;
201
202 let (version, header_len) = preamble_checked(&preamble)?;
203 let mut header_raw = Vec::with_capacity(header_len);
204
205 let mut r = r.take(header_len as u64);
207
208 r.read_to_end(&mut header_raw)
209 .map_err(|_e| Error::ConstraintViolation)
210 .await?;
211
212 let mut r = r.into_inner();
213
214 let mut header_sig_len_bytes = [0u8; SIG_SIZE_SIZE];
215 r.read_exact(&mut header_sig_len_bytes)
216 .map_err(|_e| Error::FormatViolation("no header signature length".to_string()))
217 .await?;
218 let header_sig_len = u32::from_be_bytes(header_sig_len_bytes) as usize;
219
220 if header_sig_len > MAX_SIG_SIZE {
223 return Err(Error::ConstraintViolation);
224 }
225
226 let mut header_sig_raw = Vec::with_capacity(header_sig_len);
227 let mut r = r.take(header_sig_len as u64);
228
229 r.read_to_end(&mut header_sig_raw).await?;
230
231 let h_sig_ext: SignatureExt = crate::bincode_compat::deserialize(&header_sig_raw)?;
232
233 let verifier = Verifier::default().chain(&header_raw);
234 let pub_id = h_sig_ext.pol.derive_ibs()?;
235
236 if !verifier.clone().verify(&pk.0, &h_sig_ext.sig, &pub_id) {
237 return Err(Error::IncorrectSignature);
238 }
239
240 let header: Header = crate::bincode_compat::deserialize(&header_raw)?;
241 let (segment_size, _) = stream_mode_checked(&header)?;
242
243 Ok(Unsealer {
244 version,
245 header,
246 pub_id: h_sig_ext.pol,
247 config: UnsealerStreamConfig { segment_size },
248 r: r.into_inner(), verifier,
250 vk: pk.clone(),
251 })
252 }
253
254 pub async fn unseal<W: AsyncWrite + Unpin>(
256 mut self,
257 ident: &str,
258 usk: &UserSecretKey<CGWKV>,
259 mut w: W,
260 ) -> Result<VerificationResult, Error> {
261 let rec_info = self
262 .header
263 .recipients
264 .get(ident)
265 .ok_or_else(|| Error::UnknownIdentifier(ident.to_string()))?;
266
267 let ss = rec_info.decaps(usk)?;
268 let key = &ss.0[..KEY_SIZE];
269 let aead = Aes128Gcm::new_from_slice(key)?;
270
271 let Algorithm::Aes128Gcm(iv) = self.header.algo;
272 let nonce = &iv.0[..STREAM_NONCE_SIZE];
273
274 let mut dec = DecryptorBE32::from_aead(aead, nonce.into());
275
276 let bufsize: usize = self.config.segment_size as usize + SIG_BYTES + TAG_SIZE;
277 let mut buf = vec![0u8; bufsize];
278 let mut buf_tail = 0;
279 let mut counter: u32 = 0;
280 let mut pol_id: Option<(Policy, Identity)> = None;
281
282 fn extract_policy(buf: &mut Vec<u8>) -> Result<Option<(Policy, Identity)>, Error> {
283 if buf.len() < POL_SIZE_SIZE {
284 return Err(Error::FormatViolation(alloc::string::String::from(
285 "policy length",
286 )));
287 }
288 let pol_len = u32::from_be_bytes(buf[..POL_SIZE_SIZE].try_into()?) as usize;
289 let pol_end = POL_SIZE_SIZE.checked_add(pol_len).ok_or_else(|| {
290 Error::FormatViolation(alloc::string::String::from("policy length overflow"))
291 })?;
292 if buf.len() < pol_end {
293 return Err(Error::FormatViolation(alloc::string::String::from(
294 "policy truncated",
295 )));
296 }
297 let pol_bytes = &buf[POL_SIZE_SIZE..pol_end];
298 let pol: Policy = crate::bincode_compat::deserialize(pol_bytes)?;
299 let id = pol.derive_ibs()?;
300
301 buf.drain(..pol_end);
302
303 Ok(Some((pol, id)))
304 }
305
306 fn verify_segment<'a>(
307 seg: &'a [u8],
308 verifier: &mut Verifier,
309 vk: &VerifyingKey,
310 id: &Identity,
311 counter: u32,
312 is_last: bool,
313 ) -> Result<&'a [u8], Error> {
314 if seg.len() < SIG_BYTES {
315 return Err(Error::FormatViolation(alloc::string::String::from(
316 "segment too short for signature",
317 )));
318 }
319
320 let (m, sig_bytes) = seg.split_at(seg.len() - SIG_BYTES);
321 let sig: Signature = crate::bincode_compat::deserialize(sig_bytes)?;
322 verifier.update(m);
323
324 if !verifier
325 .clone()
326 .chain(counter.to_be_bytes())
327 .chain([is_last as u8])
328 .verify(&vk.0, &sig, id)
329 {
330 return Err(Error::IncorrectSignature);
331 }
332
333 Ok(m)
334 }
335
336 loop {
337 let read = self.r.read(&mut buf[buf_tail..bufsize]).await?;
338 buf_tail += read;
339
340 if buf_tail == bufsize {
341 dec.decrypt_next_in_place(b"", &mut buf)?;
342
343 if counter == 0 {
344 pol_id = extract_policy(&mut buf)?;
345 }
346
347 let m = verify_segment(
348 &buf,
349 &mut self.verifier,
350 &self.vk,
351 &pol_id.as_ref().unwrap().1,
352 counter,
353 false,
354 )?;
355
356 w.write_all(m).await?;
357
358 buf_tail = 0;
359 buf.resize(bufsize, 0);
360 counter += 1;
361 } else if read == 0 {
362 buf.truncate(buf_tail);
363 dec.decrypt_last_in_place(b"", &mut buf)?;
364
365 if counter == 0 {
366 pol_id = extract_policy(&mut buf)?;
367 }
368
369 let m = verify_segment(
370 &buf,
371 &mut self.verifier,
372 &self.vk,
373 &pol_id.as_ref().unwrap().1,
374 counter,
375 true,
376 )?;
377
378 w.write_all(m).await?;
379
380 break;
381 }
382 }
383
384 w.close().await?;
385
386 let private_id = pol_id.unwrap().0;
387 let private = if self.pub_id == private_id {
388 None
389 } else {
390 Some(private_id)
391 };
392
393 Ok(VerificationResult {
394 public: self.pub_id,
395 private,
396 })
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::{Sealer, SealerStreamConfig, Unsealer, UnsealerStreamConfig};
403 use crate::client::VerificationResult;
404 use crate::error::Error;
405 use crate::test::TestSetup;
406 use crate::{PREAMBLE_SIZE, SYMMETRIC_CRYPTO_DEFAULT_CHUNK, TAG_SIZE};
407 use alloc::string::String;
408 use alloc::vec::Vec;
409 use futures::{executor::block_on, io::AllowStdIo};
410 use rand::{thread_rng, Rng, RngCore};
411 use std::io::Cursor;
412 use tokio::io::AsyncReadExt;
413
414 const LENGTHS: &[u32] = &[
415 1,
416 512,
417 SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 3,
418 SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
419 SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 3,
420 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
421 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 16,
422 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 17,
423 ];
424
425 fn seal_helper(setup: &TestSetup, plain: &[u8]) -> Vec<u8> {
426 let mut rng = rand::thread_rng();
427
428 let mut input = AllowStdIo::new(Cursor::new(plain));
429 let mut output = AllowStdIo::new(Vec::new());
430
431 let signing_key = &setup.signing_keys[0];
432
433 block_on(async {
434 Sealer::<_, SealerStreamConfig>::new(
435 &setup.ibe_pk,
436 &setup.policy,
437 signing_key,
438 &mut rng,
439 )
440 .unwrap()
441 .seal(&mut input, &mut output)
442 .await
443 .unwrap();
444 });
445
446 output.into_inner()
447 }
448
449 fn unseal_helper(setup: &TestSetup, ct: &[u8]) -> (Vec<u8>, VerificationResult) {
450 let mut input = AllowStdIo::new(Cursor::new(ct));
451 let mut output = AllowStdIo::new(Vec::new());
452
453 let (id, usk_id) = if thread_rng().gen::<bool>() {
455 ("Bob", setup.usks[2].clone())
456 } else {
457 ("Charlie", setup.usks[3].clone())
458 };
459
460 let vr = block_on(async {
461 let unsealer = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk)
462 .await
463 .unwrap();
464
465 unsealer.unseal(id, &usk_id, &mut output).await.unwrap()
468 });
469
470 (output.into_inner(), vr)
471 }
472
473 fn seal_and_unseal(setup: &TestSetup, plain: Vec<u8>) {
474 let ct = seal_helper(setup, &plain);
475 let (plain2, vr) = unseal_helper(setup, &ct);
476
477 assert_eq!(&plain, &plain2);
478 assert_eq!(&vr.public, &setup.signing_keys[0].policy);
479 assert_eq!(vr.private, None);
480 }
481
482 fn rand_vec(length: usize) -> Vec<u8> {
483 let mut vec = vec![0u8; length];
484 rand::thread_rng().fill_bytes(&mut vec);
485 vec
486 }
487
488 #[test]
489 fn test_reflection_seal_unsealer() {
490 let mut rng = rand::thread_rng();
491 let setup = TestSetup::new(&mut rng);
492
493 for l in LENGTHS {
494 seal_and_unseal(&setup, rand_vec(*l as usize));
495 }
496 }
497
498 #[test]
499 #[should_panic]
500 fn test_corrupt_header() {
501 let mut rng = rand::thread_rng();
502 let setup = TestSetup::new(&mut rng);
503
504 let plain = rand_vec(100);
505 let mut ct = seal_helper(&setup, &plain);
506
507 ct[PREAMBLE_SIZE + 2] = !ct[PREAMBLE_SIZE + 2];
509
510 let _plain2 = unseal_helper(&setup, &ct);
512 }
513
514 #[test]
515 #[should_panic]
516 fn test_corrupt_payload() {
517 let mut rng = rand::thread_rng();
518 let setup = TestSetup::new(&mut rng);
519
520 let plain = rand_vec(100);
521 let mut ct = seal_helper(&setup, &plain);
522
523 let ct_len = ct.len();
525 ct[ct_len - TAG_SIZE - 5] = !ct[ct_len - TAG_SIZE - 5];
526
527 let _plain2 = unseal_helper(&setup, &ct);
529 }
530
531 #[test]
532 #[should_panic]
533 fn test_corrupt_tag() {
534 let mut rng = rand::thread_rng();
535 let setup = TestSetup::new(&mut rng);
536
537 let plain = rand_vec(100);
538 let mut ct = seal_helper(&setup, &plain);
539
540 let len = ct.len();
541 ct[len - 5] = !ct[len - 5];
542
543 let _plain2 = unseal_helper(&setup, &ct);
545 }
546
547 #[tokio::test]
548 async fn test_tokio_file() -> Result<(), Error> {
549 use futures::AsyncWriteExt;
550 use tokio::fs::{File, OpenOptions};
551 use tokio_util::compat::TokioAsyncReadCompatExt;
552
553 let mut rng = rand::thread_rng();
554 let setup = TestSetup::new(&mut rng);
555
556 let signing_key = &setup.signing_keys[0];
557
558 let in_name = std::env::temp_dir().join("foo.txt");
559 let out_name = std::env::temp_dir().join("foo.enc");
560 let orig_name = std::env::temp_dir().join("foo2.txt");
561
562 let mut file = OpenOptions::new()
563 .create(true)
564 .write(true)
565 .truncate(true)
566 .open(&in_name)
567 .await?
568 .compat();
569
570 file.write_all(b"SECRET DATA").await?;
571 file.close().await?;
572
573 let mut in_file = File::open(&in_name).await?.compat();
574 let mut out_file = OpenOptions::new()
575 .create(true)
576 .write(true)
577 .truncate(true)
578 .open(&out_name)
579 .await?
580 .compat();
581
582 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
583 .seal(&mut in_file, &mut out_file)
584 .await?;
585
586 in_file.close().await?;
587 out_file.close().await?;
588
589 let mut out_file = File::open(&out_name).await?.compat();
590 let mut orig_file = OpenOptions::new()
591 .create(true)
592 .write(true)
593 .truncate(true)
594 .open(&orig_name)
595 .await?
596 .compat();
597
598 let id = "Bob";
599 let usk = &setup.usks[2];
600
601 Unsealer::<_, UnsealerStreamConfig>::new(&mut out_file, &setup.ibs_pk)
602 .await?
603 .unseal(id, usk, &mut orig_file)
604 .await?;
605
606 out_file.close().await?;
607 orig_file.close().await?;
608
609 let mut buf = String::new();
610 File::open(&orig_name)
611 .await?
612 .read_to_string(&mut buf)
613 .await?;
614
615 assert_eq!(buf.as_bytes(), b"SECRET DATA");
616
617 Ok(())
618 }
619
620 #[tokio::test]
621 async fn test_cursor() -> Result<(), Error> {
622 use futures::io::Cursor;
623
624 let mut rng = rand::thread_rng();
625 let setup = TestSetup::new(&mut rng);
626
627 let signing_key = &setup.signing_keys[0];
628
629 let mut input = Cursor::new(b"SECRET DATA");
630 let mut encrypted = Vec::new();
631
632 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
633 .seal(&mut input, &mut encrypted)
634 .await?;
635
636 let mut original = Vec::new();
637 let id = "Bob";
638 let usk = &setup.usks[2];
639 Unsealer::<_, UnsealerStreamConfig>::new(&mut Cursor::new(encrypted), &setup.ibs_pk)
640 .await?
641 .unseal(id, usk, &mut original)
642 .await?;
643
644 assert_eq!(input.into_inner().to_vec(), original);
645 Ok(())
646 }
647
648 #[tokio::test]
649 async fn test_stream_unseal_rejects_empty_input() {
650 use futures::io::Cursor;
651
652 let mut rng = rand::thread_rng();
653 let setup = TestSetup::new(&mut rng);
654
655 let mut input = Cursor::new(Vec::<u8>::new());
657 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
658 assert!(matches!(res, Err(Error::NotPostGuard)));
659 }
660
661 #[tokio::test]
662 async fn test_stream_unseal_rejects_truncated_preamble() {
663 use futures::io::Cursor;
664
665 let mut rng = rand::thread_rng();
666 let setup = TestSetup::new(&mut rng);
667
668 let mut input = Cursor::new(vec![0u8; PREAMBLE_SIZE - 1]);
671 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
672 assert!(matches!(res, Err(Error::NotPostGuard)));
673 }
674
675 #[tokio::test]
676 async fn test_stream_unseal_rejects_garbage_input() {
677 use futures::io::Cursor;
678
679 let mut rng = rand::thread_rng();
680 let setup = TestSetup::new(&mut rng);
681
682 let mut input = Cursor::new(vec![0u8; 4096]);
685 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
686 assert!(res.is_err());
687 }
688
689 #[tokio::test]
690 async fn test_stream_unseal_rejects_flipped_prelude() {
691 use futures::io::Cursor;
692
693 let mut rng = rand::thread_rng();
694 let setup = TestSetup::new(&mut rng);
695 let mut ct = seal_helper(&setup, b"SECRET DATA");
696
697 ct[0] = ct[0].wrapping_add(1);
700
701 let mut input = Cursor::new(ct);
702 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
703 assert!(matches!(res, Err(Error::NotPostGuard)));
704 }
705
706 #[tokio::test]
707 async fn test_stream_unseal_rejects_oversized_sig_len() {
708 use crate::util::preamble_checked;
709 use crate::{MAX_SIG_SIZE, SIG_SIZE_SIZE};
710 use futures::io::Cursor;
711
712 let mut rng = rand::thread_rng();
713 let setup = TestSetup::new(&mut rng);
714 let mut ct = seal_helper(&setup, b"SECRET DATA");
715
716 let (_, header_len) =
720 preamble_checked(&ct[..PREAMBLE_SIZE]).expect("preamble should parse");
721 let sig_len_off = PREAMBLE_SIZE + header_len;
722 assert!(sig_len_off + SIG_SIZE_SIZE <= ct.len());
723 assert!((MAX_SIG_SIZE as u64) < u32::MAX as u64);
724 ct[sig_len_off..sig_len_off + SIG_SIZE_SIZE].copy_from_slice(&u32::MAX.to_be_bytes());
725
726 let mut input = Cursor::new(ct);
727 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
728 assert!(
729 matches!(res, Err(Error::ConstraintViolation)),
730 "expected ConstraintViolation, got {res:?}"
731 );
732 }
733}