1use aes::{Aes128, Aes192, Aes256};
2use blowfish::Blowfish;
3use camellia::{Camellia128, Camellia192, Camellia256};
4use cast5::Cast5;
5use cfb_mode::{
6 cipher::{AsyncStreamCipher, KeyIvInit},
7 BufEncryptor, Decryptor, Encryptor,
8};
9use cipher::{BlockCipher, BlockDecrypt, BlockEncryptMut};
10use des::TdesEde3;
11use idea::Idea;
12use log::debug;
13use num_enum::{FromPrimitive, IntoPrimitive};
14use rand::{CryptoRng, Rng};
15use twofish::Twofish;
16use zeroize::Zeroizing;
17
18use crate::{
19 composed::RawSessionKey,
20 errors::{bail, unimplemented_err, Result},
21};
22
23mod decryptor;
24mod encryptor;
25
26pub use self::{decryptor::StreamDecryptor, encryptor::StreamEncryptor};
27
28#[cfg(test)]
29fn decrypt<MODE>(key: &[u8], iv: &[u8], prefix: &mut [u8], data: &mut [u8]) -> Result<()>
30where
31 MODE: BlockDecrypt + BlockEncryptMut + BlockCipher,
32 cfb_mode::BufDecryptor<MODE>: KeyIvInit,
33{
34 let mut mode = cfb_mode::BufDecryptor::<MODE>::new_from_slices(key, iv)?;
35
36 mode.decrypt(prefix);
43
44 mode.decrypt(data);
45 Ok(())
46}
47
48#[cfg(test)]
50fn decrypt_resync<MODE>(key: &[u8], iv: &[u8], prefix: &mut [u8], data: &mut [u8]) -> Result<()>
51where
52 MODE: BlockDecrypt + BlockEncryptMut + BlockCipher,
53 cfb_mode::BufDecryptor<MODE>: KeyIvInit,
54{
55 let mut mode = cfb_mode::BufDecryptor::<MODE>::new_from_slices(key, iv)?;
56
57 let encrypted_prefix = prefix[2..].to_vec();
64 mode.decrypt(prefix);
65 mode = cfb_mode::BufDecryptor::<MODE>::new_from_slices(key, &encrypted_prefix)?;
66
67 mode.decrypt(data);
68 Ok(())
69}
70
71fn encrypt<MODE>(key: &[u8], iv: &[u8], prefix: &mut [u8], data: &mut [u8]) -> Result<()>
72where
73 MODE: BlockDecrypt + BlockEncryptMut + BlockCipher,
74 BufEncryptor<MODE>: KeyIvInit,
75{
76 let mut mode = BufEncryptor::<MODE>::new_from_slices(key, iv)?;
77 mode.encrypt(prefix);
78
79 mode.encrypt(data);
80
81 Ok(())
82}
83
84fn encrypt_resync<MODE>(key: &[u8], iv: &[u8], prefix: &mut [u8], data: &mut [u8]) -> Result<()>
88where
89 MODE: BlockDecrypt + BlockEncryptMut + BlockCipher,
90 BufEncryptor<MODE>: KeyIvInit,
91{
92 let mut mode = BufEncryptor::<MODE>::new_from_slices(key, iv)?;
93 mode.encrypt(prefix);
94
95 mode = BufEncryptor::<MODE>::new_from_slices(key, &prefix[2..])?;
97 mode.encrypt(data);
98
99 Ok(())
100}
101
102#[derive(Debug, PartialEq, Eq, Copy, Clone, FromPrimitive, IntoPrimitive)]
105#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
106#[repr(u8)]
107#[non_exhaustive]
108pub enum SymmetricKeyAlgorithm {
109 #[cfg_attr(test, proptest(skip))]
111 Plaintext = 0,
112 IDEA = 1,
114 TripleDES = 2,
116 CAST5 = 3,
118 Blowfish = 4,
120 AES128 = 7,
123 AES192 = 8,
125 AES256 = 9,
127 Twofish = 10,
129 Camellia128 = 11,
131 Camellia192 = 12,
133 Camellia256 = 13,
135 Private10 = 110,
136
137 #[num_enum(catch_all)]
138 Other(#[cfg_attr(test, proptest(strategy = "111u8.."))] u8),
139}
140
141#[allow(clippy::derivable_impls)]
142impl Default for SymmetricKeyAlgorithm {
143 fn default() -> Self {
144 Self::AES128
145 }
146}
147
148impl zeroize::DefaultIsZeroes for SymmetricKeyAlgorithm {}
149
150impl SymmetricKeyAlgorithm {
151 pub fn block_size(self) -> usize {
154 match self {
155 SymmetricKeyAlgorithm::Plaintext => 0,
156 SymmetricKeyAlgorithm::IDEA => 8,
157 SymmetricKeyAlgorithm::TripleDES => 8,
158 SymmetricKeyAlgorithm::CAST5 => 8,
159 SymmetricKeyAlgorithm::Blowfish => 8,
160 SymmetricKeyAlgorithm::AES128 => 16,
161 SymmetricKeyAlgorithm::AES192 => 16,
162 SymmetricKeyAlgorithm::AES256 => 16,
163 SymmetricKeyAlgorithm::Twofish => 16,
164 SymmetricKeyAlgorithm::Camellia128 => 16,
165 SymmetricKeyAlgorithm::Camellia192 => 16,
166 SymmetricKeyAlgorithm::Camellia256 => 16,
167 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => 0,
168 }
169 }
170
171 #[cfg(test)]
172 pub(crate) fn cfb_prefix_size(&self) -> usize {
173 self.block_size() + 2
174 }
175
176 pub const fn key_size(self) -> usize {
179 match self {
180 SymmetricKeyAlgorithm::Plaintext => 0,
181 SymmetricKeyAlgorithm::IDEA => 16,
182 SymmetricKeyAlgorithm::TripleDES => 24,
183 SymmetricKeyAlgorithm::CAST5 => 16,
184 SymmetricKeyAlgorithm::Blowfish => 16, SymmetricKeyAlgorithm::AES128 => 16,
187 SymmetricKeyAlgorithm::AES192 => 24,
188 SymmetricKeyAlgorithm::AES256 => 32,
189 SymmetricKeyAlgorithm::Twofish => 32,
190 SymmetricKeyAlgorithm::Camellia128 => 16,
191 SymmetricKeyAlgorithm::Camellia192 => 24,
192 SymmetricKeyAlgorithm::Camellia256 => 32,
193
194 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => 0,
195 }
196 }
197
198 #[cfg(test)]
204 pub fn decrypt(self, key: &[u8], prefix: &mut [u8], ciphertext: &mut [u8]) -> Result<()> {
205 debug!("unprotected decrypt");
206 let iv_vec = vec![0u8; self.block_size()];
207 self.decrypt_with_iv_resync(key, &iv_vec, prefix, ciphertext)?;
208 Ok(())
209 }
210
211 #[cfg(test)]
219 pub fn decrypt_protected(
220 self,
221 key: &[u8],
222 prefix: &mut [u8],
223 ciphertext: &mut Vec<u8>,
224 ) -> Result<()> {
225 debug!("protected decrypt");
226
227 let iv_vec = vec![0u8; self.block_size()];
228 self.decrypt_with_iv(key, &iv_vec, prefix, ciphertext)?;
229
230 const MDC_LEN: usize = 22;
232 let mdc = ciphertext.split_off(ciphertext.len() - MDC_LEN);
233
234 let sha1 = calculate_sha1_unchecked([prefix, &ciphertext[..], &mdc[0..2]]);
236 if mdc[0] != 0xD3 || mdc[1] != 0x14 || mdc[2..] != sha1[..]
239 {
240 return Err(crate::errors::Error::MdcError);
241 }
242
243 Ok(())
244 }
245
246 #[cfg(test)]
262 pub fn decrypt_with_iv(
263 self,
264 key: &[u8],
265 iv_vec: &[u8],
266 encrypted_prefix: &mut [u8],
267 encrypted_data: &mut [u8],
268 ) -> Result<()> {
269 let bs = self.block_size();
270 let ciphertext_len = encrypted_prefix.len() + encrypted_data.len();
271 crate::errors::ensure!(bs + 2 < ciphertext_len, "invalid ciphertext");
272
273 match self {
274 SymmetricKeyAlgorithm::Plaintext => {
275 bail!("'Plaintext' is not a legal cipher for encrypted data")
276 }
277 SymmetricKeyAlgorithm::IDEA => {
278 decrypt::<Idea>(key, iv_vec, encrypted_prefix, encrypted_data)?;
279 }
280 SymmetricKeyAlgorithm::TripleDES => {
281 decrypt::<TdesEde3>(key, iv_vec, encrypted_prefix, encrypted_data)?;
282 }
283 SymmetricKeyAlgorithm::CAST5 => {
284 decrypt::<Cast5>(key, iv_vec, encrypted_prefix, encrypted_data)?;
285 }
286 SymmetricKeyAlgorithm::Blowfish => {
287 decrypt::<Blowfish>(key, iv_vec, encrypted_prefix, encrypted_data)?;
288 }
289 SymmetricKeyAlgorithm::AES128 => {
290 decrypt::<Aes128>(key, iv_vec, encrypted_prefix, encrypted_data)?;
291 }
292 SymmetricKeyAlgorithm::AES192 => {
293 decrypt::<Aes192>(key, iv_vec, encrypted_prefix, encrypted_data)?;
294 }
295 SymmetricKeyAlgorithm::AES256 => {
296 decrypt::<Aes256>(key, iv_vec, encrypted_prefix, encrypted_data)?;
297 }
298 SymmetricKeyAlgorithm::Twofish => {
299 decrypt::<Twofish>(key, iv_vec, encrypted_prefix, encrypted_data)?;
300 }
301 SymmetricKeyAlgorithm::Camellia128 => {
302 decrypt::<Camellia128>(key, iv_vec, encrypted_prefix, encrypted_data)?;
303 }
304 SymmetricKeyAlgorithm::Camellia192 => {
305 decrypt::<Camellia192>(key, iv_vec, encrypted_prefix, encrypted_data)?;
306 }
307 SymmetricKeyAlgorithm::Camellia256 => {
308 decrypt::<Camellia256>(key, iv_vec, encrypted_prefix, encrypted_data)?
309 }
310 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
311 unimplemented_err!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
312 }
313 }
314
315 Ok(())
316 }
317
318 #[cfg(test)]
322 pub fn decrypt_with_iv_resync(
323 self,
324 key: &[u8],
325 iv_vec: &[u8],
326 encrypted_prefix: &mut [u8],
327 encrypted_data: &mut [u8],
328 ) -> Result<()> {
329 let bs = self.block_size();
330 let ciphertext_len = encrypted_prefix.len() + encrypted_data.len();
331 crate::errors::ensure!(bs + 2 < ciphertext_len, "invalid ciphertext");
332
333 match self {
334 SymmetricKeyAlgorithm::Plaintext => {
335 bail!("'Plaintext' is not a legal cipher for encrypted data")
336 }
337 SymmetricKeyAlgorithm::IDEA => {
338 decrypt_resync::<Idea>(key, iv_vec, encrypted_prefix, encrypted_data)?;
339 }
340 SymmetricKeyAlgorithm::TripleDES => {
341 decrypt_resync::<TdesEde3>(key, iv_vec, encrypted_prefix, encrypted_data)?;
342 }
343 SymmetricKeyAlgorithm::CAST5 => {
344 decrypt_resync::<Cast5>(key, iv_vec, encrypted_prefix, encrypted_data)?;
345 }
346 SymmetricKeyAlgorithm::Blowfish => {
347 decrypt_resync::<Blowfish>(key, iv_vec, encrypted_prefix, encrypted_data)?;
348 }
349 SymmetricKeyAlgorithm::AES128 => {
350 decrypt_resync::<Aes128>(key, iv_vec, encrypted_prefix, encrypted_data)?;
351 }
352 SymmetricKeyAlgorithm::AES192 => {
353 decrypt_resync::<Aes192>(key, iv_vec, encrypted_prefix, encrypted_data)?;
354 }
355 SymmetricKeyAlgorithm::AES256 => {
356 decrypt_resync::<Aes256>(key, iv_vec, encrypted_prefix, encrypted_data)?;
357 }
358 SymmetricKeyAlgorithm::Twofish => {
359 decrypt_resync::<Twofish>(key, iv_vec, encrypted_prefix, encrypted_data)?;
360 }
361 SymmetricKeyAlgorithm::Camellia128 => {
362 decrypt_resync::<Camellia128>(key, iv_vec, encrypted_prefix, encrypted_data)?;
363 }
364 SymmetricKeyAlgorithm::Camellia192 => {
365 decrypt_resync::<Camellia192>(key, iv_vec, encrypted_prefix, encrypted_data)?;
366 }
367 SymmetricKeyAlgorithm::Camellia256 => {
368 decrypt_resync::<Camellia256>(key, iv_vec, encrypted_prefix, encrypted_data)?
369 }
370 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
371 unimplemented_err!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
372 }
373 }
374
375 Ok(())
376 }
377
378 pub fn decrypt_with_iv_regular(
381 self,
382 key: &[u8],
383 iv_vec: &[u8],
384 ciphertext: &mut [u8],
385 ) -> Result<()> {
386 match self {
387 SymmetricKeyAlgorithm::Plaintext => {
388 bail!("'Plaintext' is not a legal cipher for encrypted data")
389 }
390 SymmetricKeyAlgorithm::IDEA => {
391 Decryptor::<Idea>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
392 }
393 SymmetricKeyAlgorithm::TripleDES => {
394 Decryptor::<TdesEde3>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
395 }
396 SymmetricKeyAlgorithm::CAST5 => {
397 Decryptor::<Cast5>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
398 }
399 SymmetricKeyAlgorithm::Blowfish => {
400 Decryptor::<Blowfish>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
401 }
402 SymmetricKeyAlgorithm::AES128 => {
403 Decryptor::<Aes128>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
404 }
405 SymmetricKeyAlgorithm::AES192 => {
406 Decryptor::<Aes192>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
407 }
408 SymmetricKeyAlgorithm::AES256 => {
409 Decryptor::<Aes256>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
410 }
411 SymmetricKeyAlgorithm::Twofish => {
412 Decryptor::<Twofish>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
413 }
414 SymmetricKeyAlgorithm::Camellia128 => {
415 Decryptor::<Camellia128>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
416 }
417 SymmetricKeyAlgorithm::Camellia192 => {
418 Decryptor::<Camellia192>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
419 }
420 SymmetricKeyAlgorithm::Camellia256 => {
421 Decryptor::<Camellia256>::new_from_slices(key, iv_vec)?.decrypt(ciphertext);
422 }
423 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
424 unimplemented_err!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
425 }
426 }
427
428 Ok(())
429 }
430
431 pub fn encrypt<R: CryptoRng + Rng>(
434 self,
435 mut rng: R,
436 key: &[u8],
437 plaintext: &[u8],
438 ) -> Result<Vec<u8>> {
439 debug!("encrypt unprotected");
440
441 let iv_vec = vec![0u8; self.block_size()];
442
443 let bs = self.block_size();
444
445 let prefix_len = bs + 2;
446 let plaintext_len = plaintext.len();
447
448 let mut ciphertext = vec![0u8; prefix_len + plaintext_len];
449 rng.fill_bytes(&mut ciphertext[..bs]);
451
452 ciphertext[bs] = ciphertext[bs - 2];
454 ciphertext[bs + 1] = ciphertext[bs - 1];
455
456 ciphertext[prefix_len..].copy_from_slice(plaintext);
458
459 self.encrypt_with_iv_resync(key, &iv_vec, &mut ciphertext)?;
460
461 Ok(ciphertext)
462 }
463
464 pub fn encrypt_protected<R: CryptoRng + Rng>(
465 self,
466 mut rng: R,
467 key: &[u8],
468 plaintext: &[u8],
469 ) -> Result<Vec<u8>> {
470 use sha1::{Digest, Sha1};
472
473 debug!("protected encrypt");
474
475 let mdc_len = 22;
477
478 let bs = self.block_size();
479
480 let prefix_len = bs + 2;
481 let plaintext_len = plaintext.len();
482
483 let mut ciphertext = vec![0u8; prefix_len + plaintext_len + mdc_len];
484
485 rng.fill_bytes(&mut ciphertext[..bs]);
487
488 ciphertext[bs] = ciphertext[bs - 2];
490 ciphertext[bs + 1] = ciphertext[bs - 1];
491
492 ciphertext[prefix_len..(prefix_len + plaintext_len)].copy_from_slice(plaintext);
494 ciphertext[prefix_len + plaintext_len] = 0xD3;
496 ciphertext[prefix_len + plaintext_len + 1] = 0x14;
497 let checksum = &Sha1::digest(&ciphertext[..(prefix_len + plaintext_len + 2)])[..20];
499 ciphertext[(prefix_len + plaintext_len + 2)..].copy_from_slice(checksum);
500
501 let iv_vec = vec![0u8; self.block_size()];
503
504 self.encrypt_with_iv(key, &iv_vec, &mut ciphertext)?;
505
506 Ok(ciphertext)
507 }
508
509 pub fn encrypted_protected_len(&self, plaintext_len: usize) -> usize {
510 self.encrypted_protected_overhead() + plaintext_len
511 }
512
513 pub fn encrypted_protected_overhead(&self) -> usize {
514 self.block_size() +
518 2 +
520 22
522 }
523
524 pub fn stream_encryptor<R, I>(
525 self,
526 rng: R,
527 key: &[u8],
528 plaintext: I,
529 ) -> Result<StreamEncryptor<I>>
530 where
531 R: Rng + CryptoRng,
532 I: std::io::Read,
533 {
534 StreamEncryptor::new(rng, self, key, plaintext)
535 }
536
537 pub fn stream_decryptor_protected<R>(
539 self,
540 key: &[u8],
541 ciphertext: R,
542 ) -> Result<StreamDecryptor<R>>
543 where
544 R: std::io::BufRead,
545 {
546 StreamDecryptor::new(self, true, key, ciphertext)
547 }
548
549 pub fn stream_decryptor_unprotected<R>(
551 self,
552 key: &[u8],
553 ciphertext: R,
554 ) -> Result<StreamDecryptor<R>>
555 where
556 R: std::io::BufRead,
557 {
558 StreamDecryptor::new(self, false, key, ciphertext)
559 }
560
561 pub fn encrypt_with_iv(self, key: &[u8], iv_vec: &[u8], ciphertext: &mut [u8]) -> Result<()> {
568 let bs = self.block_size();
569
570 let (prefix, data) = ciphertext.split_at_mut(bs + 2);
571
572 {
573 match self {
574 SymmetricKeyAlgorithm::Plaintext => {
575 bail!("'Plaintext' is not a legal cipher for encrypted data")
576 }
577 SymmetricKeyAlgorithm::IDEA => {
578 encrypt::<Idea>(key, iv_vec, prefix, data)?;
579 }
580 SymmetricKeyAlgorithm::TripleDES => {
581 encrypt::<TdesEde3>(key, iv_vec, prefix, data)?;
582 }
583 SymmetricKeyAlgorithm::CAST5 => {
584 encrypt::<Cast5>(key, iv_vec, prefix, data)?;
585 }
586 SymmetricKeyAlgorithm::Blowfish => {
587 encrypt::<Blowfish>(key, iv_vec, prefix, data)?;
588 }
589 SymmetricKeyAlgorithm::AES128 => {
590 encrypt::<Aes128>(key, iv_vec, prefix, data)?;
591 }
592 SymmetricKeyAlgorithm::AES192 => {
593 encrypt::<Aes192>(key, iv_vec, prefix, data)?;
594 }
595 SymmetricKeyAlgorithm::AES256 => encrypt::<Aes256>(key, iv_vec, prefix, data)?,
596 SymmetricKeyAlgorithm::Twofish => {
597 encrypt::<Twofish>(key, iv_vec, prefix, data)?;
598 }
599 SymmetricKeyAlgorithm::Camellia128 => {
600 encrypt::<Camellia128>(key, iv_vec, prefix, data)?;
601 }
602 SymmetricKeyAlgorithm::Camellia192 => {
603 encrypt::<Camellia192>(key, iv_vec, prefix, data)?;
604 }
605 SymmetricKeyAlgorithm::Camellia256 => {
606 encrypt::<Camellia256>(key, iv_vec, prefix, data)?;
607 }
608 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
609 bail!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
610 }
611 }
612 }
613
614 Ok(())
615 }
616
617 pub fn encrypt_with_iv_resync(
619 self,
620 key: &[u8],
621 iv_vec: &[u8],
622 ciphertext: &mut [u8],
623 ) -> Result<()> {
624 let bs = self.block_size();
625
626 let (prefix, data) = ciphertext.split_at_mut(bs + 2);
627
628 {
629 match self {
630 SymmetricKeyAlgorithm::Plaintext => {
631 bail!("'Plaintext' is not a legal cipher for encrypted data")
632 }
633 SymmetricKeyAlgorithm::IDEA => {
634 encrypt_resync::<Idea>(key, iv_vec, prefix, data)?;
635 }
636 SymmetricKeyAlgorithm::TripleDES => {
637 encrypt_resync::<TdesEde3>(key, iv_vec, prefix, data)?;
638 }
639 SymmetricKeyAlgorithm::CAST5 => {
640 encrypt_resync::<Cast5>(key, iv_vec, prefix, data)?;
641 }
642 SymmetricKeyAlgorithm::Blowfish => {
643 encrypt_resync::<Blowfish>(key, iv_vec, prefix, data)?;
644 }
645 SymmetricKeyAlgorithm::AES128 => {
646 encrypt_resync::<Aes128>(key, iv_vec, prefix, data)?;
647 }
648 SymmetricKeyAlgorithm::AES192 => {
649 encrypt_resync::<Aes192>(key, iv_vec, prefix, data)?;
650 }
651 SymmetricKeyAlgorithm::AES256 => {
652 encrypt_resync::<Aes256>(key, iv_vec, prefix, data)?
653 }
654 SymmetricKeyAlgorithm::Twofish => {
655 encrypt_resync::<Twofish>(key, iv_vec, prefix, data)?;
656 }
657 SymmetricKeyAlgorithm::Camellia128 => {
658 encrypt_resync::<Camellia128>(key, iv_vec, prefix, data)?;
659 }
660 SymmetricKeyAlgorithm::Camellia192 => {
661 encrypt_resync::<Camellia192>(key, iv_vec, prefix, data)?;
662 }
663 SymmetricKeyAlgorithm::Camellia256 => {
664 encrypt_resync::<Camellia256>(key, iv_vec, prefix, data)?;
665 }
666 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
667 bail!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
668 }
669 }
670 }
671
672 Ok(())
673 }
674
675 pub fn encrypt_with_iv_regular(
677 self,
678 key: &[u8],
679 iv_vec: &[u8],
680 plaintext: &mut [u8],
681 ) -> Result<()> {
682 match self {
683 SymmetricKeyAlgorithm::Plaintext => {
684 bail!("'Plaintext' is not a legal cipher for encrypted data")
685 }
686 SymmetricKeyAlgorithm::IDEA => {
687 Encryptor::<Idea>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
688 }
689 SymmetricKeyAlgorithm::TripleDES => {
690 Encryptor::<TdesEde3>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
691 }
692 SymmetricKeyAlgorithm::CAST5 => {
693 Encryptor::<Cast5>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
694 }
695 SymmetricKeyAlgorithm::Blowfish => {
696 Encryptor::<Blowfish>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
697 }
698 SymmetricKeyAlgorithm::AES128 => {
699 Encryptor::<Aes128>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
700 }
701 SymmetricKeyAlgorithm::AES192 => {
702 Encryptor::<Aes192>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
703 }
704 SymmetricKeyAlgorithm::AES256 => {
705 Encryptor::<Aes256>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
706 }
707 SymmetricKeyAlgorithm::Twofish => {
708 Encryptor::<Twofish>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
709 }
710 SymmetricKeyAlgorithm::Camellia128 => {
711 Encryptor::<Camellia128>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
712 }
713 SymmetricKeyAlgorithm::Camellia192 => {
714 Encryptor::<Camellia192>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
715 }
716 SymmetricKeyAlgorithm::Camellia256 => {
717 Encryptor::<Camellia256>::new_from_slices(key, iv_vec)?.encrypt(plaintext);
718 }
719 SymmetricKeyAlgorithm::Private10 | SymmetricKeyAlgorithm::Other(_) => {
720 unimplemented_err!("SymmetricKeyAlgorithm {} is unsupported", u8::from(self))
721 }
722 }
723 Ok(())
724 }
725
726 pub fn new_session_key<R: Rng + CryptoRng>(self, mut rng: R) -> RawSessionKey {
728 let mut session_key = Zeroizing::new(vec![0u8; self.key_size()]);
729 rng.fill_bytes(&mut session_key);
730 session_key.into()
731 }
732}
733
734#[inline]
735#[cfg(test)]
736fn calculate_sha1_unchecked<I, T>(data: I) -> [u8; 20]
737where
738 T: AsRef<[u8]>,
739 I: IntoIterator<Item = T>,
740{
741 use sha1::{Digest, Sha1};
742
743 let mut digest = Sha1::new();
744 for chunk in data {
745 digest.update(chunk.as_ref());
746 }
747 digest.finalize().into()
748}
749
750#[cfg(test)]
751mod tests {
752 use std::{io::Read, time::Instant};
753
754 use log::info;
755 use rand::{Rng, SeedableRng};
756 use rand_chacha::ChaCha8Rng;
757
758 use super::*;
759
760 macro_rules! roundtrip_unprotected {
761 ($name:ident, $alg:path) => {
762 #[test]
763 fn $name() {
764 pretty_env_logger::try_init().ok();
765
766 let mut data_rng = ChaCha8Rng::seed_from_u64(0);
767
768 const MAX_SIZE: usize = 2048;
769
770 for i in 1..MAX_SIZE {
772 info!("Size {}", i);
773 let mut data = vec![0u8; i];
774 data_rng.fill(&mut data[..]);
775 let mut key = vec![0u8; $alg.key_size()];
776 data_rng.fill(&mut key[..]);
777
778 info!("unprotected encrypt");
779 let mut rng = ChaCha8Rng::seed_from_u64(8);
780 let ciphertext = $alg.encrypt(&mut rng, &key, &data).unwrap();
781 assert_ne!(data, ciphertext);
782
783 {
784 info!("unprotected decrypt");
785 let mut ciphertext = ciphertext.clone();
786 let mut plaintext = ciphertext.split_off($alg.cfb_prefix_size());
787 let mut prefix = ciphertext;
788 $alg.decrypt(&key, &mut prefix, &mut plaintext).unwrap();
789 assert_eq!(
790 hex::encode(&data),
791 hex::encode(&plaintext),
792 "unprotected decrypt"
793 );
794 }
795
796 {
797 info!("unprotected decrypt streaming");
798 dbg!(ciphertext.len(), $alg.cfb_prefix_size());
799 let mut input = std::io::Cursor::new(&ciphertext);
800 let mut decryptor =
801 $alg.stream_decryptor_unprotected(&key, &mut input).unwrap();
802 let mut plaintext = Vec::new();
803 decryptor.read_to_end(&mut plaintext).unwrap();
804 assert_eq!(
805 hex::encode(&data),
806 hex::encode(&plaintext),
807 "stream decrypt failed"
808 );
809 }
810 }
811 }
812 };
813 }
814
815 macro_rules! roundtrip_protected {
816 ($name:ident, $alg:path) => {
817 #[test]
818 fn $name() {
819 pretty_env_logger::try_init().ok();
820
821 let mut data_rng = ChaCha8Rng::seed_from_u64(0);
822
823 const MAX_SIZE: usize = 2048;
824
825 for i in 1..MAX_SIZE {
827 info!("Size {}", i);
828 let mut data = vec![0u8; i];
829 data_rng.fill(&mut data[..]);
830 let mut key = vec![0u8; $alg.key_size()];
831 data_rng.fill(&mut key[..]);
832
833 info!("encrypt");
834 let mut rng = ChaCha8Rng::seed_from_u64(8);
835 let ciphertext = $alg.encrypt_protected(&mut rng, &key, &data).unwrap();
836 assert_ne!(data, ciphertext, "failed to encrypt");
837
838 {
839 info!("encrypt streaming");
840 let mut input = std::io::Cursor::new(&data);
841 let len = $alg.encrypted_protected_len(data.len());
842 assert_eq!(len, ciphertext.len(), "failed to encrypt");
843 let mut output = Vec::new();
844 let mut rng = ChaCha8Rng::seed_from_u64(8);
845 let mut encryptor =
846 $alg.stream_encryptor(&mut rng, &key, &mut input).unwrap();
847 encryptor.read_to_end(&mut output).unwrap();
848
849 assert_eq!(output.len(), len, "output length mismatch");
850 assert_eq!(ciphertext, output, "output mismatch");
851 }
852
853 {
854 info!("decrypt");
855 let mut ciphertext = ciphertext.clone();
856 let mut plaintext = ciphertext.split_off($alg.cfb_prefix_size());
857 let mut prefix = ciphertext;
858 $alg.decrypt_protected(&key, &mut prefix, &mut plaintext)
859 .unwrap();
860 assert_eq!(data, plaintext, "decrypt failed");
861 }
862 {
863 info!("decrypt streaming");
864 dbg!(ciphertext.len(), $alg.cfb_prefix_size());
865 let mut input = std::io::Cursor::new(&ciphertext);
866 let mut decryptor =
867 $alg.stream_decryptor_protected(&key, &mut input).unwrap();
868 let mut plaintext = Vec::new();
869 decryptor.read_to_end(&mut plaintext).unwrap();
870 assert_eq!(
871 hex::encode(&data),
872 hex::encode(&plaintext),
873 "stream decrypt failed"
874 );
875 }
876 }
877 }
878 };
879 }
880
881 roundtrip_protected!(roundtrip_protected_aes128, SymmetricKeyAlgorithm::AES128);
882 roundtrip_protected!(roundtrip_protected_aes192, SymmetricKeyAlgorithm::AES192);
883 roundtrip_protected!(roundtrip_protected_aes256, SymmetricKeyAlgorithm::AES256);
884 roundtrip_protected!(
885 roundtrip_protected_tripledes,
886 SymmetricKeyAlgorithm::TripleDES
887 );
888 roundtrip_protected!(
889 roundtrip_protected_blowfish,
890 SymmetricKeyAlgorithm::Blowfish
891 );
892 roundtrip_protected!(roundtrip_protected_twofish, SymmetricKeyAlgorithm::Twofish);
893 roundtrip_protected!(roundtrip_protected_cast5, SymmetricKeyAlgorithm::CAST5);
894 roundtrip_protected!(roundtrip_protected_idea, SymmetricKeyAlgorithm::IDEA);
895 roundtrip_protected!(
896 roundtrip_protected_camellia128,
897 SymmetricKeyAlgorithm::Camellia128
898 );
899 roundtrip_protected!(
900 roundtrip_protected_camellia192,
901 SymmetricKeyAlgorithm::Camellia192
902 );
903 roundtrip_protected!(
904 roundtrip_protected_camellia256,
905 SymmetricKeyAlgorithm::Camellia256
906 );
907
908 roundtrip_unprotected!(roundtrip_unprotected_aes128, SymmetricKeyAlgorithm::AES128);
909 roundtrip_unprotected!(roundtrip_unprotected_aes192, SymmetricKeyAlgorithm::AES192);
910 roundtrip_unprotected!(roundtrip_unprotected_aes256, SymmetricKeyAlgorithm::AES256);
911 roundtrip_unprotected!(
912 roundtrip_unprotected_tripledes,
913 SymmetricKeyAlgorithm::TripleDES
914 );
915 roundtrip_unprotected!(
916 roundtrip_unprotected_blowfish,
917 SymmetricKeyAlgorithm::Blowfish
918 );
919 roundtrip_unprotected!(
920 roundtrip_unprotected_twofish,
921 SymmetricKeyAlgorithm::Twofish
922 );
923 roundtrip_unprotected!(roundtrip_unprotected_cast5, SymmetricKeyAlgorithm::CAST5);
924 roundtrip_unprotected!(roundtrip_unprotected_idea, SymmetricKeyAlgorithm::IDEA);
925 roundtrip_unprotected!(
926 roundtrip_unprotected_camellia128,
927 SymmetricKeyAlgorithm::Camellia128
928 );
929 roundtrip_unprotected!(
930 roundtrip_unprotected_camellia192,
931 SymmetricKeyAlgorithm::Camellia192
932 );
933 roundtrip_unprotected!(
934 roundtrip_unprotected_camellia256,
935 SymmetricKeyAlgorithm::Camellia256
936 );
937
938 #[test]
939 pub fn decrypt_without_enough_ciphertext() {
940 let key: [u8; 0] = [];
941 let mut prefix: [u8; 0] = [];
942 let mut cipher_text: [u8; 0] = [];
943 assert!(SymmetricKeyAlgorithm::AES128
944 .decrypt(&key, &mut prefix, &mut cipher_text)
945 .is_err());
946 }
947
948 use rand::RngCore;
949
950 #[ignore]
951 #[test]
952 fn bench_aes_256_protected() {
953 const SIZE: usize = 1024 * 1024 * 64;
954 let mut rng = ChaCha8Rng::seed_from_u64(0);
955 let mut data = vec![0u8; SIZE];
956 rng.fill_bytes(&mut data);
957
958 let mut key = vec![0u8; SymmetricKeyAlgorithm::AES256.key_size()];
959 rng.fill_bytes(&mut key);
960
961 let now = Instant::now();
962 let mut encryptor = SymmetricKeyAlgorithm::AES256
963 .stream_encryptor(&mut rng, &key, &data[..])
964 .unwrap();
965
966 let mut output = Vec::with_capacity(SIZE);
967 encryptor.read_to_end(&mut output).unwrap();
968
969 let elapsed = now.elapsed();
970 let elapsed_milli = elapsed.as_millis();
971 let mb_per_s = ((SIZE as f64) / 1000f64 / 1000f64 / elapsed_milli as f64) * 1000f64;
972 println!("Encryption: {elapsed_milli} ms, MByte/s: {mb_per_s:.2?}");
973
974 let now = Instant::now();
975
976 let mut decryptor = SymmetricKeyAlgorithm::AES256
977 .stream_decryptor_protected(&key, &output[..])
978 .unwrap();
979 let mut res = Vec::with_capacity(SIZE);
980 decryptor.read_to_end(&mut res).unwrap();
981 let elapsed = now.elapsed();
982
983 assert_eq!(res, data);
984
985 let elapsed_milli = elapsed.as_millis();
986 let mb_per_s = (SIZE as f64 / 1000f64 / 1000f64 / elapsed_milli as f64) * 1000f64;
987 println!("Decryption: {elapsed_milli} ms, MByte/s: {mb_per_s:.2?}");
988 }
989
990 #[ignore]
991 #[test]
992 fn bench_aes_256_unprotected() {
993 const SIZE: usize = 1024 * 1024 * 256;
994 let mut rng = ChaCha8Rng::seed_from_u64(0);
995 let mut data = vec![0u8; SIZE];
996 rng.fill_bytes(&mut data);
997
998 let mut key = vec![0u8; SymmetricKeyAlgorithm::AES256.key_size()];
999 rng.fill_bytes(&mut key);
1000
1001 let now = Instant::now();
1002 let output = SymmetricKeyAlgorithm::AES256
1003 .encrypt(&mut rng, &key, &data[..])
1004 .unwrap();
1005
1006 let elapsed = now.elapsed();
1007 let elapsed_milli = elapsed.as_millis();
1008 let mb_per_s = ((SIZE as f64) / 1000f64 / 1000f64 / elapsed_milli as f64) * 1000f64;
1009 println!("Encryption: {elapsed_milli} ms, MByte/s: {mb_per_s:.2?}");
1010
1011 let now = Instant::now();
1012
1013 let mut decryptor = SymmetricKeyAlgorithm::AES256
1014 .stream_decryptor_unprotected(&key, &output[..])
1015 .unwrap();
1016 let mut res = Vec::with_capacity(SIZE);
1017 decryptor.read_to_end(&mut res).unwrap();
1018 let elapsed = now.elapsed();
1019
1020 assert_eq!(res, data);
1021
1022 let elapsed_milli = elapsed.as_millis();
1023 let mb_per_s = (SIZE as f64 / 1000f64 / 1000f64 / elapsed_milli as f64) * 1000f64;
1024 println!("Decryption: {elapsed_milli} ms, MByte/s: {mb_per_s:.2?}");
1025 }
1026}