1#![allow(clippy::needless_range_loop)]
10
11use crate::BlockCipher;
72use crate::cipher::aes::Aes;
73use crate::cipher::des::{Des, TripleDes};
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub enum Algorithm {
82 Aes128,
84 Aes192,
86 Aes256,
88 Des,
91 TripleDes,
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
98pub enum Mode {
99 Ecb,
102 Cbc,
104 Ctr,
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub enum Padding {
116 None,
119 Pkcs7,
124 Iso9797M1,
131 Iso9797M2,
136 AnsiX923,
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub enum Direction {
145 Encrypt,
147 Decrypt,
149}
150
151#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153pub enum Error {
154 InvalidKeyLen,
156 InvalidIvLen,
158 InvalidPaddingForMode,
162 OutputBufferTooSmall {
166 needed: usize,
168 },
169 NotInitialized,
171 AlreadyFinalized,
174 UnpaddedInput,
177 BadPadding,
180}
181
182const MAX_BLOCK: usize = 16;
187
188enum Key {
190 None,
191 Aes(Aes),
192 Des(Des),
193 TripleDes(TripleDes),
194}
195
196impl Key {
197 fn encrypt_block(&self, blk: &mut [u8]) {
198 match self {
199 Key::None => unreachable!("encrypt_block on uninitialised Cipher"),
200 Key::Aes(c) => c.encrypt_block(blk),
201 Key::Des(c) => c.encrypt_block(blk),
202 Key::TripleDes(c) => c.encrypt_block(blk),
203 }
204 }
205
206 fn decrypt_block(&self, blk: &mut [u8]) {
207 match self {
208 Key::None => unreachable!("decrypt_block on uninitialised Cipher"),
209 Key::Aes(c) => c.decrypt_block(blk),
210 Key::Des(c) => c.decrypt_block(blk),
211 Key::TripleDes(c) => c.decrypt_block(blk),
212 }
213 }
214}
215
216pub struct Cipher {
225 algo: Algorithm,
226 mode: Mode,
227 padding: Padding,
228 block_len: usize,
229
230 key: Key,
231 direction: Option<Direction>,
232
233 iv: [u8; MAX_BLOCK],
236
237 ctr_ks: [u8; MAX_BLOCK],
240 ctr_ks_pos: usize,
241
242 buf: [u8; 2 * MAX_BLOCK],
250 buf_len: usize,
251
252 finalized: bool,
254}
255
256impl Cipher {
257 pub fn new(algo: Algorithm, mode: Mode, padding: Padding) -> Result<Self, Error> {
267 let block_len = match algo {
268 Algorithm::Aes128 | Algorithm::Aes192 | Algorithm::Aes256 => 16,
269 Algorithm::Des | Algorithm::TripleDes => 8,
270 };
271
272 if matches!(mode, Mode::Ctr) && !matches!(padding, Padding::None) {
274 return Err(Error::InvalidPaddingForMode);
275 }
276
277 Ok(Self {
278 algo,
279 mode,
280 padding,
281 block_len,
282 key: Key::None,
283 direction: None,
284 iv: [0u8; MAX_BLOCK],
285 ctr_ks: [0u8; MAX_BLOCK],
286 ctr_ks_pos: MAX_BLOCK, buf: [0u8; 2 * MAX_BLOCK],
288 buf_len: 0,
289 finalized: false,
290 })
291 }
292
293 pub fn init(&mut self, direction: Direction, key: &[u8], iv: &[u8]) -> Result<(), Error> {
308 let expected_key_len = match self.algo {
310 Algorithm::Aes128 => 16,
311 Algorithm::Aes192 => 24,
312 Algorithm::Aes256 => 32,
313 Algorithm::Des => 8,
314 Algorithm::TripleDes => 24,
315 };
316 if key.len() != expected_key_len {
317 return Err(Error::InvalidKeyLen);
318 }
319
320 match self.mode {
322 Mode::Ecb => { }
323 Mode::Cbc | Mode::Ctr => {
324 if iv.len() != self.block_len {
325 return Err(Error::InvalidIvLen);
326 }
327 }
328 }
329
330 self.key = match self.algo {
332 Algorithm::Aes128 | Algorithm::Aes192 | Algorithm::Aes256 => Key::Aes(Aes::new(key)),
333 Algorithm::Des => Key::Des(Des::new(key)),
334 Algorithm::TripleDes => Key::TripleDes(TripleDes::new(key)),
335 };
336
337 self.iv = [0u8; MAX_BLOCK];
339 if matches!(self.mode, Mode::Cbc | Mode::Ctr) {
340 self.iv[..self.block_len].copy_from_slice(iv);
341 }
342 self.ctr_ks = [0u8; MAX_BLOCK];
343 self.ctr_ks_pos = self.block_len; self.buf = [0u8; 2 * MAX_BLOCK];
345 self.buf_len = 0;
346 self.direction = Some(direction);
347 self.finalized = false;
348
349 Ok(())
350 }
351
352 pub const fn block_len(&self) -> usize {
355 self.block_len
356 }
357
358 pub const fn iv_len(&self) -> usize {
361 match self.mode {
362 Mode::Ecb => 0,
363 Mode::Cbc | Mode::Ctr => self.block_len,
364 }
365 }
366
367 pub fn update_output_size(&self, input_len: usize) -> usize {
372 match self.mode {
373 Mode::Ctr => input_len,
374 Mode::Ecb | Mode::Cbc => {
375 let total = self.buf_len + input_len;
378 if total < self.block_len {
379 0
380 } else {
381 (total / self.block_len) * self.block_len
383 }
384 }
385 }
386 }
387
388 pub const fn finalize_output_size(&self) -> usize {
391 match self.mode {
392 Mode::Ctr => 0,
393 Mode::Ecb | Mode::Cbc => self.block_len,
394 }
395 }
396
397 pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
412 let dir = self.direction.ok_or(Error::NotInitialized)?;
413 if self.finalized {
414 return Err(Error::AlreadyFinalized);
415 }
416
417 match self.mode {
418 Mode::Ctr => self.update_ctr(input, output),
419 Mode::Ecb | Mode::Cbc => self.update_block(dir, input, output),
420 }
421 }
422
423 pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, Error> {
439 let dir = self.direction.ok_or(Error::NotInitialized)?;
440 if self.finalized {
441 return Err(Error::AlreadyFinalized);
442 }
443
444 let written = match self.mode {
445 Mode::Ctr => {
446 0
448 }
449 Mode::Ecb | Mode::Cbc => match dir {
450 Direction::Encrypt => self.finalize_block_encrypt(output)?,
451 Direction::Decrypt => self.finalize_block_decrypt(output)?,
452 },
453 };
454
455 self.finalized = true;
456 Ok(written)
457 }
458
459 fn update_ctr(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
464 if output.len() < input.len() {
465 return Err(Error::OutputBufferTooSmall { needed: input.len() });
466 }
467 let bs = self.block_len;
468 for i in 0..input.len() {
469 if self.ctr_ks_pos == bs {
470 self.ctr_ks[..bs].copy_from_slice(&self.iv[..bs]);
473 self.key.encrypt_block(&mut self.ctr_ks[..bs]);
474 ctr_increment(&mut self.iv[..bs]);
475 self.ctr_ks_pos = 0;
476 }
477 output[i] = input[i] ^ self.ctr_ks[self.ctr_ks_pos];
478 self.ctr_ks_pos += 1;
479 }
480 Ok(input.len())
481 }
482
483 fn keep_back(&self, dir: Direction) -> usize {
491 if matches!(dir, Direction::Decrypt) && !matches!(self.padding, Padding::None) {
492 self.block_len
493 } else {
494 0
495 }
496 }
497
498 fn update_block(&mut self, dir: Direction, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
499 let bs = self.block_len;
500 let kb = self.keep_back(dir);
501 let mut written = 0usize;
502 let mut in_pos = 0usize;
503 let cap = 2 * bs;
504
505 while in_pos < input.len() {
506 let space = cap - self.buf_len;
508 if space > 0 {
509 let take = space.min(input.len() - in_pos);
510 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&input[in_pos..in_pos + take]);
511 self.buf_len += take;
512 in_pos += take;
513 }
514
515 while self.buf_len >= bs && self.buf_len - bs >= kb {
518 if output.len() - written < bs {
519 return Err(Error::OutputBufferTooSmall { needed: written + bs });
520 }
521 let mut blk = [0u8; MAX_BLOCK];
522 blk[..bs].copy_from_slice(&self.buf[..bs]);
523 self.process_one_block(dir, &mut blk[..bs]);
524 output[written..written + bs].copy_from_slice(&blk[..bs]);
525 written += bs;
526 self.buf.copy_within(bs..self.buf_len, 0);
528 self.buf_len -= bs;
529 }
530 }
531
532 Ok(written)
533 }
534
535 fn process_one_block(&mut self, dir: Direction, blk: &mut [u8]) {
538 let bs = self.block_len;
539 match (self.mode, dir) {
540 (Mode::Ecb, Direction::Encrypt) => {
541 self.key.encrypt_block(blk);
542 }
543 (Mode::Ecb, Direction::Decrypt) => {
544 self.key.decrypt_block(blk);
545 }
546 (Mode::Cbc, Direction::Encrypt) => {
547 for i in 0..bs {
548 blk[i] ^= self.iv[i];
549 }
550 self.key.encrypt_block(blk);
551 self.iv[..bs].copy_from_slice(&blk[..bs]);
552 }
553 (Mode::Cbc, Direction::Decrypt) => {
554 let ct_copy = {
555 let mut tmp = [0u8; MAX_BLOCK];
556 tmp[..bs].copy_from_slice(&blk[..bs]);
557 tmp
558 };
559 self.key.decrypt_block(blk);
560 for i in 0..bs {
561 blk[i] ^= self.iv[i];
562 }
563 self.iv[..bs].copy_from_slice(&ct_copy[..bs]);
564 }
565 (Mode::Ctr, _) => unreachable!("CTR uses update_ctr"),
566 }
567 }
568
569 fn finalize_block_encrypt(&mut self, output: &mut [u8]) -> Result<usize, Error> {
574 let bs = self.block_len;
575
576 match self.padding {
577 Padding::None => {
578 if self.buf_len != 0 {
579 return Err(Error::UnpaddedInput);
580 }
581 Ok(0)
582 }
583 Padding::Pkcs7 | Padding::Iso9797M2 | Padding::Iso9797M1 | Padding::AnsiX923 => {
584 if matches!(self.padding, Padding::Iso9797M1) && self.buf_len == 0 {
587 return Ok(0);
588 }
589
590 if output.len() < bs {
591 return Err(Error::OutputBufferTooSmall { needed: bs });
592 }
593 let pad_len = bs - self.buf_len; apply_padding(self.padding, &mut self.buf[..bs], self.buf_len, pad_len);
595 self.buf_len = bs;
596
597 let mut blk = [0u8; MAX_BLOCK];
598 blk[..bs].copy_from_slice(&self.buf[..bs]);
599 self.process_one_block(Direction::Encrypt, &mut blk[..bs]);
600 output[..bs].copy_from_slice(&blk[..bs]);
601 self.buf_len = 0;
602 Ok(bs)
603 }
604 }
605 }
606
607 fn finalize_block_decrypt(&mut self, output: &mut [u8]) -> Result<usize, Error> {
612 let bs = self.block_len;
613
614 match self.padding {
615 Padding::None => {
616 if self.buf_len != 0 {
617 return Err(Error::UnpaddedInput);
618 }
619 Ok(0)
620 }
621 _ => {
622 if self.buf_len != bs {
626 return Err(Error::UnpaddedInput);
627 }
628 let mut blk = [0u8; MAX_BLOCK];
629 blk[..bs].copy_from_slice(&self.buf[..bs]);
630 self.process_one_block(Direction::Decrypt, &mut blk[..bs]);
631
632 let unpadded = strip_padding(self.padding, &blk[..bs])?;
633 if output.len() < unpadded {
634 return Err(Error::OutputBufferTooSmall { needed: unpadded });
635 }
636 output[..unpadded].copy_from_slice(&blk[..unpadded]);
637 self.buf_len = 0;
638 Ok(unpadded)
639 }
640 }
641 }
642
643 pub fn update_to_vec(&mut self, input: &[u8]) -> Result<Vec<u8>, Error> {
650 let upper = self.update_output_size(input.len());
651 let mut out = vec![0u8; upper];
652 let n = self.update(input, &mut out)?;
653 out.truncate(n);
654 Ok(out)
655 }
656
657 pub fn finalize_to_vec(&mut self) -> Result<Vec<u8>, Error> {
660 let upper = self.finalize_output_size();
661 let mut out = vec![0u8; upper];
662 let n = self.finalize(&mut out)?;
663 out.truncate(n);
664 Ok(out)
665 }
666}
667
668fn apply_padding(padding: Padding, block: &mut [u8], data_len: usize, pad_len: usize) {
676 let bs = block.len();
677 debug_assert_eq!(data_len + pad_len, bs);
678 match padding {
679 Padding::None => {}
680 Padding::Pkcs7 => {
681 for b in &mut block[data_len..bs] {
682 *b = pad_len as u8;
683 }
684 }
685 Padding::Iso9797M1 => {
686 for b in &mut block[data_len..bs] {
687 *b = 0x00;
688 }
689 }
690 Padding::Iso9797M2 => {
691 block[data_len] = 0x80;
692 for b in &mut block[data_len + 1..bs] {
693 *b = 0x00;
694 }
695 }
696 Padding::AnsiX923 => {
697 for b in &mut block[data_len..bs - 1] {
698 *b = 0x00;
699 }
700 block[bs - 1] = pad_len as u8;
701 }
702 }
703}
704
705fn strip_padding(padding: Padding, block: &[u8]) -> Result<usize, Error> {
708 let bs = block.len();
709 match padding {
710 Padding::None => Ok(bs),
711 Padding::Pkcs7 => {
712 let pad_len = block[bs - 1] as usize;
713 if pad_len == 0 || pad_len > bs {
714 return Err(Error::BadPadding);
715 }
716 for &b in &block[bs - pad_len..bs] {
717 if b as usize != pad_len {
718 return Err(Error::BadPadding);
719 }
720 }
721 Ok(bs - pad_len)
722 }
723 Padding::Iso9797M1 => {
724 let mut len = bs;
729 while len > 0 && block[len - 1] == 0x00 {
730 len -= 1;
731 }
732 Ok(len)
733 }
734 Padding::Iso9797M2 => {
735 let mut i = bs;
737 while i > 0 {
738 i -= 1;
739 if block[i] == 0x80 {
740 return Ok(i);
741 }
742 if block[i] != 0x00 {
743 return Err(Error::BadPadding);
744 }
745 }
746 Err(Error::BadPadding)
747 }
748 Padding::AnsiX923 => {
749 let pad_len = block[bs - 1] as usize;
750 if pad_len == 0 || pad_len > bs {
751 return Err(Error::BadPadding);
752 }
753 for &b in &block[bs - pad_len..bs - 1] {
754 if b != 0x00 {
755 return Err(Error::BadPadding);
756 }
757 }
758 Ok(bs - pad_len)
759 }
760 }
761}
762
763fn ctr_increment(counter: &mut [u8]) {
770 let n = counter.len();
771 let lo = n.saturating_sub(8);
772 for i in (lo..n).rev() {
773 let (v, carry) = counter[i].overflowing_add(1);
774 counter[i] = v;
775 if !carry {
776 return;
777 }
778 }
779}
780
781#[cfg(test)]
786mod tests {
787 use super::*;
788 use crate::BlockCipher;
789 use crate::cipher::aes::Aes128;
790 use crate::cipher::modes::{cbc_decrypt, cbc_encrypt, ctr_encrypt, ecb_encrypt};
791
792 fn hex(s: &str) -> Vec<u8> {
793 (0..s.len())
794 .step_by(2)
795 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
796 .collect()
797 }
798
799 #[test]
802 fn ecb_aes128_no_padding_round_trip() {
803 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
804 let pt = hex("6bc1bee22e409f96e93d7e117393172a"); let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::None).unwrap();
807 enc.init(Direction::Encrypt, &key, &[]).unwrap();
808 let ct = {
809 let mut out = vec![0u8; 32];
810 let n = enc.update(&pt, &mut out).unwrap();
811 let m = enc.finalize(&mut out[n..]).unwrap();
812 out.truncate(n + m);
813 out
814 };
815
816 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::None).unwrap();
817 dec.init(Direction::Decrypt, &key, &[]).unwrap();
818 let mut got = vec![0u8; 32];
819 let n = dec.update(&ct, &mut got).unwrap();
820 let m = dec.finalize(&mut got[n..]).unwrap();
821 got.truncate(n + m);
822 assert_eq!(got, pt);
823 }
824
825 #[test]
826 fn ecb_aes128_pkcs7_unaligned() {
827 let key = [0x42u8; 16];
828 let pt: Vec<u8> = (0u8..30).collect(); let mut padded = pt.clone();
832 let pad = 16 - (padded.len() % 16);
833 padded.extend(std::iter::repeat_n(pad as u8, pad));
834 let cipher_ref = Aes128::new(&key);
835 ecb_encrypt(&cipher_ref, &mut padded);
836 let ct_ref = padded;
837
838 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::Pkcs7).unwrap();
840 enc.init(Direction::Encrypt, &key, &[]).unwrap();
841 let ct = {
842 let mut out = vec![0u8; 64];
843 let n = enc.update(&pt, &mut out).unwrap();
844 let m = enc.finalize(&mut out[n..]).unwrap();
845 out.truncate(n + m);
846 out
847 };
848 assert_eq!(ct, ct_ref, "Cipher PKCS#7 ECB encrypt mismatch");
849
850 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::Pkcs7).unwrap();
851 dec.init(Direction::Decrypt, &key, &[]).unwrap();
852 let pt_back = {
853 let mut out = vec![0u8; 64];
854 let n = dec.update(&ct, &mut out).unwrap();
855 let m = dec.finalize(&mut out[n..]).unwrap();
856 out.truncate(n + m);
857 out
858 };
859 assert_eq!(pt_back, pt);
860 }
861
862 #[test]
865 fn cbc_aes128_pkcs7_matches_modes_helper() {
866 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
867 let iv = hex("000102030405060708090a0b0c0d0e0f");
868 let pt: Vec<u8> = (0u8..37).collect(); let mut padded = pt.clone();
872 let pad = 16 - (padded.len() % 16);
873 padded.extend(std::iter::repeat_n(pad as u8, pad));
874 let cipher_ref = Aes128::new(&key);
875 cbc_encrypt(&cipher_ref, &iv, &mut padded);
876 let ct_ref = padded;
877
878 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
879 enc.init(Direction::Encrypt, &key, &iv).unwrap();
880 let mut ct = vec![0u8; 64];
881 let mut w = enc.update(&pt[..10], &mut ct).unwrap();
883 w += enc.update(&pt[10..], &mut ct[w..]).unwrap();
884 w += enc.finalize(&mut ct[w..]).unwrap();
885 ct.truncate(w);
886 assert_eq!(ct, ct_ref, "Cipher CBC PKCS#7 encrypt mismatch");
887
888 let mut ref_pt = ct.clone();
890 cbc_decrypt(&cipher_ref, &iv, &mut ref_pt);
891 let pad = *ref_pt.last().unwrap() as usize;
893 ref_pt.truncate(ref_pt.len() - pad);
894 assert_eq!(ref_pt, pt);
895
896 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
897 dec.init(Direction::Decrypt, &key, &iv).unwrap();
898 let mut got = vec![0u8; 64];
899 let mut n = dec.update(&ct[..7], &mut got).unwrap();
900 n += dec.update(&ct[7..], &mut got[n..]).unwrap();
901 n += dec.finalize(&mut got[n..]).unwrap();
902 got.truncate(n);
903 assert_eq!(got, pt);
904 }
905
906 #[test]
907 fn cbc_aes128_none_padding_aligned() {
908 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
909 let iv = hex("000102030405060708090a0b0c0d0e0f");
910 let pt = hex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
911
912 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::None).unwrap();
913 enc.init(Direction::Encrypt, &key, &iv).unwrap();
914 let mut ct = vec![0u8; 64];
915 let mut n = enc.update(&pt, &mut ct).unwrap();
916 n += enc.finalize(&mut ct[n..]).unwrap();
917 ct.truncate(n);
918
919 let cipher_ref = Aes128::new(&key);
921 let mut ct_ref = pt.clone();
922 cbc_encrypt(&cipher_ref, &iv, &mut ct_ref);
923 assert_eq!(ct, ct_ref);
924 }
925
926 #[test]
927 fn cbc_aes128_none_padding_unaligned_errors() {
928 let key = [0u8; 16];
929 let iv = [0u8; 16];
930 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::None).unwrap();
931 enc.init(Direction::Encrypt, &key, &iv).unwrap();
932 let mut out = vec![0u8; 64];
933 enc.update(&[0u8; 13], &mut out).unwrap();
934 assert_eq!(enc.finalize(&mut out), Err(Error::UnpaddedInput));
935 }
936
937 #[test]
940 fn ctr_aes128_streaming_matches_one_shot() {
941 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
942 let nonce = hex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); let pt = hex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51\
944 30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
945
946 let cipher_ref = Aes128::new(&key);
951 let mut ct_ref = pt.clone();
952 let nonce8 = &nonce[..8];
957 ctr_encrypt(&cipher_ref, nonce8, &mut ct_ref);
958
959 let mut iv = [0u8; 16];
961 iv[..8].copy_from_slice(nonce8);
962 iv[15] = 1;
963
964 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::None).unwrap();
965 enc.init(Direction::Encrypt, &key, &iv).unwrap();
966 let mut ct = vec![0u8; pt.len()];
967 let mut w = 0;
969 for chunk in pt.chunks(7) {
970 w += enc.update(chunk, &mut ct[w..]).unwrap();
971 }
972 w += enc.finalize(&mut ct[w..]).unwrap();
973 assert_eq!(w, pt.len());
974 assert_eq!(ct, ct_ref, "Cipher CTR streaming mismatch");
975
976 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::None).unwrap();
978 dec.init(Direction::Decrypt, &key, &iv).unwrap();
979 let mut pt_back = vec![0u8; ct.len()];
980 let mut w = 0;
981 for chunk in ct.chunks(11) {
982 w += dec.update(chunk, &mut pt_back[w..]).unwrap();
983 }
984 w += dec.finalize(&mut pt_back[w..]).unwrap();
985 assert_eq!(w, ct.len());
986 assert_eq!(pt_back, pt);
987 }
988
989 fn pad_round_trip(padding: Padding, msg_len: usize) {
992 let key = [0x33u8; 16];
993 let iv = [0x77u8; 16];
994 let pt: Vec<u8> = (0..msg_len).map(|i| (i as u8).wrapping_mul(7)).collect();
995
996 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
997 enc.init(Direction::Encrypt, &key, &iv).unwrap();
998 let mut ct = vec![0u8; pt.len() + 16];
999 let mut n = enc.update(&pt, &mut ct).unwrap();
1000 n += enc.finalize(&mut ct[n..]).unwrap();
1001 ct.truncate(n);
1002
1003 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
1004 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1005 let mut got = vec![0u8; ct.len() + 16];
1006 let mut n = dec.update(&ct, &mut got).unwrap();
1007 n += dec.finalize(&mut got[n..]).unwrap();
1008 got.truncate(n);
1009 assert_eq!(got, pt, "round-trip {:?} len={}", padding, msg_len);
1010 }
1011
1012 #[test]
1013 fn pkcs7_round_trips() {
1014 for len in &[0, 1, 15, 16, 17, 31, 32, 33, 100] {
1015 pad_round_trip(Padding::Pkcs7, *len);
1016 }
1017 }
1018
1019 #[test]
1020 fn iso9797_m2_round_trips() {
1021 for len in &[0, 1, 15, 16, 17, 31, 32, 33, 100] {
1022 pad_round_trip(Padding::Iso9797M2, *len);
1023 }
1024 }
1025
1026 #[test]
1027 fn ansix923_round_trips() {
1028 for len in &[1, 15, 16, 17, 31, 32, 33, 100] {
1029 pad_round_trip(Padding::AnsiX923, *len);
1030 }
1031 }
1032
1033 #[test]
1034 fn iso9797_m1_round_trips_when_no_trailing_zero() {
1035 let padding = Padding::Iso9797M1;
1038 let key = [0u8; 16];
1039 let iv = [0u8; 16];
1040
1041 for len in &[1usize, 5, 15, 17, 30] {
1042 let pt: Vec<u8> = (0..*len).map(|i| (i as u8) | 1).collect();
1043 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
1044 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1045 let mut ct = vec![0u8; pt.len() + 16];
1046 let mut n = enc.update(&pt, &mut ct).unwrap();
1047 n += enc.finalize(&mut ct[n..]).unwrap();
1048 ct.truncate(n);
1049
1050 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
1051 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1052 let mut got = vec![0u8; ct.len() + 16];
1053 let mut n = dec.update(&ct, &mut got).unwrap();
1054 n += dec.finalize(&mut got[n..]).unwrap();
1055 got.truncate(n);
1056 assert_eq!(got, pt);
1057 }
1058 }
1059
1060 #[test]
1063 fn invalid_key_len_rejected() {
1064 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1065 assert_eq!(
1066 c.init(Direction::Encrypt, &[0u8; 17], &[0u8; 16]),
1067 Err(Error::InvalidKeyLen)
1068 );
1069 }
1070
1071 #[test]
1072 fn invalid_iv_len_rejected() {
1073 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1074 assert_eq!(
1075 c.init(Direction::Encrypt, &[0u8; 16], &[0u8; 8]),
1076 Err(Error::InvalidIvLen)
1077 );
1078 }
1079
1080 #[test]
1081 fn ctr_with_padding_rejected() {
1082 assert_eq!(
1083 Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::Pkcs7).err(),
1084 Some(Error::InvalidPaddingForMode)
1085 );
1086 }
1087
1088 #[test]
1089 fn output_too_small_reported() {
1090 let key = [0u8; 16];
1091 let iv = [0u8; 16];
1092 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1093 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1094 let mut tiny = [0u8; 4];
1095 let err = enc.update(&[0u8; 32], &mut tiny);
1096 assert!(matches!(err, Err(Error::OutputBufferTooSmall { .. })));
1097 }
1098
1099 #[test]
1100 fn bad_padding_detected() {
1101 let key = [1u8; 16];
1103 let iv = [2u8; 16];
1104 let pt = b"hello, world! Some content here.";
1105
1106 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1107 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1108 let mut ct = vec![0u8; 64];
1109 let mut n = enc.update(pt, &mut ct).unwrap();
1110 n += enc.finalize(&mut ct[n..]).unwrap();
1111 ct.truncate(n);
1112 let last = ct.len() - 1;
1113 ct[last] ^= 0xFF;
1114
1115 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1116 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1117 let mut out = vec![0u8; 64];
1118 let n = dec.update(&ct, &mut out).unwrap();
1119 let r = dec.finalize(&mut out[n..]);
1120 assert_eq!(r, Err(Error::BadPadding));
1121 }
1122
1123 #[test]
1126 fn tripledes_cbc_pkcs7_round_trip() {
1127 let key = [0x11u8; 24];
1128 let iv = [0x22u8; 8];
1129 let pt: Vec<u8> = (0u8..23).collect();
1130
1131 let mut enc = Cipher::new(Algorithm::TripleDes, Mode::Cbc, Padding::Pkcs7).unwrap();
1132 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1133 let mut ct = vec![0u8; 64];
1134 let mut n = enc.update(&pt, &mut ct).unwrap();
1135 n += enc.finalize(&mut ct[n..]).unwrap();
1136 ct.truncate(n);
1137 assert_eq!(ct.len() % 8, 0);
1138
1139 let mut dec = Cipher::new(Algorithm::TripleDes, Mode::Cbc, Padding::Pkcs7).unwrap();
1140 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1141 let mut got = vec![0u8; 64];
1142 let mut n = dec.update(&ct, &mut got).unwrap();
1143 n += dec.finalize(&mut got[n..]).unwrap();
1144 got.truncate(n);
1145 assert_eq!(got, pt);
1146 }
1147
1148 #[test]
1149 fn reuse_after_init() {
1150 let key = [9u8; 16];
1151 let iv = [8u8; 16];
1152 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1153
1154 for &msg in &[b"first message".as_slice(), b"second", b"a third one!"] {
1155 c.init(Direction::Encrypt, &key, &iv).unwrap();
1156 let ct = {
1157 let mut out = vec![0u8; 64];
1158 let mut n = c.update(msg, &mut out).unwrap();
1159 n += c.finalize(&mut out[n..]).unwrap();
1160 out.truncate(n);
1161 out
1162 };
1163 c.init(Direction::Decrypt, &key, &iv).unwrap();
1164 let pt = {
1165 let mut out = vec![0u8; 64];
1166 let mut n = c.update(&ct, &mut out).unwrap();
1167 n += c.finalize(&mut out[n..]).unwrap();
1168 out.truncate(n);
1169 out
1170 };
1171 assert_eq!(pt, msg);
1172 }
1173 }
1174}