1use std::io;
50use std::cmp;
51use std::fmt;
52
53use crate::{Error, Result};
54use crate::SymmetricAlgorithm;
55use crate::vec_resize;
56use crate::{
57 crypto::SessionKey,
58 parse::Cookie,
59};
60
61use buffered_reader::BufferedReader;
62
63#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
68#[non_exhaustive]
69pub enum BlockCipherMode {
70 CFB,
72
73 CBC,
75
76 ECB,
81}
82
83impl BlockCipherMode {
84 pub fn requires_padding(&self) -> bool {
90 match self {
91 BlockCipherMode::CFB => false,
92 BlockCipherMode::CBC => true,
93 BlockCipherMode::ECB => true,
94 }
95 }
96}
97
98#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
100#[non_exhaustive]
101pub enum PaddingMode {
102 None,
110}
111
112#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
114#[non_exhaustive]
115pub enum UnpaddingMode {
116 None,
124}
125
126pub(crate) trait Context: Send + Sync {
129 fn encrypt(
133 &mut self,
134 dst: &mut [u8],
135 src: &[u8],
136 ) -> Result<()>;
137
138 fn decrypt(
142 &mut self,
143 dst: &mut [u8],
144 src: &[u8],
145 ) -> Result<()>;
146}
147
148pub(crate) struct InternalDecryptor<'a> {
150 source: Box<dyn BufferedReader<Cookie> + 'a>,
152
153 mode: BlockCipherMode,
154 padding: UnpaddingMode,
155 dec: Box<dyn Context>,
156 block_size: usize,
157 buffer: Vec<u8>,
159}
160assert_send_and_sync!(InternalDecryptor<'_>);
161
162impl<'a> InternalDecryptor<'a> {
163 pub fn new<R>(algo: SymmetricAlgorithm,
165 mode: BlockCipherMode,
166 padding: UnpaddingMode,
167 key: &SessionKey,
168 iv: Option<&[u8]>,
169 source: R)
170 -> Result<Self>
171 where
172 R: BufferedReader<Cookie> + 'a,
173 {
174 use crate::crypto::backend::{Backend, interface::Symmetric};
175 let block_size = algo.block_size()?;
176 let dec = Backend::decryptor(algo, mode, key.as_protected(), iv)?;
177
178 Ok(InternalDecryptor {
179 source: source.into_boxed(),
180 mode,
181 padding,
182 dec,
183 block_size,
184 buffer: Vec::with_capacity(block_size),
185 })
186 }
187}
188
189impl<'a> io::Read for InternalDecryptor<'a> {
194 fn read(&mut self, plaintext: &mut [u8]) -> io::Result<usize> {
195 let mut pos = 0;
196
197 if !self.buffer.is_empty() {
199 let to_copy = cmp::min(self.buffer.len(), plaintext.len());
200 plaintext[..to_copy].copy_from_slice(&self.buffer[..to_copy]);
201 crate::vec_drain_prefix(&mut self.buffer, to_copy);
202 pos = to_copy;
203 }
204
205 if pos == plaintext.len() {
206 return Ok(pos);
207 }
208
209 let mut to_copy
211 = ((plaintext.len() - pos) / self.block_size) * self.block_size;
212 let result = self.source.data_consume(to_copy);
213 let short_read;
214 let ciphertext = match result {
215 Ok(data) => {
216 short_read = data.len() < to_copy;
217 to_copy = data.len().min(to_copy);
218 &data[..to_copy]
219 },
220 Err(_) if pos > 0 => return Ok(pos),
222 Err(e) => return Err(e),
223 };
224
225 if ! ciphertext.is_empty() {
228 match self.padding {
230 UnpaddingMode::None => if self.mode.requires_padding()
231 && ciphertext.len() % self.block_size > 0
232 {
233 return Err(io::Error::new(
234 io::ErrorKind::UnexpectedEof,
235 Error::InvalidOperation(
236 "incomplete last block".into())));
237 },
238 }
239
240 self.dec.decrypt(&mut plaintext[pos..pos + to_copy],
241 ciphertext)
242 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
243 format!("{}", e)))?;
244
245 match self.padding {
247 UnpaddingMode::None => (),
248 }
249
250 pos += to_copy;
251 }
252
253 if short_read || pos == plaintext.len() {
254 return Ok(pos);
255 }
256
257 let mut to_copy = plaintext.len() - pos;
259 assert!(0 < to_copy);
260 assert!(to_copy < self.block_size);
261
262 let to_read = self.block_size;
263 let result = self.source.data_consume(to_read);
264 let ciphertext = match result {
265 Ok(data) => {
266 to_copy = cmp::min(to_copy, data.len());
268 &data[..data.len().min(to_read)]
269 },
270 Err(_) if pos > 0 => return Ok(pos),
272 Err(e) => return Err(e),
273 };
274 assert!(ciphertext.len() <= self.block_size);
275
276 if ciphertext.is_empty() {
279 return Ok(pos);
280 }
281
282 vec_resize(&mut self.buffer, ciphertext.len());
283
284 match self.padding {
286 UnpaddingMode::None => if self.mode.requires_padding()
287 && ciphertext.len() % self.block_size > 0
288 {
289 return Err(io::Error::new(
290 io::ErrorKind::UnexpectedEof,
291 Error::InvalidOperation(
292 "incomplete last block".into())));
293 },
294 }
295
296 self.dec.decrypt(&mut self.buffer, ciphertext)
297 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
298 format!("{}", e)))?;
299
300 match self.padding {
302 UnpaddingMode::None => (),
303 }
304
305 plaintext[pos..pos + to_copy].copy_from_slice(&self.buffer[..to_copy]);
306 crate::vec_drain_prefix(&mut self.buffer, to_copy);
307
308 pos += to_copy;
309
310 Ok(pos)
311 }
312}
313
314pub struct Decryptor<'a> {
317 reader: buffered_reader::Generic<InternalDecryptor<'a>, Cookie>,
318}
319
320impl<'a> Decryptor<'a> {
321 pub fn new<R>(algo: SymmetricAlgorithm,
326 mode: BlockCipherMode,
327 padding: UnpaddingMode,
328 key: &SessionKey,
329 iv: Option<&[u8]>,
330 source: R)
331 -> Result<Self>
332 where
333 R: BufferedReader<Cookie> + 'a,
334 {
335 Self::with_cookie(
336 algo, mode, padding, key, iv, source, Default::default())
337 }
338
339 pub fn with_cookie<R>(algo: SymmetricAlgorithm,
341 mode: BlockCipherMode,
342 padding: UnpaddingMode,
343 key: &SessionKey,
344 iv: Option<&[u8]>,
345 reader: R,
346 cookie: Cookie)
347 -> Result<Self>
348 where
349 R: BufferedReader<Cookie> + 'a,
350 {
351 Ok(Decryptor {
352 reader: buffered_reader::Generic::with_cookie(
353 InternalDecryptor::new(algo, mode, padding, key, iv, reader)?,
354 None, cookie),
355 })
356 }
357}
358
359impl<'a> io::Read for Decryptor<'a> {
360 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
361 self.reader.read(buf)
362 }
363}
364
365impl<'a> fmt::Display for Decryptor<'a> {
366 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367 write!(f, "Decryptor")
368 }
369}
370
371impl<'a> fmt::Debug for Decryptor<'a> {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 f.debug_struct("Decryptor")
374 .field("reader", &self.get_ref().unwrap())
375 .finish()
376 }
377}
378
379impl<'a> BufferedReader<Cookie> for Decryptor<'a> {
380 fn buffer(&self) -> &[u8] {
381 self.reader.buffer()
382 }
383
384 fn data(&mut self, amount: usize) -> io::Result<&[u8]> {
385 self.reader.data(amount)
386 }
387
388 fn data_hard(&mut self, amount: usize) -> io::Result<&[u8]> {
389 self.reader.data_hard(amount)
390 }
391
392 fn data_eof(&mut self) -> io::Result<&[u8]> {
393 self.reader.data_eof()
394 }
395
396 fn consume(&mut self, amount: usize) -> &[u8] {
397 self.reader.consume(amount)
398 }
399
400 fn data_consume(&mut self, amount: usize)
401 -> io::Result<&[u8]> {
402 self.reader.data_consume(amount)
403 }
404
405 fn data_consume_hard(&mut self, amount: usize) -> io::Result<&[u8]> {
406 self.reader.data_consume_hard(amount)
407 }
408
409 fn read_be_u16(&mut self) -> io::Result<u16> {
410 self.reader.read_be_u16()
411 }
412
413 fn read_be_u32(&mut self) -> io::Result<u32> {
414 self.reader.read_be_u32()
415 }
416
417 fn steal(&mut self, amount: usize) -> io::Result<Vec<u8>> {
418 self.reader.steal(amount)
419 }
420
421 fn steal_eof(&mut self) -> io::Result<Vec<u8>> {
422 self.reader.steal_eof()
423 }
424
425 fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<Cookie>> {
426 Some(&mut self.reader.reader_mut().source)
427 }
428
429 fn get_ref(&self) -> Option<&dyn BufferedReader<Cookie>> {
430 Some(&self.reader.reader_ref().source)
431 }
432
433 fn into_inner<'b>(self: Box<Self>)
434 -> Option<Box<dyn BufferedReader<Cookie> + 'b>> where Self: 'b {
435 Some(self.reader.into_reader().source.into_boxed())
436 }
437
438 fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
439 self.reader.cookie_set(cookie)
440 }
441
442 fn cookie_ref(&self) -> &Cookie {
443 self.reader.cookie_ref()
444 }
445
446 fn cookie_mut(&mut self) -> &mut Cookie {
447 self.reader.cookie_mut()
448 }
449}
450
451pub struct Encryptor<W: io::Write> {
453 inner: Option<W>,
454
455 mode: BlockCipherMode,
456 padding: PaddingMode,
457 cipher: Box<dyn Context>,
458 block_size: usize,
459 buffer: Vec<u8>,
461 scratch: Vec<u8>,
463}
464assert_send_and_sync!(Encryptor<W> where W: io::Write);
465
466impl<W: io::Write> Encryptor<W> {
467 pub fn new(algo: SymmetricAlgorithm,
472 mode: BlockCipherMode,
473 padding: PaddingMode,
474 key: &SessionKey,
475 iv: Option<&[u8]>,
476 sink: W) -> Result<Self> {
477 use crate::crypto::backend::{Backend, interface::Symmetric};
478 let block_size = algo.block_size()?;
479 let cipher =
480 Backend::encryptor(algo, mode, key.as_protected(), iv)?;
481
482 Ok(Encryptor {
483 inner: Some(sink),
484 mode,
485 padding,
486 cipher,
487 block_size,
488 buffer: Vec::with_capacity(block_size),
489 scratch: vec![0; 4096],
490 })
491 }
492
493 pub fn finalize(mut self) -> Result<W> {
495 self.finalize_intern()
496 }
497
498 fn finalize_intern(&mut self) -> Result<W> {
505 if let Some(mut inner) = self.inner.take() {
506 if !self.buffer.is_empty() {
507 let n = self.buffer.len();
508 assert!(n < self.block_size);
509
510 match self.padding {
512 PaddingMode::None => if self.mode.requires_padding()
513 {
514 return Err(Error::InvalidOperation(
515 "incomplete last block".into())
516 .into());
517 },
518 }
519
520 self.cipher.encrypt(&mut self.scratch[..n], &self.buffer)?;
521
522 match self.padding {
524 PaddingMode::None => (),
525 }
526
527 crate::vec_truncate(&mut self.buffer, 0);
528 inner.write_all(&self.scratch[..n])?;
529 crate::vec_truncate(&mut self.scratch, 0);
530 }
531 Ok(inner)
532 } else {
533 Err(io::Error::new(io::ErrorKind::BrokenPipe,
534 "Inner writer was taken").into())
535 }
536 }
537
538 pub(crate) fn get_ref(&self) -> Option<&W> {
540 self.inner.as_ref()
541 }
542
543 #[allow(dead_code)]
545 pub(crate) fn get_mut(&mut self) -> Option<&mut W> {
546 self.inner.as_mut()
547 }
548}
549
550impl<W: io::Write> io::Write for Encryptor<W> {
551 fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
552 if self.inner.is_none() {
553 return Err(io::Error::new(io::ErrorKind::BrokenPipe,
554 "Inner writer was taken"));
555 }
556 let inner = self.inner.as_mut().unwrap();
557 let amount = buf.len();
558
559 if !self.buffer.is_empty() {
561 let n = cmp::min(buf.len(), self.block_size - self.buffer.len());
562 self.buffer.extend_from_slice(&buf[..n]);
563 assert!(self.buffer.len() <= self.block_size);
564 buf = &buf[n..];
565
566 if self.buffer.len() == self.block_size {
568 self.cipher.encrypt(&mut self.scratch[..self.block_size],
569 &self.buffer)
570 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
571 format!("{}", e)))?;
572 crate::vec_truncate(&mut self.buffer, 0);
573 inner.write_all(&self.scratch[..self.block_size])?;
574 }
575 }
576
577 let whole_blocks = (buf.len() / self.block_size) * self.block_size;
579 if whole_blocks > 0 {
580 if self.scratch.len() < whole_blocks {
582 vec_resize(&mut self.scratch, whole_blocks);
583 }
584
585 self.cipher.encrypt(&mut self.scratch[..whole_blocks],
586 &buf[..whole_blocks])
587 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
588 format!("{}", e)))?;
589 inner.write_all(&self.scratch[..whole_blocks])?;
590 }
591
592 assert!(buf.is_empty() || self.buffer.is_empty());
594 self.buffer.extend_from_slice(&buf[whole_blocks..]);
595 assert!(self.buffer.len() < self.block_size);
596
597 Ok(amount)
598 }
599
600 fn flush(&mut self) -> io::Result<()> {
601 if let Some(ref mut inner) = self.inner {
605 inner.flush()
606 } else {
607 Err(io::Error::new(io::ErrorKind::BrokenPipe,
608 "Inner writer was taken"))
609 }
610 }
611}
612
613impl<W: io::Write> Drop for Encryptor<W> {
614 fn drop(&mut self) {
615 let _ = self.finalize_intern();
619 }
620}
621
622#[cfg(test)]
623mod tests {
624 use super::*;
625 use std::io::{Cursor, Read, Write};
626
627 #[test]
628 fn smoke_test() {
629 use crate::crypto::mem::Protected;
630 use crate::crypto::symmetric::BlockCipherMode;
631 use crate::crypto::backend::{Backend, interface::Symmetric};
632
633 use crate::fmt::hex;
634
635 let algo = SymmetricAlgorithm::AES128;
636 let key: Protected =
637 hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap().into();
638 assert_eq!(key.len(), 16);
639
640 let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
642 let mut cfb =
643 Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
644 let msg = hex::decode("6bc1bee22e409f96e93d7e117393172a").unwrap();
645 let mut dst = vec![0; msg.len()];
646 cfb.encrypt(&mut dst, &*msg).unwrap();
647 assert_eq!(&dst[..16], &*hex::decode("3b3fd92eb72dad20333449f8e83cfb4a").unwrap());
648
649 let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
651 let mut cfb =
652 Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
653 let msg = b"This is a very important message";
654 let mut dst = vec![0; msg.len()];
655 cfb.encrypt(&mut dst, &*msg).unwrap();
656 assert_eq!(&dst, &hex::decode(
657 "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded"
658 ).unwrap());
659
660 let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
662 let mut cfb =
663 Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
664 let msg = b"This is a very important message!";
665 let mut dst = vec![0; msg.len()];
666 cfb.encrypt(&mut dst, &*msg).unwrap();
667 assert_eq!(&dst, &hex::decode(
668 "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded0b"
669 ).unwrap());
670
671 let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
673 let mut cfb =
674 Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
675 let mut dst = vec![0; msg.len()];
676 for (mut dst, msg) in dst.chunks_mut(16).zip(msg.chunks(16)) {
677 cfb.encrypt(&mut dst, msg).unwrap();
678 }
679 assert_eq!(&dst, &hex::decode(
680 "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded0b"
681 ).unwrap());
682 }
683
684 #[test]
689 fn decryptor() {
690 for algo in [SymmetricAlgorithm::AES128,
691 SymmetricAlgorithm::AES192,
692 SymmetricAlgorithm::AES256].iter() {
693 let mut key = vec![0u8; algo.key_size().unwrap()];
695 key[0] = key.len() as u8 - 1;
696 let key = key.into();
697
698 let filename = &format!(
699 "raw/a-cypherpunks-manifesto.aes{}.key_is_key_len_dec1_as_le",
700 algo.key_size().unwrap() * 8);
701 let ciphertext = buffered_reader::Memory::with_cookie(
702 crate::tests::file(filename), Default::default());
703 let decryptor = InternalDecryptor::new(
704 *algo, BlockCipherMode::CFB, UnpaddingMode::None,
705 &key, None, ciphertext).unwrap();
706
707 let mut plaintext = Vec::new();
709 for b in decryptor.bytes() {
710 plaintext.push(b.unwrap());
711 }
712
713 assert_eq!(crate::tests::manifesto(), &plaintext[..]);
714 }
715 }
716
717 #[test]
720 fn encryptor() {
721 for algo in [SymmetricAlgorithm::AES128,
722 SymmetricAlgorithm::AES192,
723 SymmetricAlgorithm::AES256].iter() {
724 let mut key = vec![0u8; algo.key_size().unwrap()];
726 key[0] = key.len() as u8 - 1;
727 let key = key.into();
728
729 let mut ciphertext = Vec::new();
730 {
731 let mut encryptor = Encryptor::new(
732 *algo, BlockCipherMode::CFB, PaddingMode::None,
733 &key, None, &mut ciphertext).unwrap();
734
735 for b in crate::tests::manifesto().chunks(1) {
737 encryptor.write_all(b).unwrap();
738 }
739 }
740
741 let filename = format!(
742 "raw/a-cypherpunks-manifesto.aes{}.key_is_key_len_dec1_as_le",
743 algo.key_size().unwrap() * 8);
744 let mut cipherfile = Cursor::new(crate::tests::file(&filename));
745 let mut reference = Vec::new();
746 cipherfile.read_to_end(&mut reference).unwrap();
747 assert_eq!(&reference[..], &ciphertext[..]);
748 }
749 }
750
751 #[test]
753 fn roundtrip() {
754 for algo in SymmetricAlgorithm::variants()
755 .filter(|x| x.is_supported()) {
756 for mode in [BlockCipherMode::CFB,
757 BlockCipherMode::CBC,
758 BlockCipherMode::ECB] {
759 eprintln!("Testing {:?}/{:?}", algo, mode);
760
761 let bs = algo.block_size().unwrap();
762 let text = if mode.requires_padding() {
763 let l = (crate::tests::manifesto().len() / bs) * bs;
767 &crate::tests::manifesto()[..l]
768 } else {
769 crate::tests::manifesto()
770 };
771
772 let key = SessionKey::new(algo.key_size().unwrap()).unwrap();
773
774 let mut ciphertext = Vec::new();
775 let mut encryptor = Encryptor::new(
776 algo, mode, PaddingMode::None,
777 &key, None, &mut ciphertext).unwrap();
778
779 encryptor.write_all(text).unwrap();
780 encryptor.finalize().unwrap();
781
782 let mut plaintext = Vec::new();
783 let reader = buffered_reader::Memory::with_cookie(
784 &ciphertext, Default::default());
785
786 let mut decryptor = InternalDecryptor::new(
787 algo, mode, UnpaddingMode::None,
788 &key, None, reader).unwrap();
789
790 decryptor.read_to_end(&mut plaintext).unwrap();
791
792 assert_eq!(&plaintext[..], text);
793 }
794 }
795 }
796}