1use md5::{Digest, Md5};
11use sha1::Sha1;
12
13#[derive(Debug, thiserror::Error)]
15pub enum CryptoError {
16 #[error("invalid key length")]
18 InvalidKeyLength,
19 #[error("invalid data length (must be multiple of block size)")]
21 InvalidDataLength,
22 #[error("invalid padding")]
24 InvalidPadding,
25 #[error("data too short for IV")]
27 DataTooShort,
28 #[error("not supported: {0}")]
30 NotSupported(String),
31}
32
33pub fn md5(data: &[u8]) -> [u8; 16] {
35 let mut hasher = Md5::new();
36 hasher.update(data);
37 hasher.finalize().into()
38}
39
40pub fn sha1(data: &[u8]) -> [u8; 20] {
46 let mut hasher = Sha1::new();
47 hasher.update(data);
48 hasher.finalize().into()
49}
50
51pub fn rc4_crypt(key: &[u8], data: &[u8]) -> Result<Vec<u8>, CryptoError> {
59 if key.is_empty() || key.len() > 256 {
60 return Err(CryptoError::InvalidKeyLength);
61 }
62
63 let mut s = [0u8; 256];
65 for (i, b) in s.iter_mut().enumerate() {
66 *b = i as u8;
67 }
68 let mut j: u8 = 0;
69 for i in 0..256 {
70 j = j.wrapping_add(s[i]).wrapping_add(key[i % key.len()]);
71 s.swap(i, j as usize);
72 }
73
74 let mut i: u8 = 0;
76 let mut j: u8 = 0;
77 Ok(data
78 .iter()
79 .map(|&byte| {
80 i = i.wrapping_add(1);
81 j = j.wrapping_add(s[i as usize]);
82 s.swap(i as usize, j as usize);
83 let k = s[(s[i as usize].wrapping_add(s[j as usize])) as usize];
84 byte ^ k
85 })
86 .collect())
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
98 fn test_sha1_empty() {
99 assert_eq!(
100 sha1(b""),
101 [
102 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60,
103 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09
104 ]
105 );
106 }
107
108 #[test]
111 fn test_sha1_known_vector_abc() {
112 assert_eq!(
113 sha1(b"abc"),
114 [
115 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50,
116 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
117 ]
118 );
119 }
120
121 #[test]
124 fn test_sha1_fips_a2_multi_block() {
125 assert_eq!(
126 sha1(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
127 [
128 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae, 0x4a, 0xa1, 0xf9, 0x51,
129 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1
130 ]
131 );
132 }
133
134 #[test]
136 fn test_md5_empty() {
137 let hash = md5(b"");
138 assert_eq!(
139 hash,
140 [
141 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8,
142 0x42, 0x7e
143 ]
144 );
145 }
146
147 #[test]
149 fn test_md5_abc() {
150 let hash = md5(b"abc");
151 assert_eq!(
152 hash,
153 [
154 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1,
155 0x7f, 0x72
156 ]
157 );
158 }
159
160 #[test]
164 fn test_md5_long_data() {
165 let length = 10 * 1024 * 1024 + 1;
166 let data: Vec<u8> = (0..length).map(|i| (i & 0xFF) as u8).collect();
167 let hash = md5(&data);
168 assert_eq!(
169 hash,
170 [
171 0x90, 0xbd, 0x6a, 0xd9, 0x0a, 0xce, 0xf5, 0xad, 0xaa, 0x92, 0x20, 0x3e, 0x21, 0xc7,
172 0xa1, 0x3e
173 ]
174 );
175 }
176
177 #[test]
178 fn test_rc4_round_trip() {
179 let key = b"secret";
180 let plaintext = b"Hello, PDF encryption!";
181 let ciphertext = rc4_crypt(key, plaintext).unwrap();
182 assert_ne!(ciphertext, plaintext);
183 let decrypted = rc4_crypt(key, &ciphertext).unwrap();
184 assert_eq!(decrypted, plaintext);
185 }
186
187 #[test]
189 fn test_rc4_known_vector() {
190 let key = b"Key";
191 let plaintext = b"Plaintext";
192 let ciphertext = rc4_crypt(key, plaintext).unwrap();
193 assert_eq!(
194 ciphertext,
195 [0xBB, 0xF3, 0x16, 0xE8, 0xD9, 0x40, 0xAF, 0x0A, 0xD3]
196 );
197 }
198
199 #[test]
200 fn test_rc4_empty_key_returns_error() {
201 let result = rc4_crypt(b"", b"data");
202 assert!(result.is_err());
203 assert!(matches!(result.unwrap_err(), CryptoError::InvalidKeyLength));
204 }
205
206 #[test]
207 fn test_rc4_oversized_key_returns_error() {
208 let key = vec![0u8; 257];
209 let result = rc4_crypt(&key, b"data");
210 assert!(result.is_err());
211 assert!(matches!(result.unwrap_err(), CryptoError::InvalidKeyLength));
212 }
213
214 #[test]
218 fn test_md5_rfc1321_a() {
219 assert_eq!(
220 md5(b"a"),
221 [
222 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77,
223 0x26, 0x61
224 ]
225 );
226 }
227
228 #[test]
230 fn test_md5_rfc1321_message_digest() {
231 assert_eq!(
232 md5(b"message digest"),
233 [
234 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1,
235 0x61, 0xd0
236 ]
237 );
238 }
239
240 #[test]
242 fn test_md5_rfc1321_alphabet() {
243 assert_eq!(
244 md5(b"abcdefghijklmnopqrstuvwxyz"),
245 [
246 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67,
247 0xe1, 0x3b
248 ]
249 );
250 }
251
252 #[test]
254 fn test_md5_rfc1321_alphanumeric() {
255 assert_eq!(
256 md5(b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
257 [
258 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41,
259 0x9d, 0x9f
260 ]
261 );
262 }
263
264 #[test]
266 fn test_md5_rfc1321_numeric_repeated() {
267 assert_eq!(
268 md5(
269 b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
270 ),
271 [
272 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07,
273 0xb6, 0x7a
274 ]
275 );
276 }
277
278 #[test]
282 fn test_rc4_foobar_key() {
283 let key = b"foobar";
284 let data = b"The Quick Fox Jumped Over The Lazy Brown Dog.\0";
286 let ciphertext = rc4_crypt(key, data).unwrap();
287 #[rustfmt::skip]
288 let expected: &[u8] = &[
289 59, 193, 117, 206, 167, 54, 218, 7, 229, 214, 188, 55,
290 90, 205, 196, 25, 36, 114, 199, 218, 161, 107, 122, 119,
291 106, 167, 44, 175, 240, 123, 192, 102, 174, 167, 105, 187,
292 202, 70, 121, 81, 17, 30, 5, 138, 116, 166,
293 ];
294 assert_eq!(ciphertext, expected);
295 }
296}