1use aes::{Aes128, Aes192, Aes256};
11use cbc::{Decryptor, Encryptor};
12use cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit};
13use md5::{Digest, Md5};
14use sha1::Sha1;
15use sha2::{Sha256, Sha384, Sha512};
16
17pub(crate) const BLOCK: usize = 16;
19
20pub(crate) fn ct_eq(a: &[u8], b: &[u8]) -> bool {
28 if a.len() != b.len() {
29 return false;
30 }
31 let mut diff = 0u8;
32 for (x, y) in a.iter().zip(b) {
33 diff |= x ^ y;
34 }
35 diff == 0
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
42pub(crate) enum CipherError {
43 #[error("AES key length {0} bytes is not 16, 24 or 32")]
45 KeyLength(usize),
46 #[error("CBC input of {0} bytes is not a multiple of 16")]
48 NotBlockAligned(usize),
49}
50
51#[must_use]
53pub fn md5(data: &[u8]) -> [u8; 16] {
54 Md5::digest(data).into()
55}
56
57#[must_use]
63pub(crate) fn md5_parts(parts: &[&[u8]]) -> [u8; 16] {
64 let mut hasher = Md5::new();
65 for part in parts {
66 hasher.update(part);
67 }
68 hasher.finalize().into()
69}
70
71#[must_use]
73pub fn sha1(data: &[u8]) -> [u8; 20] {
74 Sha1::digest(data).into()
75}
76
77#[must_use]
79pub(crate) fn sha256(data: &[u8]) -> [u8; 32] {
80 Sha256::digest(data).into()
81}
82
83#[must_use]
85pub(crate) fn sha256_parts(parts: &[&[u8]]) -> [u8; 32] {
86 let mut hasher = Sha256::new();
87 for part in parts {
88 hasher.update(part);
89 }
90 hasher.finalize().into()
91}
92
93#[must_use]
95pub(crate) fn sha384(data: &[u8]) -> [u8; 48] {
96 Sha384::digest(data).into()
97}
98
99#[must_use]
101pub(crate) fn sha512(data: &[u8]) -> [u8; 64] {
102 Sha512::digest(data).into()
103}
104
105pub(crate) fn aes_cbc_encrypt(
110 key: &[u8],
111 iv: &[u8; BLOCK],
112 data: &mut [u8],
113) -> Result<(), CipherError> {
114 let mut blocks = split_blocks(data)?;
115 match key.len() {
116 16 => {
117 Encryptor::<Aes128>::new_from_slices(key, iv).map(|mut c| c.encrypt_blocks(&mut blocks))
118 }
119 24 => {
120 Encryptor::<Aes192>::new_from_slices(key, iv).map(|mut c| c.encrypt_blocks(&mut blocks))
121 }
122 32 => {
123 Encryptor::<Aes256>::new_from_slices(key, iv).map(|mut c| c.encrypt_blocks(&mut blocks))
124 }
125 other => return Err(CipherError::KeyLength(other)),
126 }
127 .map_err(|_| CipherError::KeyLength(key.len()))?;
128 join_blocks(&blocks, data);
129 Ok(())
130}
131
132fn split_blocks(data: &[u8]) -> Result<Vec<cipher::Block<Aes128>>, CipherError> {
134 if !data.len().is_multiple_of(BLOCK) {
135 return Err(CipherError::NotBlockAligned(data.len()));
136 }
137 Ok(data
140 .as_chunks::<BLOCK>()
141 .0
142 .iter()
143 .map(|block| (*block).into())
144 .collect())
145}
146
147fn join_blocks(blocks: &[cipher::Block<Aes128>], data: &mut [u8]) {
149 for (chunk, block) in data.as_chunks_mut::<BLOCK>().0.iter_mut().zip(blocks) {
150 chunk.copy_from_slice(block);
151 }
152}
153
154pub(crate) fn aes_cbc_decrypt(
160 key: &[u8],
161 iv: &[u8; BLOCK],
162 data: &mut [u8],
163) -> Result<(), CipherError> {
164 let mut blocks = split_blocks(data)?;
165 match key.len() {
166 16 => {
167 Decryptor::<Aes128>::new_from_slices(key, iv).map(|mut c| c.decrypt_blocks(&mut blocks))
168 }
169 24 => {
170 Decryptor::<Aes192>::new_from_slices(key, iv).map(|mut c| c.decrypt_blocks(&mut blocks))
171 }
172 32 => {
173 Decryptor::<Aes256>::new_from_slices(key, iv).map(|mut c| c.decrypt_blocks(&mut blocks))
174 }
175 other => return Err(CipherError::KeyLength(other)),
176 }
177 .map_err(|_| CipherError::KeyLength(key.len()))?;
178 join_blocks(&blocks, data);
179 Ok(())
180}
181
182#[cfg(test)]
183mod tests {
184 use super::{
185 BLOCK, CipherError, aes_cbc_decrypt, aes_cbc_encrypt, ct_eq, md5, md5_parts, sha1, sha256,
186 sha384, sha512,
187 };
188
189 fn hex(bytes: &[u8]) -> String {
190 use std::fmt::Write as _;
191 bytes.iter().fold(String::new(), |mut out, b| {
192 let _ = write!(out, "{b:02x}");
193 out
194 })
195 }
196
197 fn unhex(s: &str) -> Vec<u8> {
198 s.as_bytes()
199 .chunks(2)
200 .filter_map(|c| std::str::from_utf8(c).ok())
201 .filter_map(|c| u8::from_str_radix(c, 16).ok())
202 .collect()
203 }
204
205 #[test]
207 fn md5_rfc1321_suite() {
208 let cases: [(&[u8], &str); 7] = [
209 (b"", "d41d8cd98f00b204e9800998ecf8427e"),
210 (b"a", "0cc175b9c0f1b6a831c399e269772661"),
211 (b"abc", "900150983cd24fb0d6963f7d28e17f72"),
212 (b"message digest", "f96b697d7cb7938d525a2f31aaf161d0"),
213 (
214 b"abcdefghijklmnopqrstuvwxyz",
215 "c3fcd3d76192e4007dfb496cca67e13b",
216 ),
217 (
218 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
219 "d174ab98d277d9f5a5611c2c9f419d9f",
220 ),
221 (
222 b"1234567890123456789012345678901234567890\
223 1234567890123456789012345678901234567890",
224 "57edf4a22be3c955ac49da2e2107b67a",
225 ),
226 ];
227 for (input, expected) in cases {
228 assert_eq!(hex(&md5(input)), expected, "md5 of {input:?}");
229 }
230 }
231
232 #[test]
235 fn md5_over_ten_megabytes_in_odd_chunks() {
236 let data: Vec<u8> = (0..=10 * 1024 * 1024_usize)
237 .map(|i| u8::try_from(i & 0xFF).unwrap_or(0))
238 .collect();
239 assert_eq!(hex(&md5(&data)), "90bd6ad90acef5adaa92203e21c7a13e");
240 let chunks: Vec<&[u8]> = data.chunks(4097).collect();
241 assert_eq!(hex(&md5_parts(&chunks)), "90bd6ad90acef5adaa92203e21c7a13e");
242 }
243
244 #[test]
245 fn md5_parts_hashes_the_concatenation() {
246 assert_eq!(md5_parts(&[b"ab", b"c"]), md5(b"abc"));
247 assert_eq!(md5_parts(&[]), md5(b""));
248 }
249
250 #[test]
252 fn sha1_vectors() {
253 assert_eq!(hex(&sha1(b"")), "da39a3ee5e6b4b0d3255bfef95601890afd80709");
254 assert_eq!(
255 hex(&sha1(b"abc")),
256 "a9993e364706816aba3e25717850c26c9cd0d89d"
257 );
258 assert_eq!(
260 hex(&sha1(
261 b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
262 )),
263 "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
264 );
265 }
266
267 #[test]
268 fn sha256_vectors() {
269 assert_eq!(
270 hex(&sha256(b"")),
271 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
272 );
273 assert_eq!(
274 hex(&sha256(b"abc")),
275 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
276 );
277 assert_eq!(
279 hex(&sha256(
280 b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
281 )),
282 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
283 );
284 }
285
286 #[test]
287 fn sha384_vectors() {
288 assert_eq!(
289 hex(&sha384(b"")),
290 "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da\
291 274edebfe76f65fbd51ad2f14898b95b"
292 .replace(char::is_whitespace, "")
293 );
294 assert_eq!(
295 hex(&sha384(
296 b"This is a simple test. To see whether it is getting correct value."
297 )),
298 "9554ffd389f0d642e933fe4c078119cacbb31446d8bda4f412d554037928e5dc\
299 12a51be9fe59253c92305ee50e035807"
300 .replace(char::is_whitespace, "")
301 );
302 }
303
304 #[test]
307 fn sha384_and_sha512_at_the_padding_boundary() {
308 let input = [b'a'; 112];
309 assert_eq!(
310 hex(&sha384(&input)),
311 "187d4e07cb306103c69967bf544d0dfbe904257759 9c73c330abc0cb64c61236\
312 d5ed565ee19119d8c31779a38f791fcd"
313 .replace(char::is_whitespace, "")
314 );
315 assert_eq!(
316 hex(&sha512(&input)),
317 "c01d080efd492776a1c43bd23dd99d0a2e626d481e16782e75d54c2503b5dc32\
318 bd05f0f1ba33e568b88fd2d970929b719ecbb152f58f130a407c8830604b70ca"
319 .replace(char::is_whitespace, "")
320 );
321 }
322
323 #[test]
324 fn sha512_vectors() {
325 assert_eq!(
326 hex(&sha512(b"")),
327 "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce\
328 47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
329 .replace(char::is_whitespace, "")
330 );
331 assert_eq!(
332 hex(&sha512(
333 b"This is a simple test. To see whether it is getting correct value."
334 )),
335 "86b50563a26fd6faeb9bc3bb9eb70382b650556b9069d0a7530a34ddea11cc91\
336 5cc793caae30d196bed035214ac642560ca300694477cc3ed4d61031c6c058cf"
337 .replace(char::is_whitespace, "")
338 );
339 }
340
341 fn aes_chain(key_hex: &str, ciphertexts: [&str; 4]) {
344 const PLAINTEXTS: [&str; 4] = [
345 "6bc1bee22e409f96e93d7e117393172a",
346 "ae2d8a571e03ac9c9eb76fac45af8e51",
347 "30c81c46a35ce411e5fbc1191a0a52ef",
348 "f69f2445df4f9b17ad2b417be66c3710",
349 ];
350 let key = unhex(key_hex);
351 let mut iv: [u8; BLOCK] = unhex("000102030405060708090a0b0c0d0e0f")
352 .try_into()
353 .expect("16 bytes");
354 for (plaintext, expected) in PLAINTEXTS.iter().zip(ciphertexts) {
355 let mut buf = unhex(plaintext);
356 aes_cbc_encrypt(&key, &iv, &mut buf).expect("valid key and length");
357 assert_eq!(hex(&buf), expected, "key {key_hex} iv {}", hex(&iv));
358
359 let mut back = buf.clone();
360 aes_cbc_decrypt(&key, &iv, &mut back).expect("valid key and length");
361 assert_eq!(hex(&back), *plaintext);
362
363 iv = buf.try_into().expect("16 bytes");
364 }
365 }
366
367 #[test]
368 fn aes128_cbc_chain() {
369 aes_chain(
370 "2b7e151628aed2a6abf7158809cf4f3c",
371 [
372 "7649abac8119b246cee98e9b12e9197d",
373 "5086cb9b507219ee95db113a917678b2",
374 "73bed6b8e3c1743b7116e69e22229516",
375 "3ff1caa1681fac09120eca307586e1a7",
376 ],
377 );
378 }
379
380 #[test]
381 fn aes192_cbc_chain() {
382 aes_chain(
383 "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
384 [
385 "4f021db243bc633d7178183a9fa071e8",
386 "b4d9ada9ad7dedf4e5e738763f69145a",
387 "571b242012fb7ae07fa9baac3df102e0",
388 "08b0e27988598881d920a9e64f5615cd",
389 ],
390 );
391 }
392
393 #[test]
394 fn aes256_cbc_chain() {
395 aes_chain(
396 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
397 [
398 "f58c4c04d6e5f1ba779eabfb5f7bfbd6",
399 "9cfc4e967edb808d679f777bc6702c7d",
400 "39f23369a9d9bacfa530e26304231461",
401 "b2eb05e2c39be9fcda6c19078c6a9d1b",
402 ],
403 );
404 }
405
406 #[test]
408 fn cbc_chains_across_blocks_within_one_call() {
409 let key = unhex("2b7e151628aed2a6abf7158809cf4f3c");
410 let iv: [u8; BLOCK] = unhex("000102030405060708090a0b0c0d0e0f")
411 .try_into()
412 .expect("16 bytes");
413 let mut buf = unhex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
414 aes_cbc_encrypt(&key, &iv, &mut buf).expect("valid");
415 assert_eq!(
416 hex(&buf),
417 "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2"
418 );
419 }
420
421 #[test]
423 fn bad_key_and_buffer_lengths_report_rather_than_abort() {
424 let iv = [0u8; BLOCK];
425 let mut block = [0u8; BLOCK];
426 for len in [0usize, 1, 15, 17, 31, 33, 64] {
427 let key = vec![0u8; len];
428 assert_eq!(
429 aes_cbc_decrypt(&key, &iv, &mut block),
430 Err(CipherError::KeyLength(len))
431 );
432 }
433 let key = [0u8; 16];
434 for len in [1usize, 15, 17, 31] {
435 let mut buf = vec![0u8; len];
436 assert_eq!(
437 aes_cbc_encrypt(&key, &iv, &mut buf),
438 Err(CipherError::NotBlockAligned(len))
439 );
440 }
441 assert_eq!(aes_cbc_decrypt(&key, &iv, &mut []), Ok(()));
443 }
444
445 #[test]
446 fn ct_eq_is_length_sensitive_and_agrees_with_eq() {
447 assert!(ct_eq(b"abcd", b"abcd"));
448 assert!(!ct_eq(b"abcd", b"abce"));
449 assert!(!ct_eq(b"abc", b"abcd"));
450 assert!(ct_eq(&[], &[]));
451 }
452}