1use crate::BlockCipher;
62use crate::cipher::aes::Aes;
63use crate::cipher::des::{Des, TripleDes};
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71pub enum Algorithm {
72 Aes128,
74 Aes192,
76 Aes256,
78 Des,
81 TripleDes,
84}
85
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88pub enum Mode {
89 Ecb,
92 Cbc,
94 Ctr,
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
105pub enum Padding {
106 None,
109 Pkcs7,
114 Iso9797M1,
121 Iso9797M2,
126 AnsiX923,
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq)]
134pub enum Direction {
135 Encrypt,
137 Decrypt,
139}
140
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143pub enum Error {
144 InvalidKeyLen,
146 InvalidIvLen,
148 InvalidPaddingForMode,
152 OutputBufferTooSmall {
156 needed: usize,
158 },
159 NotInitialized,
161 AlreadyFinalized,
164 UnpaddedInput,
167 BadPadding,
170}
171
172const MAX_BLOCK: usize = 16;
177
178enum Key {
180 None,
181 Aes(Aes),
182 Des(Des),
183 TripleDes(TripleDes),
184}
185
186impl Key {
187 fn encrypt_block(&self, blk: &mut [u8]) {
188 match self {
189 Key::None => unreachable!("encrypt_block on uninitialised Cipher"),
190 Key::Aes(c) => c.encrypt_block(blk),
191 Key::Des(c) => c.encrypt_block(blk),
192 Key::TripleDes(c) => c.encrypt_block(blk),
193 }
194 }
195
196 fn decrypt_block(&self, blk: &mut [u8]) {
197 match self {
198 Key::None => unreachable!("decrypt_block on uninitialised Cipher"),
199 Key::Aes(c) => c.decrypt_block(blk),
200 Key::Des(c) => c.decrypt_block(blk),
201 Key::TripleDes(c) => c.decrypt_block(blk),
202 }
203 }
204}
205
206pub struct Cipher {
215 algo: Algorithm,
216 mode: Mode,
217 padding: Padding,
218 block_len: usize,
219
220 key: Key,
221 direction: Option<Direction>,
222
223 iv: [u8; MAX_BLOCK],
226
227 ctr_ks: [u8; MAX_BLOCK],
230 ctr_ks_pos: usize,
231
232 buf: [u8; 2 * MAX_BLOCK],
240 buf_len: usize,
241
242 finalized: bool,
244}
245
246impl Cipher {
247 pub fn new(algo: Algorithm, mode: Mode, padding: Padding) -> Result<Self, Error> {
257 let block_len = match algo {
258 Algorithm::Aes128 | Algorithm::Aes192 | Algorithm::Aes256 => 16,
259 Algorithm::Des | Algorithm::TripleDes => 8,
260 };
261
262 if matches!(mode, Mode::Ctr) && !matches!(padding, Padding::None) {
264 return Err(Error::InvalidPaddingForMode);
265 }
266
267 Ok(Self {
268 algo,
269 mode,
270 padding,
271 block_len,
272 key: Key::None,
273 direction: None,
274 iv: [0u8; MAX_BLOCK],
275 ctr_ks: [0u8; MAX_BLOCK],
276 ctr_ks_pos: MAX_BLOCK, buf: [0u8; 2 * MAX_BLOCK],
278 buf_len: 0,
279 finalized: false,
280 })
281 }
282
283 pub fn init(&mut self, direction: Direction, key: &[u8], iv: &[u8]) -> Result<(), Error> {
298 let expected_key_len = match self.algo {
300 Algorithm::Aes128 => 16,
301 Algorithm::Aes192 => 24,
302 Algorithm::Aes256 => 32,
303 Algorithm::Des => 8,
304 Algorithm::TripleDes => 24,
305 };
306 if key.len() != expected_key_len {
307 return Err(Error::InvalidKeyLen);
308 }
309
310 match self.mode {
312 Mode::Ecb => { }
313 Mode::Cbc | Mode::Ctr => {
314 if iv.len() != self.block_len {
315 return Err(Error::InvalidIvLen);
316 }
317 }
318 }
319
320 self.key = match self.algo {
322 Algorithm::Aes128 | Algorithm::Aes192 | Algorithm::Aes256 => Key::Aes(Aes::new(key)),
323 Algorithm::Des => Key::Des(Des::new(key)),
324 Algorithm::TripleDes => Key::TripleDes(TripleDes::new(key)),
325 };
326
327 self.iv = [0u8; MAX_BLOCK];
329 if matches!(self.mode, Mode::Cbc | Mode::Ctr) {
330 self.iv[..self.block_len].copy_from_slice(iv);
331 }
332 self.ctr_ks = [0u8; MAX_BLOCK];
333 self.ctr_ks_pos = self.block_len; self.buf = [0u8; 2 * MAX_BLOCK];
335 self.buf_len = 0;
336 self.direction = Some(direction);
337 self.finalized = false;
338
339 Ok(())
340 }
341
342 pub const fn block_len(&self) -> usize {
345 self.block_len
346 }
347
348 pub const fn iv_len(&self) -> usize {
351 match self.mode {
352 Mode::Ecb => 0,
353 Mode::Cbc | Mode::Ctr => self.block_len,
354 }
355 }
356
357 pub fn update_output_size(&self, input_len: usize) -> usize {
362 match self.mode {
363 Mode::Ctr => input_len,
364 Mode::Ecb | Mode::Cbc => {
365 let total = self.buf_len + input_len;
368 if total < self.block_len {
369 0
370 } else {
371 (total / self.block_len) * self.block_len
373 }
374 }
375 }
376 }
377
378 pub const fn finalize_output_size(&self) -> usize {
381 match self.mode {
382 Mode::Ctr => 0,
383 Mode::Ecb | Mode::Cbc => self.block_len,
384 }
385 }
386
387 pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
402 let dir = self.direction.ok_or(Error::NotInitialized)?;
403 if self.finalized {
404 return Err(Error::AlreadyFinalized);
405 }
406
407 match self.mode {
408 Mode::Ctr => self.update_ctr(input, output),
409 Mode::Ecb | Mode::Cbc => self.update_block(dir, input, output),
410 }
411 }
412
413 pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, Error> {
429 let dir = self.direction.ok_or(Error::NotInitialized)?;
430 if self.finalized {
431 return Err(Error::AlreadyFinalized);
432 }
433
434 let written = match self.mode {
435 Mode::Ctr => {
436 0
438 }
439 Mode::Ecb | Mode::Cbc => match dir {
440 Direction::Encrypt => self.finalize_block_encrypt(output)?,
441 Direction::Decrypt => self.finalize_block_decrypt(output)?,
442 },
443 };
444
445 self.finalized = true;
446 Ok(written)
447 }
448
449 fn update_ctr(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
454 if output.len() < input.len() {
455 return Err(Error::OutputBufferTooSmall { needed: input.len() });
456 }
457 let bs = self.block_len;
458 for i in 0..input.len() {
459 if self.ctr_ks_pos == bs {
460 self.ctr_ks[..bs].copy_from_slice(&self.iv[..bs]);
463 self.key.encrypt_block(&mut self.ctr_ks[..bs]);
464 ctr_increment(&mut self.iv[..bs]);
465 self.ctr_ks_pos = 0;
466 }
467 output[i] = input[i] ^ self.ctr_ks[self.ctr_ks_pos];
468 self.ctr_ks_pos += 1;
469 }
470 Ok(input.len())
471 }
472
473 fn keep_back(&self, dir: Direction) -> usize {
481 if matches!(dir, Direction::Decrypt) && !matches!(self.padding, Padding::None) {
482 self.block_len
483 } else {
484 0
485 }
486 }
487
488 fn update_block(&mut self, dir: Direction, input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
489 let bs = self.block_len;
490 let kb = self.keep_back(dir);
491 let mut written = 0usize;
492 let mut in_pos = 0usize;
493 let cap = 2 * bs;
494
495 while in_pos < input.len() {
496 let space = cap - self.buf_len;
498 if space > 0 {
499 let take = space.min(input.len() - in_pos);
500 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&input[in_pos..in_pos + take]);
501 self.buf_len += take;
502 in_pos += take;
503 }
504
505 while self.buf_len >= bs && self.buf_len - bs >= kb {
508 if output.len() - written < bs {
509 return Err(Error::OutputBufferTooSmall { needed: written + bs });
510 }
511 let mut blk = [0u8; MAX_BLOCK];
512 blk[..bs].copy_from_slice(&self.buf[..bs]);
513 self.process_one_block(dir, &mut blk[..bs]);
514 output[written..written + bs].copy_from_slice(&blk[..bs]);
515 written += bs;
516 self.buf.copy_within(bs..self.buf_len, 0);
518 self.buf_len -= bs;
519 }
520 }
521
522 Ok(written)
523 }
524
525 fn process_one_block(&mut self, dir: Direction, blk: &mut [u8]) {
528 let bs = self.block_len;
529 match (self.mode, dir) {
530 (Mode::Ecb, Direction::Encrypt) => {
531 self.key.encrypt_block(blk);
532 }
533 (Mode::Ecb, Direction::Decrypt) => {
534 self.key.decrypt_block(blk);
535 }
536 (Mode::Cbc, Direction::Encrypt) => {
537 for i in 0..bs {
538 blk[i] ^= self.iv[i];
539 }
540 self.key.encrypt_block(blk);
541 self.iv[..bs].copy_from_slice(&blk[..bs]);
542 }
543 (Mode::Cbc, Direction::Decrypt) => {
544 let ct_copy = {
545 let mut tmp = [0u8; MAX_BLOCK];
546 tmp[..bs].copy_from_slice(&blk[..bs]);
547 tmp
548 };
549 self.key.decrypt_block(blk);
550 for i in 0..bs {
551 blk[i] ^= self.iv[i];
552 }
553 self.iv[..bs].copy_from_slice(&ct_copy[..bs]);
554 }
555 (Mode::Ctr, _) => unreachable!("CTR uses update_ctr"),
556 }
557 }
558
559 fn finalize_block_encrypt(&mut self, output: &mut [u8]) -> Result<usize, Error> {
564 let bs = self.block_len;
565
566 match self.padding {
567 Padding::None => {
568 if self.buf_len != 0 {
569 return Err(Error::UnpaddedInput);
570 }
571 Ok(0)
572 }
573 Padding::Pkcs7 | Padding::Iso9797M2 | Padding::Iso9797M1 | Padding::AnsiX923 => {
574 if matches!(self.padding, Padding::Iso9797M1) && self.buf_len == 0 {
577 return Ok(0);
578 }
579
580 if output.len() < bs {
581 return Err(Error::OutputBufferTooSmall { needed: bs });
582 }
583 let pad_len = bs - self.buf_len; apply_padding(self.padding, &mut self.buf[..bs], self.buf_len, pad_len);
585 self.buf_len = bs;
586
587 let mut blk = [0u8; MAX_BLOCK];
588 blk[..bs].copy_from_slice(&self.buf[..bs]);
589 self.process_one_block(Direction::Encrypt, &mut blk[..bs]);
590 output[..bs].copy_from_slice(&blk[..bs]);
591 self.buf_len = 0;
592 Ok(bs)
593 }
594 }
595 }
596
597 fn finalize_block_decrypt(&mut self, output: &mut [u8]) -> Result<usize, Error> {
602 let bs = self.block_len;
603
604 match self.padding {
605 Padding::None => {
606 if self.buf_len != 0 {
607 return Err(Error::UnpaddedInput);
608 }
609 Ok(0)
610 }
611 _ => {
612 if self.buf_len != bs {
616 return Err(Error::UnpaddedInput);
617 }
618 let mut blk = [0u8; MAX_BLOCK];
619 blk[..bs].copy_from_slice(&self.buf[..bs]);
620 self.process_one_block(Direction::Decrypt, &mut blk[..bs]);
621
622 let unpadded = strip_padding(self.padding, &blk[..bs])?;
623 if output.len() < unpadded {
624 return Err(Error::OutputBufferTooSmall { needed: unpadded });
625 }
626 output[..unpadded].copy_from_slice(&blk[..unpadded]);
627 self.buf_len = 0;
628 Ok(unpadded)
629 }
630 }
631 }
632
633 pub fn update_to_vec(&mut self, input: &[u8]) -> Result<Vec<u8>, Error> {
640 let upper = self.update_output_size(input.len());
641 let mut out = vec![0u8; upper];
642 let n = self.update(input, &mut out)?;
643 out.truncate(n);
644 Ok(out)
645 }
646
647 pub fn finalize_to_vec(&mut self) -> Result<Vec<u8>, Error> {
650 let upper = self.finalize_output_size();
651 let mut out = vec![0u8; upper];
652 let n = self.finalize(&mut out)?;
653 out.truncate(n);
654 Ok(out)
655 }
656}
657
658fn apply_padding(padding: Padding, block: &mut [u8], data_len: usize, pad_len: usize) {
666 let bs = block.len();
667 debug_assert_eq!(data_len + pad_len, bs);
668 match padding {
669 Padding::None => {}
670 Padding::Pkcs7 => {
671 for b in &mut block[data_len..bs] {
672 *b = pad_len as u8;
673 }
674 }
675 Padding::Iso9797M1 => {
676 for b in &mut block[data_len..bs] {
677 *b = 0x00;
678 }
679 }
680 Padding::Iso9797M2 => {
681 block[data_len] = 0x80;
682 for b in &mut block[data_len + 1..bs] {
683 *b = 0x00;
684 }
685 }
686 Padding::AnsiX923 => {
687 for b in &mut block[data_len..bs - 1] {
688 *b = 0x00;
689 }
690 block[bs - 1] = pad_len as u8;
691 }
692 }
693}
694
695fn strip_padding(padding: Padding, block: &[u8]) -> Result<usize, Error> {
698 let bs = block.len();
699 match padding {
700 Padding::None => Ok(bs),
701 Padding::Pkcs7 => {
702 let pad_len = block[bs - 1] as usize;
703 if pad_len == 0 || pad_len > bs {
704 return Err(Error::BadPadding);
705 }
706 for &b in &block[bs - pad_len..bs] {
707 if b as usize != pad_len {
708 return Err(Error::BadPadding);
709 }
710 }
711 Ok(bs - pad_len)
712 }
713 Padding::Iso9797M1 => {
714 let mut len = bs;
719 while len > 0 && block[len - 1] == 0x00 {
720 len -= 1;
721 }
722 Ok(len)
723 }
724 Padding::Iso9797M2 => {
725 let mut i = bs;
727 while i > 0 {
728 i -= 1;
729 if block[i] == 0x80 {
730 return Ok(i);
731 }
732 if block[i] != 0x00 {
733 return Err(Error::BadPadding);
734 }
735 }
736 Err(Error::BadPadding)
737 }
738 Padding::AnsiX923 => {
739 let pad_len = block[bs - 1] as usize;
740 if pad_len == 0 || pad_len > bs {
741 return Err(Error::BadPadding);
742 }
743 for &b in &block[bs - pad_len..bs - 1] {
744 if b != 0x00 {
745 return Err(Error::BadPadding);
746 }
747 }
748 Ok(bs - pad_len)
749 }
750 }
751}
752
753fn ctr_increment(counter: &mut [u8]) {
760 let n = counter.len();
761 let lo = n.saturating_sub(8);
762 for i in (lo..n).rev() {
763 let (v, carry) = counter[i].overflowing_add(1);
764 counter[i] = v;
765 if !carry {
766 return;
767 }
768 }
769}
770
771#[cfg(test)]
776mod tests {
777 use super::*;
778 use crate::BlockCipher;
779 use crate::cipher::aes::Aes128;
780 use crate::cipher::modes::{cbc_decrypt, cbc_encrypt, ctr_encrypt, ecb_encrypt};
781
782 fn hex(s: &str) -> Vec<u8> {
783 (0..s.len())
784 .step_by(2)
785 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
786 .collect()
787 }
788
789 #[test]
792 fn ecb_aes128_no_padding_round_trip() {
793 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
794 let pt = hex("6bc1bee22e409f96e93d7e117393172a"); let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::None).unwrap();
797 enc.init(Direction::Encrypt, &key, &[]).unwrap();
798 let ct = {
799 let mut out = vec![0u8; 32];
800 let n = enc.update(&pt, &mut out).unwrap();
801 let m = enc.finalize(&mut out[n..]).unwrap();
802 out.truncate(n + m);
803 out
804 };
805
806 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::None).unwrap();
807 dec.init(Direction::Decrypt, &key, &[]).unwrap();
808 let mut got = vec![0u8; 32];
809 let n = dec.update(&ct, &mut got).unwrap();
810 let m = dec.finalize(&mut got[n..]).unwrap();
811 got.truncate(n + m);
812 assert_eq!(got, pt);
813 }
814
815 #[test]
816 fn ecb_aes128_pkcs7_unaligned() {
817 let key = [0x42u8; 16];
818 let pt: Vec<u8> = (0u8..30).collect(); let mut padded = pt.clone();
822 let pad = 16 - (padded.len() % 16);
823 padded.extend(std::iter::repeat(pad as u8).take(pad));
824 let cipher_ref = Aes128::new(&key);
825 ecb_encrypt(&cipher_ref, &mut padded);
826 let ct_ref = padded;
827
828 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::Pkcs7).unwrap();
830 enc.init(Direction::Encrypt, &key, &[]).unwrap();
831 let ct = {
832 let mut out = vec![0u8; 64];
833 let n = enc.update(&pt, &mut out).unwrap();
834 let m = enc.finalize(&mut out[n..]).unwrap();
835 out.truncate(n + m);
836 out
837 };
838 assert_eq!(ct, ct_ref, "Cipher PKCS#7 ECB encrypt mismatch");
839
840 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ecb, Padding::Pkcs7).unwrap();
841 dec.init(Direction::Decrypt, &key, &[]).unwrap();
842 let pt_back = {
843 let mut out = vec![0u8; 64];
844 let n = dec.update(&ct, &mut out).unwrap();
845 let m = dec.finalize(&mut out[n..]).unwrap();
846 out.truncate(n + m);
847 out
848 };
849 assert_eq!(pt_back, pt);
850 }
851
852 #[test]
855 fn cbc_aes128_pkcs7_matches_modes_helper() {
856 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
857 let iv = hex("000102030405060708090a0b0c0d0e0f");
858 let pt: Vec<u8> = (0u8..37).collect(); let mut padded = pt.clone();
862 let pad = 16 - (padded.len() % 16);
863 padded.extend(std::iter::repeat(pad as u8).take(pad));
864 let cipher_ref = Aes128::new(&key);
865 cbc_encrypt(&cipher_ref, &iv, &mut padded);
866 let ct_ref = padded;
867
868 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
869 enc.init(Direction::Encrypt, &key, &iv).unwrap();
870 let mut ct = vec![0u8; 64];
871 let mut w = enc.update(&pt[..10], &mut ct).unwrap();
873 w += enc.update(&pt[10..], &mut ct[w..]).unwrap();
874 w += enc.finalize(&mut ct[w..]).unwrap();
875 ct.truncate(w);
876 assert_eq!(ct, ct_ref, "Cipher CBC PKCS#7 encrypt mismatch");
877
878 let mut ref_pt = ct.clone();
880 cbc_decrypt(&cipher_ref, &iv, &mut ref_pt);
881 let pad = *ref_pt.last().unwrap() as usize;
883 ref_pt.truncate(ref_pt.len() - pad);
884 assert_eq!(ref_pt, pt);
885
886 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
887 dec.init(Direction::Decrypt, &key, &iv).unwrap();
888 let mut got = vec![0u8; 64];
889 let mut n = dec.update(&ct[..7], &mut got).unwrap();
890 n += dec.update(&ct[7..], &mut got[n..]).unwrap();
891 n += dec.finalize(&mut got[n..]).unwrap();
892 got.truncate(n);
893 assert_eq!(got, pt);
894 }
895
896 #[test]
897 fn cbc_aes128_none_padding_aligned() {
898 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
899 let iv = hex("000102030405060708090a0b0c0d0e0f");
900 let pt = hex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
901
902 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::None).unwrap();
903 enc.init(Direction::Encrypt, &key, &iv).unwrap();
904 let mut ct = vec![0u8; 64];
905 let mut n = enc.update(&pt, &mut ct).unwrap();
906 n += enc.finalize(&mut ct[n..]).unwrap();
907 ct.truncate(n);
908
909 let cipher_ref = Aes128::new(&key);
911 let mut ct_ref = pt.clone();
912 cbc_encrypt(&cipher_ref, &iv, &mut ct_ref);
913 assert_eq!(ct, ct_ref);
914 }
915
916 #[test]
917 fn cbc_aes128_none_padding_unaligned_errors() {
918 let key = [0u8; 16];
919 let iv = [0u8; 16];
920 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::None).unwrap();
921 enc.init(Direction::Encrypt, &key, &iv).unwrap();
922 let mut out = vec![0u8; 64];
923 enc.update(&[0u8; 13], &mut out).unwrap();
924 assert_eq!(enc.finalize(&mut out), Err(Error::UnpaddedInput));
925 }
926
927 #[test]
930 fn ctr_aes128_streaming_matches_one_shot() {
931 let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
932 let nonce = hex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); let pt = hex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51\
934 30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
935
936 let cipher_ref = Aes128::new(&key);
941 let mut ct_ref = pt.clone();
942 let nonce8 = &nonce[..8];
947 ctr_encrypt(&cipher_ref, nonce8, &mut ct_ref);
948
949 let mut iv = [0u8; 16];
951 iv[..8].copy_from_slice(nonce8);
952 iv[15] = 1;
953
954 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::None).unwrap();
955 enc.init(Direction::Encrypt, &key, &iv).unwrap();
956 let mut ct = vec![0u8; pt.len()];
957 let mut w = 0;
959 for chunk in pt.chunks(7) {
960 w += enc.update(chunk, &mut ct[w..]).unwrap();
961 }
962 w += enc.finalize(&mut ct[w..]).unwrap();
963 assert_eq!(w, pt.len());
964 assert_eq!(ct, ct_ref, "Cipher CTR streaming mismatch");
965
966 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::None).unwrap();
968 dec.init(Direction::Decrypt, &key, &iv).unwrap();
969 let mut pt_back = vec![0u8; ct.len()];
970 let mut w = 0;
971 for chunk in ct.chunks(11) {
972 w += dec.update(chunk, &mut pt_back[w..]).unwrap();
973 }
974 w += dec.finalize(&mut pt_back[w..]).unwrap();
975 assert_eq!(w, ct.len());
976 assert_eq!(pt_back, pt);
977 }
978
979 fn pad_round_trip(padding: Padding, msg_len: usize) {
982 let key = [0x33u8; 16];
983 let iv = [0x77u8; 16];
984 let pt: Vec<u8> = (0..msg_len).map(|i| (i as u8).wrapping_mul(7)).collect();
985
986 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
987 enc.init(Direction::Encrypt, &key, &iv).unwrap();
988 let mut ct = vec![0u8; pt.len() + 16];
989 let mut n = enc.update(&pt, &mut ct).unwrap();
990 n += enc.finalize(&mut ct[n..]).unwrap();
991 ct.truncate(n);
992
993 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
994 dec.init(Direction::Decrypt, &key, &iv).unwrap();
995 let mut got = vec![0u8; ct.len() + 16];
996 let mut n = dec.update(&ct, &mut got).unwrap();
997 n += dec.finalize(&mut got[n..]).unwrap();
998 got.truncate(n);
999 assert_eq!(got, pt, "round-trip {:?} len={}", padding, msg_len);
1000 }
1001
1002 #[test]
1003 fn pkcs7_round_trips() {
1004 for len in &[0, 1, 15, 16, 17, 31, 32, 33, 100] {
1005 pad_round_trip(Padding::Pkcs7, *len);
1006 }
1007 }
1008
1009 #[test]
1010 fn iso9797_m2_round_trips() {
1011 for len in &[0, 1, 15, 16, 17, 31, 32, 33, 100] {
1012 pad_round_trip(Padding::Iso9797M2, *len);
1013 }
1014 }
1015
1016 #[test]
1017 fn ansix923_round_trips() {
1018 for len in &[1, 15, 16, 17, 31, 32, 33, 100] {
1019 pad_round_trip(Padding::AnsiX923, *len);
1020 }
1021 }
1022
1023 #[test]
1024 fn iso9797_m1_round_trips_when_no_trailing_zero() {
1025 let padding = Padding::Iso9797M1;
1028 let key = [0u8; 16];
1029 let iv = [0u8; 16];
1030
1031 for len in &[1usize, 5, 15, 17, 30] {
1032 let pt: Vec<u8> = (0..*len).map(|i| (i as u8) | 1).collect();
1033 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
1034 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1035 let mut ct = vec![0u8; pt.len() + 16];
1036 let mut n = enc.update(&pt, &mut ct).unwrap();
1037 n += enc.finalize(&mut ct[n..]).unwrap();
1038 ct.truncate(n);
1039
1040 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, padding).unwrap();
1041 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1042 let mut got = vec![0u8; ct.len() + 16];
1043 let mut n = dec.update(&ct, &mut got).unwrap();
1044 n += dec.finalize(&mut got[n..]).unwrap();
1045 got.truncate(n);
1046 assert_eq!(got, pt);
1047 }
1048 }
1049
1050 #[test]
1053 fn invalid_key_len_rejected() {
1054 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1055 assert_eq!(
1056 c.init(Direction::Encrypt, &[0u8; 17], &[0u8; 16]),
1057 Err(Error::InvalidKeyLen)
1058 );
1059 }
1060
1061 #[test]
1062 fn invalid_iv_len_rejected() {
1063 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1064 assert_eq!(
1065 c.init(Direction::Encrypt, &[0u8; 16], &[0u8; 8]),
1066 Err(Error::InvalidIvLen)
1067 );
1068 }
1069
1070 #[test]
1071 fn ctr_with_padding_rejected() {
1072 assert_eq!(
1073 Cipher::new(Algorithm::Aes128, Mode::Ctr, Padding::Pkcs7).err(),
1074 Some(Error::InvalidPaddingForMode)
1075 );
1076 }
1077
1078 #[test]
1079 fn output_too_small_reported() {
1080 let key = [0u8; 16];
1081 let iv = [0u8; 16];
1082 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1083 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1084 let mut tiny = [0u8; 4];
1085 let err = enc.update(&[0u8; 32], &mut tiny);
1086 assert!(matches!(err, Err(Error::OutputBufferTooSmall { .. })));
1087 }
1088
1089 #[test]
1090 fn bad_padding_detected() {
1091 let key = [1u8; 16];
1093 let iv = [2u8; 16];
1094 let pt = b"hello, world! Some content here.";
1095
1096 let mut enc = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1097 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1098 let mut ct = vec![0u8; 64];
1099 let mut n = enc.update(pt, &mut ct).unwrap();
1100 n += enc.finalize(&mut ct[n..]).unwrap();
1101 ct.truncate(n);
1102 let last = ct.len() - 1;
1103 ct[last] ^= 0xFF;
1104
1105 let mut dec = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1106 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1107 let mut out = vec![0u8; 64];
1108 let n = dec.update(&ct, &mut out).unwrap();
1109 let r = dec.finalize(&mut out[n..]);
1110 assert_eq!(r, Err(Error::BadPadding));
1111 }
1112
1113 #[test]
1116 fn tripledes_cbc_pkcs7_round_trip() {
1117 let key = [0x11u8; 24];
1118 let iv = [0x22u8; 8];
1119 let pt: Vec<u8> = (0u8..23).collect();
1120
1121 let mut enc = Cipher::new(Algorithm::TripleDes, Mode::Cbc, Padding::Pkcs7).unwrap();
1122 enc.init(Direction::Encrypt, &key, &iv).unwrap();
1123 let mut ct = vec![0u8; 64];
1124 let mut n = enc.update(&pt, &mut ct).unwrap();
1125 n += enc.finalize(&mut ct[n..]).unwrap();
1126 ct.truncate(n);
1127 assert_eq!(ct.len() % 8, 0);
1128
1129 let mut dec = Cipher::new(Algorithm::TripleDes, Mode::Cbc, Padding::Pkcs7).unwrap();
1130 dec.init(Direction::Decrypt, &key, &iv).unwrap();
1131 let mut got = vec![0u8; 64];
1132 let mut n = dec.update(&ct, &mut got).unwrap();
1133 n += dec.finalize(&mut got[n..]).unwrap();
1134 got.truncate(n);
1135 assert_eq!(got, pt);
1136 }
1137
1138 #[test]
1139 fn reuse_after_init() {
1140 let key = [9u8; 16];
1141 let iv = [8u8; 16];
1142 let mut c = Cipher::new(Algorithm::Aes128, Mode::Cbc, Padding::Pkcs7).unwrap();
1143
1144 for &msg in &[b"first message".as_slice(), b"second", b"a third one!"] {
1145 c.init(Direction::Encrypt, &key, &iv).unwrap();
1146 let ct = {
1147 let mut out = vec![0u8; 64];
1148 let mut n = c.update(msg, &mut out).unwrap();
1149 n += c.finalize(&mut out[n..]).unwrap();
1150 out.truncate(n);
1151 out
1152 };
1153 c.init(Direction::Decrypt, &key, &iv).unwrap();
1154 let pt = {
1155 let mut out = vec![0u8; 64];
1156 let mut n = c.update(&ct, &mut out).unwrap();
1157 n += c.finalize(&mut out[n..]).unwrap();
1158 out.truncate(n);
1159 out
1160 };
1161 assert_eq!(pt, msg);
1162 }
1163 }
1164}