1pub mod r5_r6;
66
67use crate::error::PdfError;
68use crate::objects::{Object, ObjectId};
69
70const PAD: [u8; 32] = [
74 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
75 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
76];
77
78const AES_SALT: [u8; 4] = [0x73, 0x41, 0x6C, 0x54];
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum CryptMethod {
87 Rc4,
89 Aes128,
91 Aes256,
97}
98
99#[derive(Debug, Clone)]
103pub struct StandardHandler {
104 pub key: Vec<u8>,
106 pub method: CryptMethod,
108 pub revision: u8,
110}
111
112impl StandardHandler {
113 pub fn decrypt_object(&self, id: ObjectId, data: &[u8]) -> Result<Vec<u8>, PdfError> {
121 match self.method {
122 CryptMethod::Rc4 => {
123 let obj_key = self.object_key(id);
124 Ok(rc4(&obj_key, data))
125 }
126 CryptMethod::Aes128 => {
127 let obj_key = self.object_key(id);
128 aes128_cbc_decrypt(&obj_key, data)
129 }
130 CryptMethod::Aes256 => aes256_cbc_decrypt(&self.key, data),
131 }
132 }
133
134 pub fn encrypt_object(
144 &self,
145 id: ObjectId,
146 data: &[u8],
147 iv: &[u8; 16],
148 ) -> Result<Vec<u8>, PdfError> {
149 match self.method {
150 CryptMethod::Rc4 => {
151 let obj_key = self.object_key(id);
152 Ok(rc4(&obj_key, data))
153 }
154 CryptMethod::Aes128 => {
155 let obj_key = self.object_key(id);
156 aes128_cbc_encrypt(&obj_key, data, iv)
157 }
158 CryptMethod::Aes256 => aes256_cbc_encrypt(&self.key, data, iv),
159 }
160 }
161
162 fn object_key(&self, id: ObjectId) -> Vec<u8> {
170 let n = self.key.len();
171 let extra = if self.method == CryptMethod::Aes128 {
172 5 + 4
173 } else {
174 5
175 };
176 let mut buf = Vec::with_capacity(n + extra);
177 buf.extend_from_slice(&self.key);
178 buf.push((id.number & 0xFF) as u8);
179 buf.push(((id.number >> 8) & 0xFF) as u8);
180 buf.push(((id.number >> 16) & 0xFF) as u8);
181 buf.push((id.generation & 0xFF) as u8);
182 buf.push(((id.generation >> 8) & 0xFF) as u8);
183 if self.method == CryptMethod::Aes128 {
184 buf.extend_from_slice(&AES_SALT);
185 }
186 let h = md5(&buf);
187 let take = (n + 5).min(16);
188 h[..take].to_vec()
189 }
190}
191
192pub fn open_with_password(
200 encrypt: &crate::objects::Dict,
201 file_id: &[u8],
202 password: &[u8],
203) -> Result<Option<StandardHandler>, PdfError> {
204 let params = parse_encrypt_dict(encrypt)?;
205
206 if params.revision == 5 || params.revision == 6 {
210 return r5_r6::open_with_password(¶ms, password);
211 }
212
213 if let Some(handler) = try_user_password(¶ms, file_id, password) {
215 return Ok(Some(handler));
216 }
217 if let Some(handler) = try_owner_password(¶ms, file_id, password) {
219 return Ok(Some(handler));
220 }
221 Ok(None)
222}
223
224#[derive(Debug, Clone)]
229pub(crate) struct EncryptParams {
230 pub(crate) revision: u8,
231 pub(crate) length_bits: usize,
233 pub(crate) o: Vec<u8>,
235 pub(crate) u: Vec<u8>,
237 pub(crate) oe: Vec<u8>,
239 pub(crate) ue: Vec<u8>,
241 pub(crate) perms: Vec<u8>,
243 pub(crate) p: i32,
246 pub(crate) encrypt_metadata: bool,
248 pub(crate) cfm: CryptMethod,
250}
251
252fn parse_encrypt_dict(d: &crate::objects::Dict) -> Result<EncryptParams, PdfError> {
253 fn lookup<'a>(d: &'a crate::objects::Dict, key: &str) -> Option<&'a crate::objects::Object> {
254 d.entries().iter().find(|(k, _)| k == key).map(|(_, v)| v)
255 }
256
257 match lookup(d, "Filter") {
259 Some(Object::Name(s)) if s == "Standard" => {}
260 Some(other) => {
261 return Err(PdfError::other(format!(
262 "PDF decrypt: only the Standard security handler is supported (got Filter={other:?})"
263 )))
264 }
265 None => return Err(PdfError::other("PDF decrypt: /Encrypt missing /Filter")),
266 }
267
268 let v = match lookup(d, "V") {
269 Some(Object::Integer(n)) => *n,
270 _ => return Err(PdfError::other("PDF decrypt: /Encrypt missing /V")),
271 };
272 let r = match lookup(d, "R") {
273 Some(Object::Integer(n)) => *n,
274 _ => return Err(PdfError::other("PDF decrypt: /Encrypt missing /R")),
275 };
276 if !(2..=6).contains(&r) {
277 return Err(PdfError::other(format!(
278 "PDF decrypt: revision R={r} not supported (R∈[2,6])"
279 )));
280 }
281
282 let length_bits_default = if v >= 5 { 256 } else { 40 };
284 let length_bits = match lookup(d, "Length") {
285 Some(Object::Integer(n)) => *n as usize,
286 _ => length_bits_default,
287 };
288 let length_ok = if v >= 5 {
289 length_bits == 256
290 } else {
291 (40..=128).contains(&length_bits) && length_bits % 8 == 0
292 };
293 if !length_ok {
294 return Err(PdfError::other(format!(
295 "PDF decrypt: /Length {length_bits} bits invalid for V={v} (V≤2: 40..=128 multiple of 8; V=5: must be 256)"
296 )));
297 }
298
299 let o = match lookup(d, "O") {
300 Some(Object::LiteralString(s)) | Some(Object::HexString(s)) => s.clone(),
301 _ => return Err(PdfError::other("PDF decrypt: /Encrypt missing /O")),
302 };
303 let u = match lookup(d, "U") {
304 Some(Object::LiteralString(s)) | Some(Object::HexString(s)) => s.clone(),
305 _ => return Err(PdfError::other("PDF decrypt: /Encrypt missing /U")),
306 };
307 let o_expected = if r >= 5 { 48 } else { 32 };
308 let u_expected = if r >= 5 { 48 } else { 32 };
309 if o.len() != o_expected {
310 return Err(PdfError::other(format!(
311 "PDF decrypt: /O must be {o_expected} bytes for R={r} (got {})",
312 o.len()
313 )));
314 }
315 if u.len() != u_expected {
316 return Err(PdfError::other(format!(
317 "PDF decrypt: /U must be {u_expected} bytes for R={r} (got {})",
318 u.len()
319 )));
320 }
321
322 let p = match lookup(d, "P") {
323 Some(Object::Integer(n)) => *n as i32,
324 _ => return Err(PdfError::other("PDF decrypt: /Encrypt missing /P")),
325 };
326 let encrypt_metadata = match lookup(d, "EncryptMetadata") {
327 Some(Object::Bool(b)) => *b,
328 _ => true,
329 };
330
331 let (oe, ue, perms) = if r >= 5 {
333 let oe = match lookup(d, "OE") {
334 Some(Object::LiteralString(s)) | Some(Object::HexString(s)) => s.clone(),
335 _ => return Err(PdfError::other("PDF decrypt: V=5 /Encrypt missing /OE")),
336 };
337 let ue = match lookup(d, "UE") {
338 Some(Object::LiteralString(s)) | Some(Object::HexString(s)) => s.clone(),
339 _ => return Err(PdfError::other("PDF decrypt: V=5 /Encrypt missing /UE")),
340 };
341 let perms = match lookup(d, "Perms") {
342 Some(Object::LiteralString(s)) | Some(Object::HexString(s)) => s.clone(),
343 _ => return Err(PdfError::other("PDF decrypt: V=5 /Encrypt missing /Perms")),
344 };
345 if oe.len() != 32 {
346 return Err(PdfError::other(format!(
347 "PDF decrypt: /OE must be 32 bytes (got {})",
348 oe.len()
349 )));
350 }
351 if ue.len() != 32 {
352 return Err(PdfError::other(format!(
353 "PDF decrypt: /UE must be 32 bytes (got {})",
354 ue.len()
355 )));
356 }
357 if perms.len() != 16 {
358 return Err(PdfError::other(format!(
359 "PDF decrypt: /Perms must be 16 bytes (got {})",
360 perms.len()
361 )));
362 }
363 (oe, ue, perms)
364 } else {
365 (Vec::new(), Vec::new(), Vec::new())
366 };
367
368 let cfm = match (v, r) {
370 (1, _) | (2, _) | (_, 2) | (_, 3) => CryptMethod::Rc4,
371 (4, _) | (5, _) => {
372 let stmf = match lookup(d, "StmF") {
373 Some(Object::Name(s)) => s.as_str(),
374 _ => "Identity",
375 };
376 if stmf == "Identity" {
377 if v >= 5 {
381 CryptMethod::Aes256
382 } else {
383 CryptMethod::Rc4
384 }
385 } else {
386 let cf = lookup(d, "CF").ok_or_else(|| {
387 PdfError::other("PDF decrypt: V=4/V=5 /Encrypt missing /CF dictionary")
388 })?;
389 let Object::Dict(cf_dict) = cf else {
390 return Err(PdfError::other("PDF decrypt: /CF must be a dictionary"));
391 };
392 let filter = lookup(cf_dict, stmf).ok_or_else(|| {
393 PdfError::other(format!("PDF decrypt: /CF missing crypt filter `{stmf}`"))
394 })?;
395 let Object::Dict(filter_dict) = filter else {
396 return Err(PdfError::other(format!(
397 "PDF decrypt: /CF/{stmf} must be a dict"
398 )));
399 };
400 match lookup(filter_dict, "CFM") {
401 Some(Object::Name(s)) if s == "V2" => CryptMethod::Rc4,
402 Some(Object::Name(s)) if s == "AESV2" => CryptMethod::Aes128,
403 Some(Object::Name(s)) if s == "AESV3" => CryptMethod::Aes256,
404 Some(Object::Name(s)) if s == "None" => {
405 return Err(PdfError::other(
406 "PDF decrypt: CFM=None requires a custom security handler",
407 ))
408 }
409 Some(other) => {
410 return Err(PdfError::other(format!(
411 "PDF decrypt: unsupported CFM={other:?}"
412 )))
413 }
414 None => {
415 if v >= 5 {
416 CryptMethod::Aes256
417 } else {
418 CryptMethod::Rc4
419 }
420 }
421 }
422 }
423 }
424 _ => {
425 return Err(PdfError::other(format!(
426 "PDF decrypt: V={v} not supported (handler accepts V∈[1,2,4,5])"
427 )))
428 }
429 };
430
431 Ok(EncryptParams {
432 revision: r as u8,
433 length_bits,
434 o,
435 u,
436 oe,
437 ue,
438 perms,
439 p,
440 encrypt_metadata,
441 cfm,
442 })
443}
444
445fn compute_key(p: &EncryptParams, file_id: &[u8], password: &[u8]) -> Vec<u8> {
448 let n = p.length_bits / 8;
449 let pwd = pad_password(password);
451 let mut buf = Vec::with_capacity(32 + 32 + 4 + file_id.len() + 4);
453 buf.extend_from_slice(&pwd);
454 buf.extend_from_slice(&p.o);
456 let pbytes = (p.p as u32).to_le_bytes();
458 buf.extend_from_slice(&pbytes);
459 buf.extend_from_slice(file_id);
461 if p.revision >= 4 && !p.encrypt_metadata {
463 buf.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
464 }
465 let mut h = md5(&buf);
467 if p.revision >= 3 {
469 for _ in 0..50 {
470 h = md5(&h[..n]);
471 }
472 }
473 h[..n].to_vec()
475}
476
477fn pad_password(password: &[u8]) -> [u8; 32] {
479 let mut out = [0u8; 32];
480 let take = password.len().min(32);
481 out[..take].copy_from_slice(&password[..take]);
482 if take < 32 {
483 out[take..].copy_from_slice(&PAD[..32 - take]);
484 }
485 out
486}
487
488fn try_user_password(
490 p: &EncryptParams,
491 file_id: &[u8],
492 password: &[u8],
493) -> Option<StandardHandler> {
494 let key = compute_key(p, file_id, password);
495 let derived_u = derive_u(p, file_id, &key);
496 let cmp_len = if p.revision >= 3 { 16 } else { 32 };
499 if constant_time_eq(&derived_u[..cmp_len], &p.u[..cmp_len]) {
500 Some(StandardHandler {
501 key,
502 method: p.cfm,
503 revision: p.revision,
504 })
505 } else {
506 None
507 }
508}
509
510fn derive_u(p: &EncryptParams, file_id: &[u8], key: &[u8]) -> [u8; 32] {
515 if p.revision == 2 {
516 let cipher = rc4(key, &PAD);
518 let mut out = [0u8; 32];
519 out.copy_from_slice(&cipher);
520 out
521 } else {
522 let mut hash_input = Vec::with_capacity(32 + file_id.len());
525 hash_input.extend_from_slice(&PAD);
526 hash_input.extend_from_slice(file_id);
527 let h = md5(&hash_input);
528 let mut data = rc4(key, &h);
529 for i in 1u8..=19 {
530 let xor_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
531 data = rc4(&xor_key, &data);
532 }
533 let mut out = [0u8; 32];
537 out[..16].copy_from_slice(&data[..16]);
538 out
539 }
540}
541
542fn try_owner_password(
547 p: &EncryptParams,
548 file_id: &[u8],
549 password: &[u8],
550) -> Option<StandardHandler> {
551 let n = p.length_bits / 8;
555 let pwd = pad_password(password);
556 let mut h = md5(&pwd);
557 if p.revision >= 3 {
558 for _ in 0..50 {
559 h = md5(&h[..n]);
560 }
561 }
562 let owner_key = h[..n].to_vec();
563
564 let recovered_user_pwd = if p.revision == 2 {
566 rc4(&owner_key, &p.o)
567 } else {
568 let mut buf = p.o.clone();
569 for i in (0u8..=19).rev() {
571 let xor_key: Vec<u8> = owner_key.iter().map(|b| b ^ i).collect();
572 buf = rc4(&xor_key, &buf);
573 }
574 buf
575 };
576
577 let user_pwd = strip_pad(&recovered_user_pwd);
580 try_user_password(p, file_id, &user_pwd)
581}
582
583fn strip_pad(padded: &[u8]) -> Vec<u8> {
592 let n = padded.len();
593 for l in 0..=n {
594 if padded[l..] == PAD[..n - l] {
595 return padded[..l].to_vec();
596 }
597 }
598 padded.to_vec()
599}
600
601pub(crate) fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
602 if a.len() != b.len() {
603 return false;
604 }
605 let mut diff = 0u8;
606 for (x, y) in a.iter().zip(b.iter()) {
607 diff |= x ^ y;
608 }
609 diff == 0
610}
611
612pub fn rc4(key: &[u8], data: &[u8]) -> Vec<u8> {
620 debug_assert!(!key.is_empty(), "RC4 key must not be empty");
621 let mut s: [u8; 256] = [0; 256];
622 for (i, b) in s.iter_mut().enumerate() {
623 *b = i as u8;
624 }
625 let mut j: u8 = 0;
627 for i in 0..256 {
628 j = j.wrapping_add(s[i]).wrapping_add(key[i % key.len()]);
629 s.swap(i, j as usize);
630 }
631 let mut i: u8 = 0;
633 j = 0;
634 let mut out = Vec::with_capacity(data.len());
635 for &byte in data {
636 i = i.wrapping_add(1);
637 j = j.wrapping_add(s[i as usize]);
638 s.swap(i as usize, j as usize);
639 let k = s[s[i as usize].wrapping_add(s[j as usize]) as usize];
640 out.push(byte ^ k);
641 }
642 out
643}
644
645pub(crate) fn aes256_ecb_decrypt_block(key: &[u8], block: &[u8; 16]) -> Result<[u8; 16], PdfError> {
654 use aes::cipher::{BlockDecrypt, KeyInit};
655 if key.len() != 32 {
656 return Err(PdfError::other(format!(
657 "PDF decrypt: AES-256 requires a 32-byte key (got {} bytes)",
658 key.len()
659 )));
660 }
661 let cipher = aes::Aes256::new(key.into());
662 let mut buf = aes::cipher::generic_array::GenericArray::clone_from_slice(block);
663 cipher.decrypt_block(&mut buf);
664 let mut out = [0u8; 16];
665 out.copy_from_slice(&buf);
666 Ok(out)
667}
668
669fn aes256_cbc_decrypt(key: &[u8], data: &[u8]) -> Result<Vec<u8>, PdfError> {
673 use aes::cipher::{BlockDecryptMut, KeyIvInit};
674 type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
675 if data.len() < 16 {
676 return Err(PdfError::other(
677 "PDF decrypt: AES-256 ciphertext shorter than IV",
678 ));
679 }
680 if (data.len() - 16) % 16 != 0 {
681 return Err(PdfError::other(format!(
682 "PDF decrypt: AES-256 ciphertext length {} not aligned to 16-byte blocks (after IV)",
683 data.len() - 16
684 )));
685 }
686 if key.len() != 32 {
687 return Err(PdfError::other(format!(
688 "PDF decrypt: AES-256 expects a 32-byte key (got {} bytes)",
689 key.len()
690 )));
691 }
692 let iv = &data[..16];
693 let ct = &data[16..];
694 let dec = Aes256CbcDec::new(key.into(), iv.into());
695 let mut buf = ct.to_vec();
696 let pt = dec
697 .decrypt_padded_mut::<aes::cipher::block_padding::Pkcs7>(&mut buf)
698 .map_err(|e| PdfError::other(format!("PDF decrypt: AES-256 padding error: {e:?}")))?;
699 Ok(pt.to_vec())
700}
701
702fn aes256_cbc_encrypt(key: &[u8], data: &[u8], iv: &[u8; 16]) -> Result<Vec<u8>, PdfError> {
705 use aes::cipher::{BlockEncryptMut, KeyIvInit};
706 type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
707 if key.len() != 32 {
708 return Err(PdfError::other(format!(
709 "PDF encrypt: AES-256 expects a 32-byte key (got {} bytes)",
710 key.len()
711 )));
712 }
713 let enc = Aes256CbcEnc::new(key.into(), iv.into());
714 let pad_block = (data.len() / 16) + 1;
715 let mut buf = vec![0u8; pad_block * 16];
716 let n = enc
717 .encrypt_padded_b2b_mut::<aes::cipher::block_padding::Pkcs7>(data, &mut buf)
718 .map_err(|e| PdfError::other(format!("PDF encrypt: AES-256 padding error: {e:?}")))?
719 .len();
720 buf.truncate(n);
721 let mut out = Vec::with_capacity(16 + n);
722 out.extend_from_slice(iv);
723 out.extend_from_slice(&buf);
724 Ok(out)
725}
726
727fn aes128_cbc_encrypt(key: &[u8], data: &[u8], iv: &[u8; 16]) -> Result<Vec<u8>, PdfError> {
730 use aes::cipher::{BlockEncryptMut, KeyIvInit};
731 type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
732 if key.len() != 16 {
733 return Err(PdfError::other(format!(
734 "PDF encrypt: AES-128 expects a 16-byte key (got {} bytes)",
735 key.len()
736 )));
737 }
738 let enc = Aes128CbcEnc::new(key.into(), iv.into());
739 let pad_block = (data.len() / 16) + 1;
740 let mut buf = vec![0u8; pad_block * 16];
741 let n = enc
742 .encrypt_padded_b2b_mut::<aes::cipher::block_padding::Pkcs7>(data, &mut buf)
743 .map_err(|e| PdfError::other(format!("PDF encrypt: AES-128 padding error: {e:?}")))?
744 .len();
745 buf.truncate(n);
746 let mut out = Vec::with_capacity(16 + n);
747 out.extend_from_slice(iv);
748 out.extend_from_slice(&buf);
749 Ok(out)
750}
751
752fn aes128_cbc_decrypt(key: &[u8], data: &[u8]) -> Result<Vec<u8>, PdfError> {
756 use aes::cipher::{BlockDecryptMut, KeyIvInit};
757 type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
758 if data.len() < 16 {
759 return Err(PdfError::other(
760 "PDF decrypt: AES-128 ciphertext shorter than IV",
761 ));
762 }
763 if (data.len() - 16) % 16 != 0 {
764 return Err(PdfError::other(format!(
765 "PDF decrypt: AES-128 ciphertext length {} not aligned to 16-byte blocks (after IV)",
766 data.len() - 16
767 )));
768 }
769 if key.len() != 16 {
770 return Err(PdfError::other(format!(
771 "PDF decrypt: AES-128 expects a 16-byte key (got {} bytes)",
772 key.len()
773 )));
774 }
775 let iv = &data[..16];
776 let ct = &data[16..];
777 let dec = Aes128CbcDec::new(key.into(), iv.into());
778 let mut buf = ct.to_vec();
779 let pt = dec
780 .decrypt_padded_mut::<aes::cipher::block_padding::Pkcs7>(&mut buf)
781 .map_err(|e| PdfError::other(format!("PDF decrypt: AES-128 padding error: {e:?}")))?;
782 Ok(pt.to_vec())
783}
784
785const MD5_S: [u32; 64] = [
793 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, ];
798
799const MD5_K: [u32; 64] = [
800 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
801 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
802 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
803 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
804 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
805 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
806 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
807 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391,
808];
809
810pub fn md5(input: &[u8]) -> [u8; 16] {
812 let mut state: [u32; 4] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476];
813
814 let mut buf = input.to_vec();
817 let bit_len = (input.len() as u64).wrapping_mul(8);
818 buf.push(0x80);
819 while buf.len() % 64 != 56 {
820 buf.push(0);
821 }
822 buf.extend_from_slice(&bit_len.to_le_bytes());
823
824 for chunk in buf.chunks_exact(64) {
825 let mut m = [0u32; 16];
826 for (i, w) in chunk.chunks_exact(4).enumerate() {
827 m[i] = u32::from_le_bytes([w[0], w[1], w[2], w[3]]);
828 }
829 let mut a = state[0];
830 let mut b = state[1];
831 let mut c = state[2];
832 let mut d = state[3];
833 for i in 0..64 {
834 let (f, g) = match i {
835 0..=15 => ((b & c) | (!b & d), i),
836 16..=31 => ((d & b) | (!d & c), (5 * i + 1) % 16),
837 32..=47 => (b ^ c ^ d, (3 * i + 5) % 16),
838 _ => (c ^ (b | !d), (7 * i) % 16),
839 };
840 let temp = d;
841 d = c;
842 c = b;
843 b = b.wrapping_add(
844 a.wrapping_add(f)
845 .wrapping_add(MD5_K[i])
846 .wrapping_add(m[g])
847 .rotate_left(MD5_S[i]),
848 );
849 a = temp;
850 }
851 state[0] = state[0].wrapping_add(a);
852 state[1] = state[1].wrapping_add(b);
853 state[2] = state[2].wrapping_add(c);
854 state[3] = state[3].wrapping_add(d);
855 }
856
857 let mut out = [0u8; 16];
858 for (i, s) in state.iter().enumerate() {
859 out[4 * i..4 * (i + 1)].copy_from_slice(&s.to_le_bytes());
860 }
861 out
862}
863
864#[cfg(test)]
865mod tests {
866 use super::*;
867
868 #[test]
870 fn md5_empty_string() {
871 assert_eq!(
872 md5(b""),
873 [
874 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8,
875 0x42, 0x7E
876 ]
877 );
878 }
879
880 #[test]
881 fn md5_short_inputs() {
882 assert_eq!(
884 md5(b"a"),
885 [
886 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77,
887 0x26, 0x61
888 ]
889 );
890 assert_eq!(
892 md5(b"abc"),
893 [
894 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1,
895 0x7F, 0x72
896 ]
897 );
898 assert_eq!(
900 md5(b"message digest"),
901 [
902 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1,
903 0x61, 0xD0
904 ]
905 );
906 }
907
908 #[test]
909 fn md5_long_block() {
910 assert_eq!(
912 md5(b"abcdefghijklmnopqrstuvwxyz"),
913 [
914 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67,
915 0xE1, 0x3B
916 ]
917 );
918 }
919
920 #[test]
921 fn md5_multi_block() {
922 let s = b"12345678901234567890123456789012345678901234567890123456789012345678901234567890";
924 assert_eq!(
926 md5(s),
927 [
928 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07,
929 0xB6, 0x7A
930 ]
931 );
932 }
933
934 #[test]
936 fn rc4_rfc6229_key0102030405() {
937 let key = [0x01, 0x02, 0x03, 0x04, 0x05];
941 let pt = [0u8; 16];
942 let ct = rc4(&key, &pt);
943 assert_eq!(
944 ct,
945 vec![
946 0xB2, 0x39, 0x63, 0x05, 0xF0, 0x3D, 0xC0, 0x27, 0xCC, 0xC3, 0x52, 0x4A, 0x0A, 0x11,
947 0x18, 0xA8
948 ]
949 );
950 }
951
952 #[test]
953 fn rc4_rfc6229_key0102030405060708() {
954 let key = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
957 let pt = [0u8; 16];
958 let ct = rc4(&key, &pt);
959 assert_eq!(
960 ct,
961 vec![
962 0x97, 0xAB, 0x8A, 0x1B, 0xF0, 0xAF, 0xB9, 0x61, 0x32, 0xF2, 0xF6, 0x72, 0x58, 0xDA,
963 0x15, 0xA8
964 ]
965 );
966 }
967
968 #[test]
969 fn rc4_self_inverse() {
970 let key = b"Key";
972 let plain = b"Plaintext";
973 let cipher = rc4(key, plain);
974 let recovered = rc4(key, &cipher);
975 assert_eq!(&recovered, plain);
976 }
977
978 #[test]
980 fn aes128_cbc_decrypt_round_trips_pkcs7() {
981 use aes::cipher::{BlockEncryptMut, KeyIvInit};
982 type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
983 let key = [0x42u8; 16];
984 let iv = [0x17u8; 16];
985 let pt = b"hello world".to_vec();
986 let mut buf = vec![0u8; 16 + ((pt.len() / 16) + 1) * 16];
987 let enc = Aes128CbcEnc::new((&key).into(), (&iv).into());
988 let n = enc
989 .encrypt_padded_b2b_mut::<aes::cipher::block_padding::Pkcs7>(&pt, &mut buf[16..])
990 .unwrap()
991 .len();
992 buf[..16].copy_from_slice(&iv);
993 buf.truncate(16 + n);
994 let recovered = aes128_cbc_decrypt(&key, &buf).unwrap();
995 assert_eq!(recovered, pt);
996 }
997
998 #[test]
1000 fn algorithm_2_known_answer_r3_empty_password() {
1001 let p = EncryptParams {
1009 revision: 3,
1010 length_bits: 128,
1011 o: vec![0xAA; 32],
1012 u: vec![0; 32],
1013 oe: Vec::new(),
1014 ue: Vec::new(),
1015 perms: Vec::new(),
1016 p: -4,
1017 encrypt_metadata: true,
1018 cfm: CryptMethod::Rc4,
1019 };
1020 let id = vec![0xBB; 16];
1021 let k = compute_key(&p, &id, b"");
1022 let mut buf = Vec::new();
1024 buf.extend_from_slice(&PAD);
1025 buf.extend_from_slice(&p.o);
1026 buf.extend_from_slice(&((-4i32) as u32).to_le_bytes());
1027 buf.extend_from_slice(&id);
1028 let mut h = md5(&buf);
1029 for _ in 0..50 {
1030 h = md5(&h[..16]);
1031 }
1032 assert_eq!(k, h[..16].to_vec());
1033 }
1034
1035 #[test]
1037 fn algorithm_1_object_key_rc4() {
1038 let h = StandardHandler {
1039 key: vec![0x01, 0x02, 0x03, 0x04, 0x05], method: CryptMethod::Rc4,
1041 revision: 2,
1042 };
1043 let id = ObjectId {
1044 number: 0x010203,
1045 generation: 0x0405,
1046 };
1047 let k = h.object_key(id);
1048 assert_eq!(k.len(), 10);
1050 let mut buf = Vec::new();
1052 buf.extend_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05]);
1053 buf.extend_from_slice(&[0x03, 0x02, 0x01]); buf.extend_from_slice(&[0x05, 0x04]); let h2 = md5(&buf);
1056 assert_eq!(k, h2[..10].to_vec());
1057 }
1058
1059 #[test]
1060 fn algorithm_1_object_key_aes_appends_salt() {
1061 let h = StandardHandler {
1062 key: vec![0u8; 16],
1063 method: CryptMethod::Aes128,
1064 revision: 4,
1065 };
1066 let id = ObjectId {
1067 number: 1,
1068 generation: 0,
1069 };
1070 let k = h.object_key(id);
1071 assert_eq!(k.len(), 16);
1073 let mut buf = Vec::new();
1074 buf.extend_from_slice(&h.key);
1075 buf.extend_from_slice(&[0x01, 0x00, 0x00, 0x00, 0x00]);
1076 buf.extend_from_slice(&AES_SALT);
1077 let h2 = md5(&buf);
1078 assert_eq!(k, h2[..16].to_vec());
1079 }
1080
1081 #[test]
1083 fn rc4_object_roundtrip_via_handler() {
1084 let h = StandardHandler {
1085 key: vec![0xDE, 0xAD, 0xBE, 0xEF, 0x42],
1086 method: CryptMethod::Rc4,
1087 revision: 2,
1088 };
1089 let id = ObjectId {
1090 number: 7,
1091 generation: 0,
1092 };
1093 let plain = b"Hello, encrypted world!".to_vec();
1094 let cipher = h.decrypt_object(id, &plain).unwrap();
1097 let recovered = h.decrypt_object(id, &cipher).unwrap();
1098 assert_eq!(recovered, plain);
1099 }
1100
1101 #[test]
1103 fn strip_pad_recovers_short_passwords() {
1104 let mut padded = Vec::from(b"hello".as_slice());
1105 padded.extend_from_slice(&PAD[..27]);
1106 assert_eq!(strip_pad(&padded), b"hello".to_vec());
1107 }
1108
1109 #[test]
1110 fn strip_pad_empty_password() {
1111 assert_eq!(strip_pad(&PAD), Vec::<u8>::new());
1112 }
1113}