1use crate::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, inout::InOutBuf};
4
5const MAX_MSG_LEN: usize = 1 << 12;
6
7#[derive(Debug, Clone, Copy)]
9pub struct TestVector {
10 pub key: &'static [u8],
12 pub iv: &'static [u8],
14 pub plaintext: &'static [u8],
16 pub ciphertext: &'static [u8],
18}
19
20pub fn encrypt<C: BlockModeEncrypt + KeyIvInit>(tv: &TestVector) -> Result<(), &'static str> {
22 let mut buf = [0u8; MAX_MSG_LEN];
23 let Some(out) = buf.get_mut(..tv.ciphertext.len()) else {
24 return Err("ciphertext is bigger than MAX_MSG_LEN bytes");
25 };
26 let Ok(mut buf) = InOutBuf::new(tv.plaintext, out) else {
27 return Err("plaintext/ciphertext length mismatch");
28 };
29 let (blocks, tail) = buf.reborrow().into_chunks();
30 if !tail.is_empty() {
31 return Err("plaintext/ciphertext length is not multiple of block size");
32 }
33
34 let Ok(mut cipher) = C::new_from_slices(tv.key, tv.iv) else {
35 return Err("cipher initialization failure");
36 };
37 for block in blocks {
38 cipher.encrypt_block_inout(block);
39 }
40 if buf.get_out() != tv.ciphertext {
41 return Err("single block encryption failure");
42 }
43
44 let Ok(mut cipher) = C::new_from_slices(tv.key, tv.iv) else {
46 return Err("cipher initialization failure");
47 };
48 buf.get_out().fill(0);
49 let (blocks, _) = buf.reborrow().into_chunks();
50 cipher.encrypt_blocks_inout(blocks);
51 if buf.get_out() != tv.ciphertext {
52 return Err("multi-block encryption failure");
53 }
54 Ok(())
55}
56
57pub fn decrypt<C: BlockModeDecrypt + KeyIvInit>(tv: &TestVector) -> Result<(), &'static str> {
59 let mut buf = [0u8; MAX_MSG_LEN];
60 let Some(out) = buf.get_mut(..tv.plaintext.len()) else {
61 return Err("plaintext is bigger than MAX_MSG_LEN bytes");
62 };
63 let Ok(mut buf) = InOutBuf::new(tv.ciphertext, out) else {
64 return Err("plaintext/ciphertext length mismatch");
65 };
66 let (blocks, tail) = buf.reborrow().into_chunks();
67 if !tail.is_empty() {
68 return Err("plaintext/ciphertext length is not multiple of block size");
69 }
70
71 let Ok(mut cipher) = C::new_from_slices(tv.key, tv.iv) else {
72 return Err("cipher initialization failure");
73 };
74 for block in blocks {
75 cipher.decrypt_block_inout(block);
76 }
77 if buf.get_out() != tv.plaintext {
78 return Err("single block decryption failure");
79 }
80
81 let Ok(mut cipher) = C::new_from_slices(tv.key, tv.iv) else {
83 return Err("cipher initialization failure");
84 };
85 buf.get_out().fill(0);
86 let (blocks, _) = buf.reborrow().into_chunks();
87 cipher.decrypt_blocks_inout(blocks);
88 if buf.get_out() != tv.plaintext {
89 return Err("multi-block decryption failure");
90 }
91 Ok(())
92}
93
94#[macro_export]
96macro_rules! block_mode_test {
97 ($name:ident, $cipher:ty, $test_fn:ident $(,)?) => {
99 $crate::block_cipher_test!($name, stringify!($name), $cipher);
100 };
101 ($test_name:ident, $file_name:expr, $cipher:ty, $test_fn:ident $(,)?) => {
103 #[test]
104 fn $test_name() {
105 use $crate::dev::block_mode::TestVector;
106
107 $crate::dev::blobby::parse_into_structs!(
108 include_bytes!(concat!("data/", $file_name, ".blb"));
109 static TEST_VECTORS: &[
110 TestVector { key, iv, plaintext, ciphertext }
111 ];
112 );
113
114 for (i, tv) in TEST_VECTORS.iter().enumerate() {
115 if let Err(reason) = $crate::dev::block_mode::$test_fn::<$cipher>(tv) {
116 panic!(
117 "\n\
118 Failed test #{i}\n\
119 reason:\t{reason:?}\n\
120 test vector:\t{tv:?}\n",
121 );
122 }
123 }
124 }
125 };
126}
127
128#[macro_export]
130macro_rules! iv_state_test {
131 ($name:ident, $cipher:ty, encrypt $(,)?) => {
132 $crate::iv_state_test!($name, $cipher, encrypt_blocks);
133 };
134 ($name:ident, $cipher:ty, decrypt $(,)?) => {
135 $crate::iv_state_test!($name, $cipher, decrypt_blocks);
136 };
137 ($name:ident, $cipher:ty, apply_ks $(,)?) => {
138 $crate::iv_state_test!($name, $cipher, apply_keystream_blocks);
139 };
140 ($name:ident, $cipher:ty, $method:ident $(,)?) => {
141 #[test]
142 fn $name() {
143 use cipher::*;
144
145 let mut blocks = [Block::<$cipher>::default(); 32];
146
147 for (i, block) in blocks.iter_mut().enumerate() {
148 for (j, b) in block.iter_mut().enumerate() {
149 *b = (i + j) as u8;
150 }
151 }
152
153 let mut key = Key::<$cipher>::default();
154 let mut iv = Iv::<$cipher>::default();
155 key.iter_mut().for_each(|b| *b = 0x42);
156 iv.iter_mut().for_each(|b| *b = 0x24);
157
158 let mut cipher = <$cipher>::new(&key, &iv);
159 let mut target = blocks.clone();
160 cipher.$method(&mut target);
161
162 for i in 0..32 {
163 let mut blocks = blocks.clone();
164 let (b1, b2) = blocks.split_at_mut(i);
165 let mut cipher1 = <$cipher>::new(&key, &iv);
166 cipher1.$method(b1);
167 let temp_iv = cipher1.iv_state();
168 let mut cipher2 = <$cipher>::new(&key, &temp_iv);
169 cipher2.$method(b2);
170 assert_eq!(blocks, target);
171 }
172 }
173 };
174}