1use md5::{Digest, Md5};
11
12#[derive(Debug, thiserror::Error)]
14pub enum CryptoError {
15 #[error("invalid key length")]
17 InvalidKeyLength,
18 #[error("invalid data length (must be multiple of block size)")]
20 InvalidDataLength,
21 #[error("invalid padding")]
23 InvalidPadding,
24 #[error("data too short for IV")]
26 DataTooShort,
27 #[error("not supported: {0}")]
29 NotSupported(String),
30}
31
32pub fn md5(data: &[u8]) -> [u8; 16] {
34 let mut hasher = Md5::new();
35 hasher.update(data);
36 hasher.finalize().into()
37}
38
39pub fn sha1(_data: &[u8]) -> Result<[u8; 20], CryptoError> {
47 Err(CryptoError::NotSupported(
48 "sha1: not needed for PDF encryption; add sha1 crate if digital signatures require it"
49 .into(),
50 ))
51}
52
53pub fn rc4_crypt(key: &[u8], data: &[u8]) -> Vec<u8> {
58 assert!(
59 !key.is_empty() && key.len() <= 256,
60 "RC4 key length 1..=256"
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 data.iter()
78 .map(|&byte| {
79 i = i.wrapping_add(1);
80 j = j.wrapping_add(s[i as usize]);
81 s.swap(i as usize, j as usize);
82 let k = s[(s[i as usize].wrapping_add(s[j as usize])) as usize];
83 byte ^ k
84 })
85 .collect()
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn sha1_not_supported() {
94 let result = sha1(b"abc");
95 assert!(result.is_err());
96 assert!(
97 result
98 .unwrap_err()
99 .to_string()
100 .contains("not needed for PDF encryption")
101 );
102 }
103
104 #[test]
105 fn md5_empty() {
106 let hash = md5(b"");
107 assert_eq!(
108 hash,
109 [
110 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8,
111 0x42, 0x7e
112 ]
113 );
114 }
115
116 #[test]
117 fn md5_abc() {
118 let hash = md5(b"abc");
119 assert_eq!(
120 hash,
121 [
122 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1,
123 0x7f, 0x72
124 ]
125 );
126 }
127
128 #[test]
131 fn md5_long_data() {
132 let length = 10 * 1024 * 1024 + 1;
133 let data: Vec<u8> = (0..length).map(|i| (i & 0xFF) as u8).collect();
134 let hash = md5(&data);
135 assert_eq!(
136 hash,
137 [
138 0x90, 0xbd, 0x6a, 0xd9, 0x0a, 0xce, 0xf5, 0xad, 0xaa, 0x92, 0x20, 0x3e, 0x21, 0xc7,
139 0xa1, 0x3e
140 ]
141 );
142 }
143
144 #[test]
145 fn rc4_round_trip() {
146 let key = b"secret";
147 let plaintext = b"Hello, PDF encryption!";
148 let ciphertext = rc4_crypt(key, plaintext);
149 assert_ne!(ciphertext, plaintext);
150 let decrypted = rc4_crypt(key, &ciphertext);
151 assert_eq!(decrypted, plaintext);
152 }
153
154 #[test]
155 fn rc4_known_vector() {
156 let key = b"Key";
157 let plaintext = b"Plaintext";
158 let ciphertext = rc4_crypt(key, plaintext);
159 assert_eq!(
160 ciphertext,
161 [0xBB, 0xF3, 0x16, 0xE8, 0xD9, 0x40, 0xAF, 0x0A, 0xD3]
162 );
163 }
164
165 #[test]
168 fn md5_rfc1321_a() {
169 assert_eq!(
170 md5(b"a"),
171 [
172 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77,
173 0x26, 0x61
174 ]
175 );
176 }
177
178 #[test]
179 fn md5_rfc1321_message_digest() {
180 assert_eq!(
181 md5(b"message digest"),
182 [
183 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1,
184 0x61, 0xd0
185 ]
186 );
187 }
188
189 #[test]
190 fn md5_rfc1321_alphabet() {
191 assert_eq!(
192 md5(b"abcdefghijklmnopqrstuvwxyz"),
193 [
194 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67,
195 0xe1, 0x3b
196 ]
197 );
198 }
199
200 #[test]
201 fn md5_rfc1321_alphanumeric() {
202 assert_eq!(
203 md5(b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
204 [
205 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41,
206 0x9d, 0x9f
207 ]
208 );
209 }
210
211 #[test]
212 fn md5_rfc1321_numeric_repeated() {
213 assert_eq!(
214 md5(
215 b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
216 ),
217 [
218 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07,
219 0xb6, 0x7a
220 ]
221 );
222 }
223
224 #[test]
227 fn rc4_foobar_key() {
228 let key = b"foobar";
229 let data = b"The Quick Fox Jumped Over The Lazy Brown Dog.\0";
231 let ciphertext = rc4_crypt(key, data);
232 #[rustfmt::skip]
233 let expected: &[u8] = &[
234 59, 193, 117, 206, 167, 54, 218, 7, 229, 214, 188, 55,
235 90, 205, 196, 25, 36, 114, 199, 218, 161, 107, 122, 119,
236 106, 167, 44, 175, 240, 123, 192, 102, 174, 167, 105, 187,
237 202, 70, 121, 81, 17, 30, 5, 138, 116, 166,
238 ];
239 assert_eq!(ciphertext, expected);
240 }
241}