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);
219
220 let mut header_sig_raw = Vec::with_capacity(header_sig_len as usize);
221 let mut r = r.take(header_sig_len as u64);
222
223 r.read_to_end(&mut header_sig_raw).await?;
224
225 let h_sig_ext: SignatureExt = crate::bincode_compat::deserialize(&header_sig_raw)?;
226
227 let verifier = Verifier::default().chain(&header_raw);
228 let pub_id = h_sig_ext.pol.derive_ibs()?;
229
230 if !verifier.clone().verify(&pk.0, &h_sig_ext.sig, &pub_id) {
231 return Err(Error::IncorrectSignature);
232 }
233
234 let header: Header = crate::bincode_compat::deserialize(&header_raw)?;
235 let (segment_size, _) = stream_mode_checked(&header)?;
236
237 Ok(Unsealer {
238 version,
239 header,
240 pub_id: h_sig_ext.pol,
241 config: UnsealerStreamConfig { segment_size },
242 r: r.into_inner(), verifier,
244 vk: pk.clone(),
245 })
246 }
247
248 pub async fn unseal<W: AsyncWrite + Unpin>(
250 mut self,
251 ident: &str,
252 usk: &UserSecretKey<CGWKV>,
253 mut w: W,
254 ) -> Result<VerificationResult, Error> {
255 let rec_info = self
256 .header
257 .recipients
258 .get(ident)
259 .ok_or_else(|| Error::UnknownIdentifier(ident.to_string()))?;
260
261 let ss = rec_info.decaps(usk)?;
262 let key = &ss.0[..KEY_SIZE];
263 let aead = Aes128Gcm::new_from_slice(key)?;
264
265 let Algorithm::Aes128Gcm(iv) = self.header.algo;
266 let nonce = &iv.0[..STREAM_NONCE_SIZE];
267
268 let mut dec = DecryptorBE32::from_aead(aead, nonce.into());
269
270 let bufsize: usize = self.config.segment_size as usize + SIG_BYTES + TAG_SIZE;
271 let mut buf = vec![0u8; bufsize];
272 let mut buf_tail = 0;
273 let mut counter: u32 = 0;
274 let mut pol_id: Option<(Policy, Identity)> = None;
275
276 fn extract_policy(buf: &mut Vec<u8>) -> Result<Option<(Policy, Identity)>, Error> {
277 if buf.len() < POL_SIZE_SIZE {
278 return Err(Error::FormatViolation(alloc::string::String::from(
279 "policy length",
280 )));
281 }
282 let pol_len = u32::from_be_bytes(buf[..POL_SIZE_SIZE].try_into()?) as usize;
283 let pol_end = POL_SIZE_SIZE.checked_add(pol_len).ok_or_else(|| {
284 Error::FormatViolation(alloc::string::String::from("policy length overflow"))
285 })?;
286 if buf.len() < pol_end {
287 return Err(Error::FormatViolation(alloc::string::String::from(
288 "policy truncated",
289 )));
290 }
291 let pol_bytes = &buf[POL_SIZE_SIZE..pol_end];
292 let pol: Policy = crate::bincode_compat::deserialize(pol_bytes)?;
293 let id = pol.derive_ibs()?;
294
295 buf.drain(..pol_end);
296
297 Ok(Some((pol, id)))
298 }
299
300 fn verify_segment<'a>(
301 seg: &'a [u8],
302 verifier: &mut Verifier,
303 vk: &VerifyingKey,
304 id: &Identity,
305 counter: u32,
306 is_last: bool,
307 ) -> Result<&'a [u8], Error> {
308 if seg.len() < SIG_BYTES {
309 return Err(Error::FormatViolation(alloc::string::String::from(
310 "segment too short for signature",
311 )));
312 }
313
314 let (m, sig_bytes) = seg.split_at(seg.len() - SIG_BYTES);
315 let sig: Signature = crate::bincode_compat::deserialize(sig_bytes)?;
316 verifier.update(m);
317
318 if !verifier
319 .clone()
320 .chain(&counter.to_be_bytes())
321 .chain(&[is_last as u8])
322 .verify(&vk.0, &sig, id)
323 {
324 return Err(Error::IncorrectSignature);
325 }
326
327 Ok(m)
328 }
329
330 loop {
331 let read = self.r.read(&mut buf[buf_tail..bufsize]).await?;
332 buf_tail += read;
333
334 if buf_tail == bufsize {
335 dec.decrypt_next_in_place(b"", &mut buf)?;
336
337 if counter == 0 {
338 pol_id = extract_policy(&mut buf)?;
339 }
340
341 let m = verify_segment(
342 &buf,
343 &mut self.verifier,
344 &self.vk,
345 &pol_id.as_ref().unwrap().1,
346 counter,
347 false,
348 )?;
349
350 w.write_all(m).await?;
351
352 buf_tail = 0;
353 buf.resize(bufsize, 0);
354 counter += 1;
355 } else if read == 0 {
356 buf.truncate(buf_tail);
357 dec.decrypt_last_in_place(b"", &mut buf)?;
358
359 if counter == 0 {
360 pol_id = extract_policy(&mut buf)?;
361 }
362
363 let m = verify_segment(
364 &buf,
365 &mut self.verifier,
366 &self.vk,
367 &pol_id.as_ref().unwrap().1,
368 counter,
369 true,
370 )?;
371
372 w.write_all(m).await?;
373
374 break;
375 }
376 }
377
378 w.close().await?;
379
380 let private_id = pol_id.unwrap().0;
381 let private = if self.pub_id == private_id {
382 None
383 } else {
384 Some(private_id)
385 };
386
387 Ok(VerificationResult {
388 public: self.pub_id,
389 private,
390 })
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::{Sealer, SealerStreamConfig, Unsealer, UnsealerStreamConfig};
397 use crate::client::VerificationResult;
398 use crate::error::Error;
399 use crate::test::TestSetup;
400 use crate::{PREAMBLE_SIZE, SYMMETRIC_CRYPTO_DEFAULT_CHUNK, TAG_SIZE};
401 use alloc::string::String;
402 use alloc::vec::Vec;
403 use futures::{executor::block_on, io::AllowStdIo};
404 use rand::{thread_rng, Rng, RngCore};
405 use std::io::Cursor;
406 use tokio::io::AsyncReadExt;
407
408 const LENGTHS: &[u32] = &[
409 1,
410 512,
411 SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 3,
412 SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
413 SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 3,
414 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK,
415 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK + 16,
416 3 * SYMMETRIC_CRYPTO_DEFAULT_CHUNK - 17,
417 ];
418
419 fn seal_helper(setup: &TestSetup, plain: &[u8]) -> Vec<u8> {
420 let mut rng = rand::thread_rng();
421
422 let mut input = AllowStdIo::new(Cursor::new(plain));
423 let mut output = AllowStdIo::new(Vec::new());
424
425 let signing_key = &setup.signing_keys[0];
426
427 block_on(async {
428 Sealer::<_, SealerStreamConfig>::new(
429 &setup.ibe_pk,
430 &setup.policy,
431 &signing_key,
432 &mut rng,
433 )
434 .unwrap()
435 .seal(&mut input, &mut output)
436 .await
437 .unwrap();
438 });
439
440 output.into_inner()
441 }
442
443 fn unseal_helper(setup: &TestSetup, ct: &[u8]) -> (Vec<u8>, VerificationResult) {
444 let mut input = AllowStdIo::new(Cursor::new(ct));
445 let mut output = AllowStdIo::new(Vec::new());
446
447 let (id, usk_id) = if thread_rng().gen::<bool>() {
449 ("Bob", setup.usks[2].clone())
450 } else {
451 ("Charlie", setup.usks[3].clone())
452 };
453
454 let vr = block_on(async {
455 let unsealer = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk)
456 .await
457 .unwrap();
458
459 unsealer.unseal(id, &usk_id, &mut output).await.unwrap()
462 });
463
464 (output.into_inner(), vr)
465 }
466
467 fn seal_and_unseal(setup: &TestSetup, plain: Vec<u8>) {
468 let ct = seal_helper(setup, &plain);
469 let (plain2, vr) = unseal_helper(setup, &ct);
470
471 assert_eq!(&plain, &plain2);
472 assert_eq!(&vr.public, &setup.signing_keys[0].policy);
473 assert_eq!(vr.private, None);
474 }
475
476 fn rand_vec(length: usize) -> Vec<u8> {
477 let mut vec = vec![0u8; length];
478 rand::thread_rng().fill_bytes(&mut vec);
479 vec
480 }
481
482 #[test]
483 fn test_reflection_seal_unsealer() {
484 let mut rng = rand::thread_rng();
485 let setup = TestSetup::new(&mut rng);
486
487 for l in LENGTHS {
488 seal_and_unseal(&setup, rand_vec(*l as usize));
489 }
490 }
491
492 #[test]
493 #[should_panic]
494 fn test_corrupt_header() {
495 let mut rng = rand::thread_rng();
496 let setup = TestSetup::new(&mut rng);
497
498 let plain = rand_vec(100);
499 let mut ct = seal_helper(&setup, &plain);
500
501 ct[PREAMBLE_SIZE + 2] = !ct[PREAMBLE_SIZE + 2];
503
504 let _plain2 = unseal_helper(&setup, &ct);
506 }
507
508 #[test]
509 #[should_panic]
510 fn test_corrupt_payload() {
511 let mut rng = rand::thread_rng();
512 let setup = TestSetup::new(&mut rng);
513
514 let plain = rand_vec(100);
515 let mut ct = seal_helper(&setup, &plain);
516
517 let ct_len = ct.len();
519 ct[ct_len - TAG_SIZE - 5] = !ct[ct_len - TAG_SIZE - 5];
520
521 let _plain2 = unseal_helper(&setup, &ct);
523 }
524
525 #[test]
526 #[should_panic]
527 fn test_corrupt_tag() {
528 let mut rng = rand::thread_rng();
529 let setup = TestSetup::new(&mut rng);
530
531 let plain = rand_vec(100);
532 let mut ct = seal_helper(&setup, &plain);
533
534 let len = ct.len();
535 ct[len - 5] = !ct[len - 5];
536
537 let _plain2 = unseal_helper(&setup, &ct);
539 }
540
541 #[tokio::test]
542 async fn test_tokio_file() -> Result<(), Error> {
543 use futures::AsyncWriteExt;
544 use tokio::fs::{File, OpenOptions};
545 use tokio_util::compat::TokioAsyncReadCompatExt;
546
547 let mut rng = rand::thread_rng();
548 let setup = TestSetup::new(&mut rng);
549
550 let signing_key = &setup.signing_keys[0];
551
552 let in_name = std::env::temp_dir().join("foo.txt");
553 let out_name = std::env::temp_dir().join("foo.enc");
554 let orig_name = std::env::temp_dir().join("foo2.txt");
555
556 let mut file = OpenOptions::new()
557 .create(true)
558 .write(true)
559 .truncate(true)
560 .open(&in_name)
561 .await?
562 .compat();
563
564 file.write_all(b"SECRET DATA").await?;
565 file.close().await?;
566
567 let mut in_file = File::open(&in_name).await?.compat();
568 let mut out_file = OpenOptions::new()
569 .create(true)
570 .write(true)
571 .truncate(true)
572 .open(&out_name)
573 .await?
574 .compat();
575
576 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
577 .seal(&mut in_file, &mut out_file)
578 .await?;
579
580 in_file.close().await?;
581 out_file.close().await?;
582
583 let mut out_file = File::open(&out_name).await?.compat();
584 let mut orig_file = OpenOptions::new()
585 .create(true)
586 .write(true)
587 .truncate(true)
588 .open(&orig_name)
589 .await?
590 .compat();
591
592 let id = "Bob";
593 let usk = &setup.usks[2];
594
595 Unsealer::<_, UnsealerStreamConfig>::new(&mut out_file, &setup.ibs_pk)
596 .await?
597 .unseal(id, usk, &mut orig_file)
598 .await?;
599
600 out_file.close().await?;
601 orig_file.close().await?;
602
603 let mut buf = String::new();
604 File::open(&orig_name)
605 .await?
606 .read_to_string(&mut buf)
607 .await?;
608
609 assert_eq!(buf.as_bytes(), b"SECRET DATA");
610
611 Ok(())
612 }
613
614 #[tokio::test]
615 async fn test_cursor() -> Result<(), Error> {
616 use futures::io::Cursor;
617
618 let mut rng = rand::thread_rng();
619 let setup = TestSetup::new(&mut rng);
620
621 let signing_key = &setup.signing_keys[0];
622
623 let mut input = Cursor::new(b"SECRET DATA");
624 let mut encrypted = Vec::new();
625
626 Sealer::<_, SealerStreamConfig>::new(&setup.ibe_pk, &setup.policy, signing_key, &mut rng)?
627 .seal(&mut input, &mut encrypted)
628 .await?;
629
630 let mut original = Vec::new();
631 let id = "Bob";
632 let usk = &setup.usks[2];
633 Unsealer::<_, UnsealerStreamConfig>::new(&mut Cursor::new(encrypted), &setup.ibs_pk)
634 .await?
635 .unseal(id, usk, &mut original)
636 .await?;
637
638 assert_eq!(input.into_inner().to_vec(), original);
639 Ok(())
640 }
641
642 #[tokio::test]
643 async fn test_stream_unseal_rejects_empty_input() {
644 use futures::io::Cursor;
645
646 let mut rng = rand::thread_rng();
647 let setup = TestSetup::new(&mut rng);
648
649 let mut input = Cursor::new(Vec::<u8>::new());
651 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
652 assert!(matches!(res, Err(Error::NotPostGuard)));
653 }
654
655 #[tokio::test]
656 async fn test_stream_unseal_rejects_truncated_preamble() {
657 use futures::io::Cursor;
658
659 let mut rng = rand::thread_rng();
660 let setup = TestSetup::new(&mut rng);
661
662 let mut input = Cursor::new(vec![0u8; PREAMBLE_SIZE - 1]);
665 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
666 assert!(matches!(res, Err(Error::NotPostGuard)));
667 }
668
669 #[tokio::test]
670 async fn test_stream_unseal_rejects_garbage_input() {
671 use futures::io::Cursor;
672
673 let mut rng = rand::thread_rng();
674 let setup = TestSetup::new(&mut rng);
675
676 let mut input = Cursor::new(vec![0u8; 4096]);
679 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
680 assert!(res.is_err());
681 }
682
683 #[tokio::test]
684 async fn test_stream_unseal_rejects_flipped_prelude() {
685 use futures::io::Cursor;
686
687 let mut rng = rand::thread_rng();
688 let setup = TestSetup::new(&mut rng);
689 let mut ct = seal_helper(&setup, b"SECRET DATA");
690
691 ct[0] = ct[0].wrapping_add(1);
694
695 let mut input = Cursor::new(ct);
696 let res = Unsealer::<_, UnsealerStreamConfig>::new(&mut input, &setup.ibs_pk).await;
697 assert!(matches!(res, Err(Error::NotPostGuard)));
698 }
699}