1use crate::object::{Dict, Name, ObjRef, Object};
25
26const PAD: [u8; 32] = [
28 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
29 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
30];
31
32#[derive(Clone, Copy, PartialEq, Debug)]
34enum Cipher {
35 Identity,
38 Rc4,
40 Aesv2,
42 Aesv3,
44}
45
46#[derive(Clone)]
48pub struct Decryptor {
49 key: Vec<u8>,
51 filters: CryptFilters,
53 encrypt_metadata: bool,
57}
58
59#[derive(Clone)]
64struct CryptFilters {
65 named: Vec<(String, Cipher)>,
69 stream: Cipher,
71 string: Cipher,
73 embedded_file: Cipher,
75}
76
77impl CryptFilters {
78 fn uniform(cipher: Cipher) -> CryptFilters {
80 CryptFilters {
81 named: Vec::new(),
82 stream: cipher,
83 string: cipher,
84 embedded_file: cipher,
85 }
86 }
87
88 fn parse(enc: &Dict) -> Option<CryptFilters> {
97 let named: Vec<(String, Cipher)> = enc
98 .get_dict("CF")
99 .into_iter()
100 .flat_map(Dict::iter)
101 .filter(|(name, _)| name.0 != "Identity")
102 .filter_map(|(name, filter)| Some((name.0.clone(), cipher_method(filter.as_dict()?)?)))
103 .collect();
104 let filters = CryptFilters {
105 named,
106 stream: Cipher::Identity,
107 string: Cipher::Identity,
108 embedded_file: Cipher::Identity,
109 };
110 let pick = |key: &str, default: Cipher| match enc.get_name(key) {
111 None => Some(default),
112 Some(n) => filters.named(&n.0),
113 };
114 let stream = pick("StmF", Cipher::Identity)?;
115 let string = pick("StrF", Cipher::Identity)?;
116 let embedded_file = pick("EFF", stream)?;
117 Some(CryptFilters {
118 stream,
119 string,
120 embedded_file,
121 ..filters
122 })
123 }
124
125 fn named(&self, name: &str) -> Option<Cipher> {
129 if name == "Identity" {
130 return Some(Cipher::Identity);
131 }
132 self.named
133 .iter()
134 .find(|(n, _)| n == name)
135 .map(|(_, cipher)| *cipher)
136 }
137}
138
139fn stream_crypt_filter(dict: &Dict) -> Option<String> {
148 let first = match dict.get("Filter")? {
149 Object::Name(n) => n,
150 Object::Array(items) => items.first()?.as_name()?,
151 _ => return None,
152 };
153 if first.0 != "Crypt" {
154 return None;
155 }
156 let parms = match dict.get("DecodeParms") {
157 Some(Object::Dict(d)) => Some(d),
158 Some(Object::Array(items)) => items.first().and_then(Object::as_dict),
159 _ => None,
160 };
161 let name = parms
162 .and_then(|p| p.get_name("Name"))
163 .map_or("Identity", |n| n.0.as_str());
164 Some(name.to_string())
165}
166
167pub fn crypt_filter_refs(enc: &Dict) -> Vec<ObjRef> {
185 match enc.get("CF") {
186 Some(Object::Ref(r)) => vec![*r],
187 Some(Object::Dict(cf)) => cf.iter().filter_map(|(_, v)| v.as_ref()).collect(),
188 _ => Vec::new(),
189 }
190}
191
192pub fn direct_crypt_filters(enc: &Dict, mut lookup: impl FnMut(ObjRef) -> Option<Object>) -> Dict {
207 let mut out = enc.clone();
208 let cf = match out.get("CF") {
209 Some(Object::Ref(r)) => lookup(*r),
210 Some(Object::Dict(cf)) => Some(Object::Dict(cf.clone())),
211 _ => None,
212 };
213 let Some(Object::Dict(mut cf)) = cf else {
214 return out;
215 };
216 for value in cf.values_mut() {
217 if let Object::Ref(r) = *value {
218 if let Some(direct) = lookup(r) {
219 *value = direct;
220 }
221 }
222 }
223 out.insert(Name("CF".to_string()), Object::Dict(cf));
224 out
225}
226
227fn cipher_method(filter: &Dict) -> Option<Cipher> {
233 match filter.get_name("CFM")?.0.as_str() {
234 "V2" => Some(Cipher::Rc4),
235 "AESV2" => Some(Cipher::Aesv2),
236 "AESV3" => Some(Cipher::Aesv3),
237 _ => None,
238 }
239}
240
241fn v4_key_length(enc: &Dict) -> usize {
248 let filter_length = ["StmF", "StrF"].iter().find_map(|key| {
249 let name = enc.get_name(key)?;
250 enc.get_dict("CF")?.get_dict(&name.0)?.get_int("Length")
251 });
252 let bytes = match (enc.get_int("Length"), filter_length) {
253 (Some(bits), _) => bits / 8,
254 (None, Some(len)) if len >= 40 => len / 8,
255 (None, Some(len)) => len,
256 (None, None) => 16,
257 };
258 bytes.clamp(5, 16) as usize
259}
260
261fn encrypt_metadata_flag(enc: &Dict) -> bool {
266 enc.get("EncryptMetadata")
267 .and_then(Object::as_bool)
268 .unwrap_or(true)
269}
270
271impl Decryptor {
272 pub fn from_standard(enc: &Dict, id0: &[u8]) -> Option<Decryptor> {
290 Decryptor::from_standard_with_password(enc, id0, b"")
291 }
292
293 pub fn from_standard_with_password_str(
298 enc: &Dict,
299 id0: &[u8],
300 password: &str,
301 ) -> Option<Decryptor> {
302 let dec = Decryptor::from_standard_with_password(enc, id0, password.as_bytes());
303 if dec.is_some() || password.is_ascii() || password.chars().any(|c| (c as u32) > 255) {
304 return dec;
305 }
306 let latin1: Vec<u8> = password.chars().map(|c| c as u8).collect();
307 Decryptor::from_standard_with_password(enc, id0, &latin1)
308 }
309
310 pub fn from_standard_with_password(
318 enc: &Dict,
319 id0: &[u8],
320 password: &[u8],
321 ) -> Option<Decryptor> {
322 if enc.get_name("Filter").map(|n| n.0.as_str()) != Some("Standard") {
323 return None;
324 }
325 let v = enc.get_int("V").unwrap_or(0);
326 let r = enc.get_int("R").unwrap_or(0);
327 let encrypt_metadata = encrypt_metadata_flag(enc);
328 let (key, filters) = match (v, r) {
329 (1 | 2, 2 | 3) => {
331 let n = if v == 1 {
332 5
333 } else {
334 (enc.get_int("Length").unwrap_or(40) / 8).clamp(5, 16) as usize
335 };
336 let key = rc4_family_key(enc, id0, r, n, password)?;
337 (key, CryptFilters::uniform(Cipher::Rc4))
338 }
339 (4, 4) => {
342 let filters = CryptFilters::parse(enc)?;
343 let key = rc4_family_key(enc, id0, r, v4_key_length(enc), password)?;
344 (key, filters)
345 }
346 (5, 5 | 6) => {
349 let filters = CryptFilters::parse(enc)?;
350 let key = aesv3_key(enc, r, password)?;
351 (key, filters)
352 }
353 _ => return None,
354 };
355 Some(Decryptor {
356 key,
357 filters,
358 encrypt_metadata,
359 })
360 }
361
362 pub fn decrypt_object(&self, obj: &mut Object, num: u32, gen: u16) {
379 self.decrypt_in_place(obj, num, gen);
380 }
381
382 fn decrypt_in_place(&self, obj: &mut Object, num: u32, gen: u16) {
395 match obj {
396 Object::String(bytes) => self.apply(self.filters.string, num, gen, bytes),
397 Object::Array(items) => items
398 .iter_mut()
399 .for_each(|it| self.decrypt_in_place(it, num, gen)),
400 Object::Dict(dict) => dict
401 .values_mut()
402 .for_each(|v| self.decrypt_in_place(v, num, gen)),
403 Object::Stream(stream) => {
404 stream
405 .dict
406 .values_mut()
407 .for_each(|v| self.decrypt_in_place(v, num, gen));
408 if !self.encrypt_metadata && is_metadata_stream(&stream.dict) {
409 return;
410 }
411 if let Some(name) = stream_crypt_filter(&stream.dict) {
412 match self.filters.named(&name) {
413 Some(Cipher::Identity) | None => {}
414 Some(cipher) => {
415 stream.data = decrypt_bytes(cipher, &self.key, &stream.data)
416 }
417 }
418 return;
419 }
420 let cipher = if is_embedded_file_stream(&stream.dict) {
421 self.filters.embedded_file
422 } else {
423 self.filters.stream
424 };
425 self.apply(cipher, num, gen, &mut stream.data);
426 }
427 _ => {}
428 }
429 }
430
431 fn apply(&self, cipher: Cipher, num: u32, gen: u16, data: &mut Vec<u8>) {
435 let key = match cipher {
436 Cipher::Identity => return,
437 Cipher::Aesv3 => self.key.clone(), Cipher::Rc4 | Cipher::Aesv2 => self.object_key(cipher, num, gen),
439 };
440 *data = decrypt_bytes(cipher, &key, data);
441 }
442
443 fn object_key(&self, cipher: Cipher, num: u32, gen: u16) -> Vec<u8> {
450 let mut input = Vec::with_capacity(self.key.len() + 9);
451 input.extend_from_slice(&self.key);
452 input.extend_from_slice(&num.to_le_bytes()[..3]);
453 input.extend_from_slice(&gen.to_le_bytes()[..2]);
454 if cipher == Cipher::Aesv2 {
455 input.extend_from_slice(b"sAlT");
456 }
457 let digest = md5(&input);
458 let n = match cipher {
459 Cipher::Aesv2 => 16,
460 _ => (self.key.len() + 5).min(16),
461 };
462 digest[..n].to_vec()
463 }
464}
465
466fn is_metadata_stream(dict: &Dict) -> bool {
468 dict.get_name("Type").map(|n| n.0.as_str()) == Some("Metadata")
469}
470
471fn is_embedded_file_stream(dict: &Dict) -> bool {
473 dict.get_name("Type").map(|n| n.0.as_str()) == Some("EmbeddedFile")
474}
475
476fn decrypt_bytes(cipher: Cipher, key: &[u8], data: &[u8]) -> Vec<u8> {
478 match cipher {
479 Cipher::Identity => data.to_vec(),
480 Cipher::Rc4 => rc4(key, data),
481 Cipher::Aesv2 | Cipher::Aesv3 => aes_cbc_decrypt(key, data),
482 }
483}
484
485fn pad_password(password: &[u8]) -> [u8; 32] {
491 let mut out = [0u8; 32];
492 let n = password.len().min(32);
493 out[..n].copy_from_slice(&password[..n]);
494 out[n..].copy_from_slice(&PAD[..32 - n]);
495 out
496}
497
498fn rc4_family_key(enc: &Dict, id0: &[u8], r: i64, n: usize, password: &[u8]) -> Option<Vec<u8>> {
505 let u = enc.get("U").and_then(Object::as_str_bytes)?;
506 if let Some(key) = md5_file_key(enc, id0, r, n, &pad_password(password)) {
507 if verify_user_password(&key, r, id0, u) {
508 return Some(key);
509 }
510 }
511 let o = enc.get("O").and_then(Object::as_str_bytes)?;
515 if o.len() < 32 {
516 return None;
517 }
518 let mut d = md5(&pad_password(password));
519 if r >= 3 {
520 for _ in 0..50 {
521 d = md5(&d[..n]);
522 }
523 }
524 let okey = &d[..n];
525 let recovered = if r == 2 {
526 rc4(okey, &o[..32])
527 } else {
528 let mut x = o[..32].to_vec();
529 for i in (1u8..=19).rev() {
530 let keyed: Vec<u8> = okey.iter().map(|b| b ^ i).collect();
531 x = rc4(&keyed, &x);
532 }
533 rc4(okey, &x)
534 };
535 let padded: [u8; 32] = recovered.get(..32)?.try_into().ok()?;
536 let key = md5_file_key(enc, id0, r, n, &padded)?;
537 verify_user_password(&key, r, id0, u).then_some(key)
538}
539
540fn md5_file_key(enc: &Dict, id0: &[u8], r: i64, n: usize, padded: &[u8; 32]) -> Option<Vec<u8>> {
544 let o = enc.get("O").and_then(Object::as_str_bytes)?;
545 if o.len() < 32 {
546 return None;
547 }
548 let p = enc.get_int("P")?;
549 let mut input = Vec::with_capacity(32 + 32 + 4 + id0.len() + 4);
550 input.extend_from_slice(padded);
551 input.extend_from_slice(&o[..32]);
552 input.extend_from_slice(&(p as i32 as u32).to_le_bytes()); input.extend_from_slice(id0);
554 if r >= 4 && !encrypt_metadata_flag(enc) {
556 input.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
557 }
558 let mut digest = md5(&input);
559 if r >= 3 {
560 for _ in 0..50 {
561 digest = md5(&digest[..n]);
562 }
563 }
564 Some(digest[..n].to_vec())
565}
566
567fn verify_user_password(key: &[u8], r: i64, id0: &[u8], u: &[u8]) -> bool {
571 if r == 2 {
572 let computed = rc4(key, &PAD);
574 u.len() >= 32 && computed == u[..32]
575 } else {
576 let mut input = Vec::with_capacity(32 + id0.len());
578 input.extend_from_slice(&PAD);
579 input.extend_from_slice(id0);
580 let mut x = md5(&input).to_vec();
581 x = rc4(key, &x);
582 for i in 1u8..=19 {
583 let keyed: Vec<u8> = key.iter().map(|b| b ^ i).collect();
584 x = rc4(&keyed, &x);
585 }
586 u.len() >= 16 && x[..16] == u[..16]
588 }
589}
590
591fn rc4(key: &[u8], data: &[u8]) -> Vec<u8> {
593 debug_assert!(!key.is_empty());
594 let mut s: [u8; 256] = core::array::from_fn(|i| i as u8);
595 let mut j = 0u8;
596 for i in 0..256 {
597 j = j.wrapping_add(s[i]).wrapping_add(key[i % key.len()]);
598 s.swap(i, j as usize);
599 }
600 let mut out = Vec::with_capacity(data.len());
601 let (mut i, mut j) = (0u8, 0u8);
602 for &byte in data {
603 i = i.wrapping_add(1);
604 j = j.wrapping_add(s[i as usize]);
605 s.swap(i as usize, j as usize);
606 let k = s[s[i as usize].wrapping_add(s[j as usize]) as usize];
607 out.push(byte ^ k);
608 }
609 out
610}
611
612#[rustfmt::skip]
616const AES_SBOX: [u8; 256] = [
617 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
618 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
619 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
620 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
621 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
622 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
623 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
624 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
625 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
626 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
627 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
628 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
629 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
630 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
631 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
632 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
633];
634
635const AES_RCON: [u8; 11] = [
637 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
638];
639
640fn aes_inv_sbox() -> [u8; 256] {
642 let mut inv = [0u8; 256];
643 for (i, &s) in AES_SBOX.iter().enumerate() {
644 inv[s as usize] = i as u8;
645 }
646 inv
647}
648
649fn gmul(mut a: u8, mut b: u8) -> u8 {
651 let mut p = 0u8;
652 for _ in 0..8 {
653 if b & 1 != 0 {
654 p ^= a;
655 }
656 let hi = a & 0x80;
657 a <<= 1;
658 if hi != 0 {
659 a ^= 0x1b;
660 }
661 b >>= 1;
662 }
663 p
664}
665
666fn aes_expand_key(key: &[u8]) -> Vec<[u8; 16]> {
669 let nk = key.len() / 4; let nr = nk + 6;
671 let total = 4 * (nr + 1);
672 let mut w: Vec<[u8; 4]> = Vec::with_capacity(total);
673 for i in 0..nk {
674 w.push([key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]);
675 }
676 for i in nk..total {
677 let mut t = w[i - 1];
678 if i.is_multiple_of(nk) {
679 t = [t[1], t[2], t[3], t[0]]; for b in &mut t {
681 *b = AES_SBOX[*b as usize]; }
683 t[0] ^= AES_RCON[i / nk];
684 } else if nk > 6 && i % nk == 4 {
685 for b in &mut t {
686 *b = AES_SBOX[*b as usize];
687 }
688 }
689 let prev = w[i - nk];
690 w.push([
691 prev[0] ^ t[0],
692 prev[1] ^ t[1],
693 prev[2] ^ t[2],
694 prev[3] ^ t[3],
695 ]);
696 }
697 (0..=nr)
698 .map(|round| {
699 let mut rk = [0u8; 16];
700 for c in 0..4 {
701 rk[4 * c..4 * c + 4].copy_from_slice(&w[4 * round + c]);
702 }
703 rk
704 })
705 .collect()
706}
707
708fn add_round_key(s: &mut [u8; 16], rk: &[u8; 16]) {
709 for (b, k) in s.iter_mut().zip(rk) {
710 *b ^= k;
711 }
712}
713
714fn shift_rows(s: &mut [u8; 16]) {
715 let o = *s;
716 for r in 1..4 {
717 for c in 0..4 {
718 s[r + 4 * c] = o[r + 4 * ((c + r) % 4)];
719 }
720 }
721}
722
723fn inv_shift_rows(s: &mut [u8; 16]) {
724 let o = *s;
725 for r in 1..4 {
726 for c in 0..4 {
727 s[r + 4 * c] = o[r + 4 * ((c + 4 - r) % 4)];
728 }
729 }
730}
731
732fn mix_columns(s: &mut [u8; 16]) {
733 for c in 0..4 {
734 let i = 4 * c;
735 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
736 s[i] = gmul(a0, 2) ^ gmul(a1, 3) ^ a2 ^ a3;
737 s[i + 1] = a0 ^ gmul(a1, 2) ^ gmul(a2, 3) ^ a3;
738 s[i + 2] = a0 ^ a1 ^ gmul(a2, 2) ^ gmul(a3, 3);
739 s[i + 3] = gmul(a0, 3) ^ a1 ^ a2 ^ gmul(a3, 2);
740 }
741}
742
743fn inv_mix_columns(s: &mut [u8; 16]) {
744 for c in 0..4 {
745 let i = 4 * c;
746 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
747 s[i] = gmul(a0, 14) ^ gmul(a1, 11) ^ gmul(a2, 13) ^ gmul(a3, 9);
748 s[i + 1] = gmul(a0, 9) ^ gmul(a1, 14) ^ gmul(a2, 11) ^ gmul(a3, 13);
749 s[i + 2] = gmul(a0, 13) ^ gmul(a1, 9) ^ gmul(a2, 14) ^ gmul(a3, 11);
750 s[i + 3] = gmul(a0, 11) ^ gmul(a1, 13) ^ gmul(a2, 9) ^ gmul(a3, 14);
751 }
752}
753
754fn aes_encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
755 #[cfg(target_arch = "aarch64")]
756 if std::arch::is_aarch64_feature_detected!("aes") {
757 unsafe { aes_hw::encrypt_block(s, rks) };
759 return;
760 }
761 #[cfg(target_arch = "x86_64")]
762 if std::arch::is_x86_feature_detected!("aes") {
763 unsafe { aes_hw::encrypt_block(s, rks) };
765 return;
766 }
767 aes_encrypt_block_soft(s, rks);
768}
769
770fn aes_encrypt_block_soft(s: &mut [u8; 16], rks: &[[u8; 16]]) {
772 let nr = rks.len() - 1;
773 add_round_key(s, &rks[0]);
774 for rk in &rks[1..nr] {
775 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
776 shift_rows(s);
777 mix_columns(s);
778 add_round_key(s, rk);
779 }
780 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
781 shift_rows(s);
782 add_round_key(s, &rks[nr]);
783}
784
785fn aes_decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]], inv_sbox: &[u8; 256]) {
786 #[cfg(target_arch = "aarch64")]
787 if std::arch::is_aarch64_feature_detected!("aes") {
788 unsafe { aes_hw::decrypt_block(s, rks) };
790 return;
791 }
792 #[cfg(target_arch = "x86_64")]
793 if std::arch::is_x86_feature_detected!("aes") {
794 unsafe { aes_hw::decrypt_block(s, rks) };
796 return;
797 }
798 aes_decrypt_block_soft(s, rks, inv_sbox);
799}
800
801fn aes_decrypt_block_soft(s: &mut [u8; 16], rks: &[[u8; 16]], inv_sbox: &[u8; 256]) {
803 let nr = rks.len() - 1;
804 add_round_key(s, &rks[nr]);
805 for rk in rks[1..nr].iter().rev() {
806 inv_shift_rows(s);
807 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
808 add_round_key(s, rk);
809 inv_mix_columns(s);
810 }
811 inv_shift_rows(s);
812 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
813 add_round_key(s, &rks[0]);
814}
815
816#[cfg(target_arch = "aarch64")]
824mod aes_hw {
825 use core::arch::aarch64::{
826 vaesdq_u8, vaeseq_u8, vaesimcq_u8, vaesmcq_u8, veorq_u8, vld1q_u8, vmovq_n_u8, vst1q_u8,
827 };
828
829 #[target_feature(enable = "aes")]
832 pub unsafe fn encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
833 let nr = rks.len() - 1;
834 let mut x = vld1q_u8(s.as_ptr());
838 for rk in &rks[..nr - 1] {
839 x = vaesmcq_u8(vaeseq_u8(x, vld1q_u8(rk.as_ptr())));
840 }
841 x = vaeseq_u8(x, vld1q_u8(rks[nr - 1].as_ptr()));
842 x = veorq_u8(x, vld1q_u8(rks[nr].as_ptr()));
843 vst1q_u8(s.as_mut_ptr(), x);
844 }
845
846 #[target_feature(enable = "aes")]
849 pub unsafe fn decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
850 let nr = rks.len() - 1;
851 let zero = vmovq_n_u8(0);
855 let mut x = vld1q_u8(s.as_ptr());
856 x = veorq_u8(x, vld1q_u8(rks[nr].as_ptr()));
857 for rk in rks[1..nr].iter().rev() {
858 x = vaesdq_u8(x, zero);
859 x = veorq_u8(x, vld1q_u8(rk.as_ptr()));
860 x = vaesimcq_u8(x);
861 }
862 x = vaesdq_u8(x, zero);
863 x = veorq_u8(x, vld1q_u8(rks[0].as_ptr()));
864 vst1q_u8(s.as_mut_ptr(), x);
865 }
866}
867
868#[cfg(target_arch = "x86_64")]
870mod aes_hw {
871 use core::arch::x86_64::{
872 __m128i, _mm_aesdec_si128, _mm_aesdeclast_si128, _mm_aesenc_si128, _mm_aesenclast_si128,
873 _mm_aesimc_si128, _mm_loadu_si128, _mm_storeu_si128, _mm_xor_si128,
874 };
875
876 #[target_feature(enable = "aes")]
879 pub unsafe fn encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
880 let nr = rks.len() - 1;
881 let mut x = _mm_loadu_si128(s.as_ptr().cast::<__m128i>());
882 x = _mm_xor_si128(x, _mm_loadu_si128(rks[0].as_ptr().cast::<__m128i>()));
883 for rk in &rks[1..nr] {
884 x = _mm_aesenc_si128(x, _mm_loadu_si128(rk.as_ptr().cast::<__m128i>()));
885 }
886 x = _mm_aesenclast_si128(x, _mm_loadu_si128(rks[nr].as_ptr().cast::<__m128i>()));
887 _mm_storeu_si128(s.as_mut_ptr().cast::<__m128i>(), x);
888 }
889
890 #[target_feature(enable = "aes")]
893 pub unsafe fn decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
894 let nr = rks.len() - 1;
895 let mut x = _mm_loadu_si128(s.as_ptr().cast::<__m128i>());
898 x = _mm_xor_si128(x, _mm_loadu_si128(rks[nr].as_ptr().cast::<__m128i>()));
899 for rk in rks[1..nr].iter().rev() {
900 let dk = _mm_aesimc_si128(_mm_loadu_si128(rk.as_ptr().cast::<__m128i>()));
901 x = _mm_aesdec_si128(x, dk);
902 }
903 x = _mm_aesdeclast_si128(x, _mm_loadu_si128(rks[0].as_ptr().cast::<__m128i>()));
904 _mm_storeu_si128(s.as_mut_ptr().cast::<__m128i>(), x);
905 }
906}
907
908fn aes_cbc_decrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
911 if !matches!(key.len(), 16 | 32) {
914 return Vec::new();
915 }
916 if data.is_empty() || !data.len().is_multiple_of(16) || iv.len() < 16 {
917 return Vec::new();
918 }
919 let rks = aes_expand_key(key);
920 let inv_sbox = aes_inv_sbox();
921 let mut prev = [0u8; 16];
922 prev.copy_from_slice(&iv[..16]);
923 let mut out = Vec::with_capacity(data.len());
924 for chunk in data.as_chunks::<16>().0 {
925 let mut block = [0u8; 16];
926 block.copy_from_slice(chunk);
927 let cipher = block;
928 aes_decrypt_block(&mut block, &rks, &inv_sbox);
929 for (b, p) in block.iter_mut().zip(&prev) {
930 *b ^= p;
931 }
932 out.extend_from_slice(&block);
933 prev = cipher;
934 }
935 out
936}
937
938fn aes_cbc_encrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
941 let rks = aes_expand_key(key);
942 let mut prev = [0u8; 16];
943 prev.copy_from_slice(&iv[..16]);
944 let mut out = Vec::with_capacity(data.len());
945 for chunk in data.as_chunks::<16>().0 {
946 let mut block = [0u8; 16];
947 for ((b, c), p) in block.iter_mut().zip(chunk).zip(&prev) {
948 *b = c ^ p;
949 }
950 aes_encrypt_block(&mut block, &rks);
951 out.extend_from_slice(&block);
952 prev = block;
953 }
954 out
955}
956
957fn aes_cbc_decrypt(key: &[u8], data: &[u8]) -> Vec<u8> {
961 if data.len() < 16 {
962 return Vec::new();
963 }
964 let (iv, ct) = data.split_at(16);
965 let mut out = aes_cbc_decrypt_blocks(key, iv, ct);
966 strip_pkcs7(&mut out);
967 out
968}
969
970fn strip_pkcs7(data: &mut Vec<u8>) {
972 let Some(&pad) = data.last() else {
973 return;
974 };
975 let pad = pad as usize;
976 if (1..=16).contains(&pad) && pad <= data.len() {
977 let start = data.len() - pad;
978 if data[start..].iter().all(|&b| b as usize == pad) {
979 data.truncate(start);
980 }
981 }
982}
983
984fn pkcs7_pad(data: &[u8]) -> Vec<u8> {
988 let pad = 16 - data.len() % 16;
989 let mut out = data.to_vec();
990 out.resize(data.len() + pad, pad as u8);
991 out
992}
993
994fn aes_cbc_encrypt(
998 key: &[u8],
999 rng: &mut dyn FnMut(&mut [u8]) -> crate::error::Result<()>,
1000 data: &[u8],
1001) -> crate::error::Result<Vec<u8>> {
1002 let mut iv = [0u8; 16];
1003 rng(&mut iv)?;
1004 let mut out = iv.to_vec();
1005 out.extend_from_slice(&aes_cbc_encrypt_blocks(key, &iv, &pkcs7_pad(data)));
1006 Ok(out)
1007}
1008
1009#[rustfmt::skip]
1012const SHA256_K: [u32; 64] = [
1013 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
1014 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
1015 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
1016 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
1017 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
1018 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
1019 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
1020 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
1021];
1022
1023#[derive(Debug, Clone)]
1028pub struct Sha256 {
1029 h: [u32; 8],
1030 tail: [u8; 64],
1031 tail_len: usize,
1032 total: u64,
1033}
1034
1035impl Default for Sha256 {
1036 fn default() -> Sha256 {
1037 Sha256::new()
1038 }
1039}
1040
1041impl Sha256 {
1042 pub fn new() -> Sha256 {
1044 Sha256 {
1045 h: [
1046 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
1047 0x5be0cd19,
1048 ],
1049 tail: [0u8; 64],
1050 tail_len: 0,
1051 total: 0,
1052 }
1053 }
1054
1055 pub fn update(&mut self, input: &[u8]) {
1060 self.total = self.total.wrapping_add(input.len() as u64);
1061 let mut input = input;
1062 if self.tail_len > 0 {
1063 let take = input.len().min(64 - self.tail_len);
1064 self.tail[self.tail_len..self.tail_len + take].copy_from_slice(&input[..take]);
1065 self.tail_len += take;
1066 input = &input[take..];
1067 if self.tail_len < 64 {
1068 return;
1069 }
1070 let block = self.tail;
1071 sha256_compress(&mut self.h, &block);
1072 self.tail_len = 0;
1073 }
1074 let (blocks, rest) = input.as_chunks::<64>();
1075 for block in blocks {
1076 sha256_compress(&mut self.h, block);
1077 }
1078 self.tail[..rest.len()].copy_from_slice(rest);
1079 self.tail_len = rest.len();
1080 }
1081
1082 pub fn finalize(mut self) -> [u8; 32] {
1084 let mut pad = [0u8; 128];
1087 pad[..self.tail_len].copy_from_slice(&self.tail[..self.tail_len]);
1088 pad[self.tail_len] = 0x80;
1089 let padded = if self.tail_len < 56 { 64 } else { 128 };
1090 let bitlen = self.total.wrapping_mul(8);
1091 pad[padded - 8..padded].copy_from_slice(&bitlen.to_be_bytes());
1092 for block in pad[..padded].as_chunks::<64>().0 {
1093 sha256_compress(&mut self.h, block);
1094 }
1095 let mut out = [0u8; 32];
1096 for (i, word) in self.h.iter().enumerate() {
1097 out[4 * i..4 * i + 4].copy_from_slice(&word.to_be_bytes());
1098 }
1099 out
1100 }
1101}
1102
1103pub fn sha256(input: &[u8]) -> [u8; 32] {
1105 let mut hasher = Sha256::new();
1106 hasher.update(input);
1107 hasher.finalize()
1108}
1109
1110fn sha256_compress(h: &mut [u32; 8], block: &[u8; 64]) {
1111 #[cfg(target_arch = "aarch64")]
1112 if std::arch::is_aarch64_feature_detected!("sha2") {
1113 unsafe { sha_hw::compress256(h, block) };
1115 return;
1116 }
1117 sha256_compress_soft(h, block);
1118}
1119
1120fn sha256_compress_soft(h: &mut [u32; 8], block: &[u8; 64]) {
1122 let mut w = [0u32; 64];
1123 for (word, bytes) in w.iter_mut().zip(block.as_chunks::<4>().0) {
1124 *word = u32::from_be_bytes(*bytes);
1125 }
1126 for i in 16..64 {
1127 let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
1128 let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
1129 w[i] = w[i - 16]
1130 .wrapping_add(s0)
1131 .wrapping_add(w[i - 7])
1132 .wrapping_add(s1);
1133 }
1134 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = *h;
1135 for (k, wi) in SHA256_K.iter().zip(&w) {
1136 let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
1137 let ch = (e & f) ^ ((!e) & g);
1138 let t1 = hh
1139 .wrapping_add(s1)
1140 .wrapping_add(ch)
1141 .wrapping_add(*k)
1142 .wrapping_add(*wi);
1143 let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
1144 let maj = (a & b) ^ (a & c) ^ (b & c);
1145 let t2 = s0.wrapping_add(maj);
1146 hh = g;
1147 g = f;
1148 f = e;
1149 e = d.wrapping_add(t1);
1150 d = c;
1151 c = b;
1152 b = a;
1153 a = t1.wrapping_add(t2);
1154 }
1155 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
1156 *hv = hv.wrapping_add(v);
1157 }
1158}
1159
1160#[rustfmt::skip]
1161const SHA512_K: [u64; 80] = [
1162 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
1163 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
1164 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
1165 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
1166 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
1167 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
1168 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
1169 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
1170 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
1171 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
1172 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
1173 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
1174 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
1175 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
1176 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
1177 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
1178 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
1179 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
1180 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
1181 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
1182];
1183
1184fn sha512_core(input: &[u8], mut h: [u64; 8]) -> [u64; 8] {
1185 let (blocks, tail) = input.as_chunks::<128>();
1186 for block in blocks {
1187 sha512_compress(&mut h, block);
1188 }
1189 let mut pad = [0u8; 256];
1193 pad[..tail.len()].copy_from_slice(tail);
1194 pad[tail.len()] = 0x80;
1195 let padded = if tail.len() < 112 { 128 } else { 256 };
1196 let bitlen = (input.len() as u128).wrapping_mul(8);
1197 pad[padded - 16..padded].copy_from_slice(&bitlen.to_be_bytes());
1198 for block in pad[..padded].as_chunks::<128>().0 {
1199 sha512_compress(&mut h, block);
1200 }
1201 h
1202}
1203
1204fn sha512_compress(h: &mut [u64; 8], block: &[u8; 128]) {
1205 #[cfg(target_arch = "aarch64")]
1206 if std::arch::is_aarch64_feature_detected!("sha3") {
1207 unsafe { sha_hw::compress512(h, block) };
1210 return;
1211 }
1212 sha512_compress_soft(h, block);
1213}
1214
1215fn sha512_compress_soft(h: &mut [u64; 8], block: &[u8; 128]) {
1217 let mut w = [0u64; 80];
1218 for (word, bytes) in w.iter_mut().zip(block.as_chunks::<8>().0) {
1219 *word = u64::from_be_bytes(*bytes);
1220 }
1221 for i in 16..80 {
1222 let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
1223 let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
1224 w[i] = w[i - 16]
1225 .wrapping_add(s0)
1226 .wrapping_add(w[i - 7])
1227 .wrapping_add(s1);
1228 }
1229 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = *h;
1230 for (k, wi) in SHA512_K.iter().zip(&w) {
1231 let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
1232 let ch = (e & f) ^ ((!e) & g);
1233 let t1 = hh
1234 .wrapping_add(s1)
1235 .wrapping_add(ch)
1236 .wrapping_add(*k)
1237 .wrapping_add(*wi);
1238 let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
1239 let maj = (a & b) ^ (a & c) ^ (b & c);
1240 let t2 = s0.wrapping_add(maj);
1241 hh = g;
1242 g = f;
1243 f = e;
1244 e = d.wrapping_add(t1);
1245 d = c;
1246 c = b;
1247 b = a;
1248 a = t1.wrapping_add(t2);
1249 }
1250 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
1251 *hv = hv.wrapping_add(v);
1252 }
1253}
1254
1255#[cfg(target_arch = "aarch64")]
1264mod sha_hw {
1265 use core::arch::aarch64::{
1266 uint32x4_t, uint64x2_t, vaddq_u32, vaddq_u64, vextq_u64, vld1q_u32, vld1q_u64, vld1q_u8,
1267 vreinterpretq_u32_u8, vreinterpretq_u64_u8, vrev32q_u8, vrev64q_u8, vsha256h2q_u32,
1268 vsha256hq_u32, vsha256su0q_u32, vsha256su1q_u32, vsha512h2q_u64, vsha512hq_u64,
1269 vsha512su0q_u64, vsha512su1q_u64, vst1q_u32,
1270 };
1271
1272 use super::{SHA256_K, SHA512_K};
1273
1274 #[target_feature(enable = "sha2")]
1277 pub unsafe fn compress256(h: &mut [u32; 8], block: &[u8; 64]) {
1278 let mut abcd = vld1q_u32(h.as_ptr());
1279 let mut efgh = vld1q_u32(h.as_ptr().add(4));
1280 let saved = (abcd, efgh);
1281 let mut w: [uint32x4_t; 4] = [
1282 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr()))),
1283 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(16)))),
1284 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(32)))),
1285 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(48)))),
1286 ];
1287 for step in 0..16 {
1288 let wk = vaddq_u32(w[step % 4], vld1q_u32(SHA256_K.as_ptr().add(4 * step)));
1289 if step < 12 {
1291 w[step % 4] = vsha256su1q_u32(
1292 vsha256su0q_u32(w[step % 4], w[(step + 1) % 4]),
1293 w[(step + 2) % 4],
1294 w[(step + 3) % 4],
1295 );
1296 }
1297 let prev = abcd;
1298 abcd = vsha256hq_u32(abcd, efgh, wk);
1299 efgh = vsha256h2q_u32(efgh, prev, wk);
1300 }
1301 vst1q_u32(h.as_mut_ptr(), vaddq_u32(abcd, saved.0));
1302 vst1q_u32(h.as_mut_ptr().add(4), vaddq_u32(efgh, saved.1));
1303 }
1304
1305 #[target_feature(enable = "sha2,sha3")]
1308 pub unsafe fn compress512(h: &mut [u64; 8], block: &[u8; 128]) {
1309 let mut s: [uint64x2_t; 4] = [
1313 vld1q_u64(h.as_ptr()),
1314 vld1q_u64(h.as_ptr().add(2)),
1315 vld1q_u64(h.as_ptr().add(4)),
1316 vld1q_u64(h.as_ptr().add(6)),
1317 ];
1318 let saved = s;
1319 let mut w: [uint64x2_t; 8] = [core::mem::zeroed(); 8];
1320 for (pair, bytes) in w.iter_mut().zip(block.as_chunks::<16>().0) {
1321 *pair = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(bytes.as_ptr())));
1322 }
1323 for step in 0..40 {
1324 let r = 3 - (step % 4);
1325 let wk = vaddq_u64(w[step % 8], vld1q_u64(SHA512_K.as_ptr().add(2 * step)));
1326 let sum = vaddq_u64(vextq_u64::<1>(wk, wk), s[r]);
1327 let im = vsha512hq_u64(
1328 sum,
1329 vextq_u64::<1>(s[(r + 3) % 4], s[r]),
1330 vextq_u64::<1>(s[(r + 2) % 4], s[(r + 3) % 4]),
1331 );
1332 let updated = vsha512h2q_u64(im, s[(r + 2) % 4], s[(r + 1) % 4]);
1333 s[(r + 2) % 4] = vaddq_u64(s[(r + 2) % 4], im);
1334 s[r] = updated;
1335 if step < 32 {
1337 let i = step % 8;
1338 w[i] = vsha512su1q_u64(
1339 vsha512su0q_u64(w[i], w[(i + 1) % 8]),
1340 w[(i + 7) % 8],
1341 vextq_u64::<1>(w[(i + 4) % 8], w[(i + 5) % 8]),
1342 );
1343 }
1344 }
1345 for (i, (out, kept)) in s.iter().zip(saved).enumerate() {
1346 let summed = vaddq_u64(*out, kept);
1347 core::arch::aarch64::vst1q_u64(h.as_mut_ptr().add(2 * i), summed);
1348 }
1349 }
1350}
1351
1352fn sha512(input: &[u8]) -> Vec<u8> {
1353 let h = sha512_core(
1354 input,
1355 [
1356 0x6a09e667f3bcc908,
1357 0xbb67ae8584caa73b,
1358 0x3c6ef372fe94f82b,
1359 0xa54ff53a5f1d36f1,
1360 0x510e527fade682d1,
1361 0x9b05688c2b3e6c1f,
1362 0x1f83d9abfb41bd6b,
1363 0x5be0cd19137e2179,
1364 ],
1365 );
1366 h.iter().flat_map(|w| w.to_be_bytes()).collect()
1367}
1368
1369fn sha384(input: &[u8]) -> Vec<u8> {
1370 let h = sha512_core(
1371 input,
1372 [
1373 0xcbbb9d5dc1059ed8,
1374 0x629a292a367cd507,
1375 0x9159015a3070dd17,
1376 0x152fecd8f70e5939,
1377 0x67332667ffc00b31,
1378 0x8eb44a8768581511,
1379 0xdb0c2e0d64f98fa7,
1380 0x47b5481dbefa4fa4,
1381 ],
1382 );
1383 h.iter().take(6).flat_map(|w| w.to_be_bytes()).collect()
1384}
1385
1386fn aesv3_key(enc: &Dict, r: i64, password: &[u8]) -> Option<Vec<u8>> {
1392 let pw = &password[..password.len().min(127)];
1393 let u = enc.get("U").and_then(Object::as_str_bytes)?;
1394 if u.len() < 48 {
1395 return None;
1396 }
1397 let perms = enc.get("Perms").and_then(Object::as_str_bytes);
1405 let o = enc.get("O").and_then(Object::as_str_bytes);
1406 if let Some(perms) = perms.filter(|p| p.len() >= 16) {
1407 if let Some(ue) = enc.get("UE").and_then(Object::as_str_bytes) {
1408 if ue.len() >= 32 {
1409 let intermediate = hash_2b(r, pw, &u[40..48], &[]);
1410 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &ue[..32]);
1411 if file_key.len() == 32 && perms_marker_valid(&file_key, perms) {
1412 return Some(file_key);
1413 }
1414 }
1415 }
1416 if let (Some(o), Some(oe)) = (o, enc.get("OE").and_then(Object::as_str_bytes)) {
1417 if o.len() >= 48 && oe.len() >= 32 {
1418 let intermediate = hash_2b(r, pw, &o[40..48], &u[..48]);
1419 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &oe[..32]);
1420 if file_key.len() == 32 && perms_marker_valid(&file_key, perms) {
1421 return Some(file_key);
1422 }
1423 }
1424 }
1425 }
1426 if let Some(ue) = enc.get("UE").and_then(Object::as_str_bytes) {
1427 if ue.len() >= 32 && hash_2b(r, pw, &u[32..40], &[])[..32] == u[..32] {
1428 let intermediate = hash_2b(r, pw, &u[40..48], &[]);
1429 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &ue[..32]);
1430 if file_key.len() == 32 {
1431 return Some(file_key);
1432 }
1433 }
1434 }
1435 let o = o?;
1436 let oe = enc.get("OE").and_then(Object::as_str_bytes)?;
1437 if o.len() < 48 || oe.len() < 32 {
1438 return None;
1439 }
1440 if hash_2b(r, pw, &o[32..40], &u[..48])[..32] != o[..32] {
1441 return None;
1442 }
1443 let intermediate = hash_2b(r, pw, &o[40..48], &u[..48]);
1444 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &oe[..32]);
1445 (file_key.len() == 32).then_some(file_key)
1446}
1447
1448fn perms_marker_valid(file_key: &[u8], perms: &[u8]) -> bool {
1451 let rks = aes_expand_key(file_key);
1452 let inv_sbox = aes_inv_sbox();
1453 let mut block = [0u8; 16];
1454 block.copy_from_slice(&perms[..16]);
1455 aes_decrypt_block(&mut block, &rks, &inv_sbox);
1456 &block[9..12] == b"adb"
1457}
1458
1459fn hash_2b(r: i64, password: &[u8], salt: &[u8], udata: &[u8]) -> Vec<u8> {
1462 let mut seed = Vec::with_capacity(password.len() + salt.len() + udata.len());
1463 seed.extend_from_slice(password);
1464 seed.extend_from_slice(salt);
1465 seed.extend_from_slice(udata);
1466 let mut k = sha256(&seed).to_vec();
1467 if r < 6 {
1468 return k; }
1470 let mut round = 0usize;
1471 let mut k1 = Vec::with_capacity(64 * (password.len() + 64 + udata.len()));
1472 loop {
1473 k1.clear();
1474 for _ in 0..64 {
1475 k1.extend_from_slice(password);
1476 k1.extend_from_slice(&k);
1477 k1.extend_from_slice(udata);
1478 }
1479 let e = aes_cbc_encrypt_blocks(&k[..16], &k[16..32], &k1);
1480 let modulus = e[..16].iter().map(|&b| u32::from(b)).sum::<u32>() % 3;
1481 k = match modulus {
1482 0 => sha256(&e).to_vec(),
1483 1 => sha384(&e),
1484 _ => sha512(&e),
1485 };
1486 round += 1;
1487 if round >= 64
1488 && e.last()
1489 .is_some_and(|&last| usize::from(last) <= round - 32)
1490 {
1491 break;
1492 }
1493 }
1494 k.truncate(32);
1495 k
1496}
1497
1498pub(crate) struct KeyMaterial {
1502 file_key: [u8; 32],
1503 u: Vec<u8>,
1504 ue: Vec<u8>,
1505 o: Vec<u8>,
1506 oe: Vec<u8>,
1507 perms: Vec<u8>,
1508}
1509
1510pub(crate) fn r6_key_material<E>(
1517 user_pw: &[u8],
1518 owner_pw: &[u8],
1519 p: i32,
1520 encrypt_metadata: bool,
1521 rng: &mut dyn FnMut(&mut [u8]) -> std::result::Result<(), E>,
1522) -> std::result::Result<KeyMaterial, E> {
1523 let user_pw = &user_pw[..user_pw.len().min(127)];
1524 let owner_pw = &owner_pw[..owner_pw.len().min(127)];
1525
1526 let mut file_key = [0u8; 32];
1527 rng(&mut file_key)?;
1528
1529 let mut user_salt = [0u8; 16];
1532 rng(&mut user_salt)?;
1533 let mut u = hash_2b(6, user_pw, &user_salt[..8], &[]);
1534 u.extend_from_slice(&user_salt);
1535 let user_intermediate = hash_2b(6, user_pw, &user_salt[8..], &[]);
1536 let ue = aes_cbc_encrypt_blocks(&user_intermediate, &[0u8; 16], &file_key);
1537
1538 let mut owner_salt = [0u8; 16];
1541 rng(&mut owner_salt)?;
1542 let mut o = hash_2b(6, owner_pw, &owner_salt[..8], &u[..48]);
1543 o.extend_from_slice(&owner_salt);
1544 let owner_intermediate = hash_2b(6, owner_pw, &owner_salt[8..], &u[..48]);
1545 let oe = aes_cbc_encrypt_blocks(&owner_intermediate, &[0u8; 16], &file_key);
1546
1547 let mut perms_block = [0u8; 16];
1550 perms_block[..4].copy_from_slice(&p.to_le_bytes());
1551 perms_block[4..8].copy_from_slice(&[0xff; 4]);
1552 perms_block[8] = if encrypt_metadata { b'T' } else { b'F' };
1553 perms_block[9..12].copy_from_slice(b"adb");
1554 rng(&mut perms_block[12..])?;
1555 aes_encrypt_block(&mut perms_block, &aes_expand_key(&file_key));
1556
1557 Ok(KeyMaterial {
1558 file_key,
1559 u,
1560 ue,
1561 o,
1562 oe,
1563 perms: perms_block.to_vec(),
1564 })
1565}
1566
1567#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
1572pub(crate) fn fill_os_random(buf: &mut [u8]) -> crate::error::Result<()> {
1573 getrandom::fill(buf).map_err(|e| crate::error::Error::RandomUnavailable(e.to_string()))
1574}
1575
1576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1581pub struct Permissions {
1582 pub print: bool,
1585 pub modify: bool,
1588 pub copy: bool,
1590 pub annotate: bool,
1593 pub fill_forms: bool,
1596 pub accessibility: bool,
1598 pub assemble: bool,
1601 pub print_hires: bool,
1604}
1605
1606pub const PERMISSION_NAMES: [&str; 8] = [
1611 "print",
1612 "modify",
1613 "copy",
1614 "annotate",
1615 "fill-forms",
1616 "accessibility",
1617 "assemble",
1618 "print-hires",
1619];
1620
1621impl Permissions {
1622 pub fn all() -> Permissions {
1624 Permissions {
1625 print: true,
1626 modify: true,
1627 copy: true,
1628 annotate: true,
1629 fill_forms: true,
1630 accessibility: true,
1631 assemble: true,
1632 print_hires: true,
1633 }
1634 }
1635
1636 pub fn from_names<'a>(names: impl IntoIterator<Item = &'a str>) -> Result<Permissions, String> {
1641 let mut permissions = Permissions {
1642 print: false,
1643 modify: false,
1644 copy: false,
1645 annotate: false,
1646 fill_forms: false,
1647 accessibility: false,
1648 assemble: false,
1649 print_hires: false,
1650 };
1651 for name in names {
1652 match name {
1653 "print" => permissions.print = true,
1654 "modify" => permissions.modify = true,
1655 "copy" => permissions.copy = true,
1656 "annotate" => permissions.annotate = true,
1657 "fill-forms" => permissions.fill_forms = true,
1658 "accessibility" => permissions.accessibility = true,
1659 "assemble" => permissions.assemble = true,
1660 "print-hires" => permissions.print_hires = true,
1661 other => return Err(other.to_string()),
1662 }
1663 }
1664 Ok(permissions)
1665 }
1666
1667 pub(crate) fn p_value(&self) -> i32 {
1674 let flags: [(u32, bool); 8] = [
1675 (3, self.print),
1676 (4, self.modify),
1677 (5, self.copy),
1678 (6, self.annotate),
1679 (9, self.fill_forms),
1680 (10, self.accessibility),
1681 (11, self.assemble),
1682 (12, self.print_hires),
1683 ];
1684 let mut bits: u32 = !0b11; for (bit, granted) in flags {
1686 if !granted {
1687 bits &= !(1u32 << (bit - 1));
1688 }
1689 }
1690 bits as i32
1691 }
1692}
1693
1694impl Default for Permissions {
1695 fn default() -> Permissions {
1697 Permissions::all()
1698 }
1699}
1700
1701fn aes256_encrypt_dict(material: &KeyMaterial, p: i32) -> Dict {
1707 let mut std_cf = Dict::new();
1708 std_cf.insert(
1709 Name("CFM".to_string()),
1710 Object::Name(Name("AESV3".to_string())),
1711 );
1712 std_cf.insert(Name("Length".to_string()), Object::Int(32));
1713 let mut cf = Dict::new();
1714 cf.insert(Name("StdCF".to_string()), Object::Dict(std_cf));
1715
1716 let mut dict = Dict::new();
1717 dict.insert(
1718 Name("Filter".to_string()),
1719 Object::Name(Name("Standard".to_string())),
1720 );
1721 dict.insert(Name("V".to_string()), Object::Int(5));
1722 dict.insert(Name("R".to_string()), Object::Int(6));
1723 dict.insert(Name("Length".to_string()), Object::Int(256));
1724 dict.insert(Name("CF".to_string()), Object::Dict(cf));
1725 dict.insert(
1726 Name("StmF".to_string()),
1727 Object::Name(Name("StdCF".to_string())),
1728 );
1729 dict.insert(
1730 Name("StrF".to_string()),
1731 Object::Name(Name("StdCF".to_string())),
1732 );
1733 dict.insert(Name("P".to_string()), Object::Int(i64::from(p)));
1734 dict.insert(Name("U".to_string()), Object::String(material.u.clone()));
1735 dict.insert(Name("UE".to_string()), Object::String(material.ue.clone()));
1736 dict.insert(Name("O".to_string()), Object::String(material.o.clone()));
1737 dict.insert(Name("OE".to_string()), Object::String(material.oe.clone()));
1738 dict.insert(
1739 Name("Perms".to_string()),
1740 Object::String(material.perms.clone()),
1741 );
1742 dict
1743}
1744
1745#[allow(
1750 clippy::type_complexity,
1751 reason = "Box<dyn FnMut(&mut [u8]) -> Result<()> + Send> names the one random-byte source the write path takes; a type alias would only rename it"
1752)]
1753pub struct Encryptor {
1754 file_key: [u8; 32],
1755 rng: Box<dyn FnMut(&mut [u8]) -> crate::error::Result<()> + Send>,
1756}
1757
1758impl Encryptor {
1759 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
1771 pub fn aes256(
1772 user_password: &str,
1773 owner_password: &str,
1774 permissions: Permissions,
1775 ) -> crate::error::Result<(Encryptor, Dict)> {
1776 let mut rng = |buf: &mut [u8]| fill_os_random(buf);
1777 let p = permissions.p_value();
1778 let material = r6_key_material(
1779 user_password.as_bytes(),
1780 owner_password.as_bytes(),
1781 p,
1782 true,
1783 &mut rng,
1784 )?;
1785 let dict = aes256_encrypt_dict(&material, p);
1786 let encryptor = Encryptor {
1787 file_key: material.file_key,
1788 rng: Box::new(|buf: &mut [u8]| fill_os_random(buf)),
1789 };
1790 Ok((encryptor, dict))
1791 }
1792
1793 #[allow(clippy::type_complexity, reason = "see Encryptor's rng field")]
1796 pub fn aes256_with_rng(
1797 user_password: &str,
1798 owner_password: &str,
1799 permissions: Permissions,
1800 rng: Box<dyn FnMut(&mut [u8]) + Send>,
1801 ) -> (Encryptor, Dict) {
1802 let mut rng = rng;
1803 let p = permissions.p_value();
1804 let material = match r6_key_material(
1805 user_password.as_bytes(),
1806 owner_password.as_bytes(),
1807 p,
1808 true,
1809 &mut |buf: &mut [u8]| -> std::result::Result<(), std::convert::Infallible> {
1810 rng(buf);
1811 Ok(())
1812 },
1813 ) {
1814 Ok(material) => material,
1815 Err(never) => match never {},
1816 };
1817 let dict = aes256_encrypt_dict(&material, p);
1818 let encryptor = Encryptor {
1819 file_key: material.file_key,
1820 rng: Box::new(move |buf: &mut [u8]| {
1821 rng(buf);
1822 Ok(())
1823 }),
1824 };
1825 (encryptor, dict)
1826 }
1827
1828 pub fn encrypt_object(
1837 &mut self,
1838 obj: &mut Object,
1839 num: u32,
1840 gen: u16,
1841 ) -> crate::error::Result<()> {
1842 let _ = (num, gen);
1843 encrypt_in_place(obj, &self.file_key, &mut *self.rng)
1844 }
1845}
1846
1847fn encrypt_in_place(
1852 obj: &mut Object,
1853 key: &[u8],
1854 rng: &mut dyn FnMut(&mut [u8]) -> crate::error::Result<()>,
1855) -> crate::error::Result<()> {
1856 match obj {
1857 Object::String(bytes) => *bytes = aes_cbc_encrypt(key, rng, bytes)?,
1858 Object::Array(items) => {
1859 for it in items {
1860 encrypt_in_place(it, key, &mut *rng)?;
1861 }
1862 }
1863 Object::Dict(dict) => {
1864 for v in dict.values_mut() {
1865 encrypt_in_place(v, key, &mut *rng)?;
1866 }
1867 }
1868 Object::Stream(stream) => {
1869 for v in stream.dict.values_mut() {
1870 encrypt_in_place(v, key, &mut *rng)?;
1871 }
1872 if stream_crypt_filter(&stream.dict).as_deref() == Some("Identity") {
1876 return Ok(());
1877 }
1878 stream.data = aes_cbc_encrypt(key, rng, &stream.data)?;
1879 }
1880 _ => {}
1881 }
1882 Ok(())
1883}
1884
1885#[rustfmt::skip]
1887const MD5_S: [u32; 64] = [
1888 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
1889 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
1890 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
1891 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
1892];
1893
1894#[rustfmt::skip]
1896const MD5_K: [u32; 64] = [
1897 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
1898 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
1899 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
1900 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
1901 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
1902 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
1903 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
1904 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
1905];
1906
1907fn md5(input: &[u8]) -> [u8; 16] {
1910 let (mut a0, mut b0, mut c0, mut d0) = (
1911 0x6745_2301u32,
1912 0xefcd_ab89u32,
1913 0x98ba_dcfeu32,
1914 0x1032_5476u32,
1915 );
1916
1917 let mut msg = input.to_vec();
1918 let bitlen = (input.len() as u64).wrapping_mul(8);
1919 msg.push(0x80);
1920 while msg.len() % 64 != 56 {
1921 msg.push(0);
1922 }
1923 msg.extend_from_slice(&bitlen.to_le_bytes());
1924
1925 for chunk in msg.as_chunks::<64>().0 {
1926 let mut m = [0u32; 16];
1927 for (word, bytes) in m.iter_mut().zip(chunk.as_chunks::<4>().0) {
1928 *word = u32::from_le_bytes(*bytes);
1929 }
1930 let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
1931 for i in 0..64 {
1932 let (f, g) = match i {
1933 0..=15 => ((b & c) | (!b & d), i),
1934 16..=31 => ((d & b) | (!d & c), (5 * i + 1) % 16),
1935 32..=47 => (b ^ c ^ d, (3 * i + 5) % 16),
1936 _ => (c ^ (b | !d), (7 * i) % 16),
1937 };
1938 let f = f.wrapping_add(a).wrapping_add(MD5_K[i]).wrapping_add(m[g]);
1939 a = d;
1940 d = c;
1941 c = b;
1942 b = b.wrapping_add(f.rotate_left(MD5_S[i]));
1943 }
1944 a0 = a0.wrapping_add(a);
1945 b0 = b0.wrapping_add(b);
1946 c0 = c0.wrapping_add(c);
1947 d0 = d0.wrapping_add(d);
1948 }
1949
1950 let mut out = [0u8; 16];
1951 out[0..4].copy_from_slice(&a0.to_le_bytes());
1952 out[4..8].copy_from_slice(&b0.to_le_bytes());
1953 out[8..12].copy_from_slice(&c0.to_le_bytes());
1954 out[12..16].copy_from_slice(&d0.to_le_bytes());
1955 out
1956}
1957
1958#[cfg(test)]
1959mod tests {
1960 use super::*;
1961 use crate::object::Name;
1962
1963 fn hex(bytes: &[u8]) -> String {
1964 bytes.iter().map(|b| format!("{b:02x}")).collect()
1965 }
1966
1967 #[test]
1968 fn md5_known_vectors() {
1969 assert_eq!(hex(&md5(b"")), "d41d8cd98f00b204e9800998ecf8427e");
1970 assert_eq!(hex(&md5(b"abc")), "900150983cd24fb0d6963f7d28e17f72");
1971 assert_eq!(
1972 hex(&md5(b"The quick brown fox jumps over the lazy dog")),
1973 "9e107d9d372bb6826bd81d3542a419d6"
1974 );
1975 }
1976
1977 #[test]
1978 fn md5_spans_block_boundary() {
1979 let input = [b'a'; 56];
1981 assert_eq!(hex(&md5(&input)), "3b0c8ac703f828b04c6c197006d17218");
1982 }
1983
1984 #[test]
1989 fn aes_block_known_vectors() {
1990 let plain: [u8; 16] = core::array::from_fn(|i| (i as u8) * 0x11);
1991 let key128: [u8; 16] = core::array::from_fn(|i| i as u8);
1992 let key256: [u8; 32] = core::array::from_fn(|i| i as u8);
1993
1994 type Encrypt = fn(&mut [u8; 16], &[[u8; 16]]);
1995 type Decrypt = fn(&mut [u8; 16], &[[u8; 16]], &[u8; 256]);
1996 let paths: [(Encrypt, Decrypt); 2] = [
1997 (aes_encrypt_block, aes_decrypt_block),
1998 (aes_encrypt_block_soft, aes_decrypt_block_soft),
1999 ];
2000 for (encrypt, decrypt) in paths {
2001 let mut s = plain;
2002 encrypt(&mut s, &aes_expand_key(&key128));
2003 assert_eq!(hex(&s), "69c4e0d86a7b0430d8cdb78070b4c55a");
2004 decrypt(&mut s, &aes_expand_key(&key128), &aes_inv_sbox());
2005 assert_eq!(s, plain);
2006
2007 let mut s = plain;
2008 encrypt(&mut s, &aes_expand_key(&key256));
2009 assert_eq!(hex(&s), "8ea2b7ca516745bfeafc49904b496089");
2010 decrypt(&mut s, &aes_expand_key(&key256), &aes_inv_sbox());
2011 assert_eq!(s, plain);
2012 }
2013 }
2014
2015 #[test]
2018 fn aes_cbc_round_trips_multiple_blocks() {
2019 let key: [u8; 16] = core::array::from_fn(|i| (i as u8).wrapping_mul(7));
2020 let iv: [u8; 16] = core::array::from_fn(|i| 0xa5 ^ (i as u8));
2021 let data: Vec<u8> = (0..64u8).collect();
2022 let ct = aes_cbc_encrypt_blocks(&key, &iv, &data);
2023 assert_eq!(ct.len(), data.len());
2024 assert_ne!(ct, data);
2025 assert_eq!(aes_cbc_decrypt_blocks(&key, &iv, &ct), data);
2026 }
2027
2028 #[test]
2032 fn sha2_known_vectors() {
2033 assert_eq!(
2034 hex(&sha256(b"")),
2035 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
2036 );
2037 assert_eq!(
2038 hex(&sha256(b"abc")),
2039 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
2040 );
2041 assert_eq!(
2042 hex(&sha256(&[b'a'; 200])),
2043 "c2a908d98f5df987ade41b5fce213067efbcc21ef2240212a41e54b5e7c28ae5"
2044 );
2045 assert_eq!(
2046 hex(&sha384(b"abc")),
2047 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
2048 8086072ba1e7cc2358baeca134c825a7"
2049 );
2050 assert_eq!(
2051 hex(&sha512(b"abc")),
2052 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
2053 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
2054 );
2055 assert_eq!(
2056 hex(&sha512(&[b'a'; 300])),
2057 "a6a77010dd9696c23831e6549de51724df332c2075039b75fcfe6c2e6de42fbd\
2058 3c80ed4073267e00c8c320712c3cdd9d65a96f90a3fe4a58a6b70a103be08e83"
2059 );
2060 }
2061
2062 #[test]
2066 fn sha2_soft_compressions_match_the_dispatch() {
2067 let block64: [u8; 64] = core::array::from_fn(|i| (i as u8).wrapping_mul(31));
2068 let mut via_dispatch = [0x6a09e667u32; 8];
2069 let mut via_soft = via_dispatch;
2070 sha256_compress(&mut via_dispatch, &block64);
2071 sha256_compress_soft(&mut via_soft, &block64);
2072 assert_eq!(via_dispatch, via_soft);
2073
2074 let block128: [u8; 128] = core::array::from_fn(|i| (i as u8).wrapping_mul(29));
2075 let mut via_dispatch = [0x6a09e667f3bcc908u64; 8];
2076 let mut via_soft = via_dispatch;
2077 sha512_compress(&mut via_dispatch, &block128);
2078 sha512_compress_soft(&mut via_soft, &block128);
2079 assert_eq!(via_dispatch, via_soft);
2080 }
2081
2082 #[test]
2085 fn incremental_sha256_matches_the_one_shot() {
2086 let input: Vec<u8> = (0..300u16).map(|i| (i % 251) as u8).collect();
2087 for splits in [
2088 vec![0, 1, 3, 7, 60, 63, 64, 65, 37],
2089 vec![300],
2090 vec![128, 128, 44],
2091 vec![55, 9, 236],
2092 ] {
2093 let mut hasher = Sha256::new();
2094 let mut fed = 0usize;
2095 for len in splits {
2096 hasher.update(&input[fed..fed + len]);
2097 fed += len;
2098 }
2099 hasher.update(&input[fed..]);
2100 assert_eq!(hasher.finalize(), sha256(&input));
2101 }
2102 assert_eq!(Sha256::new().finalize(), sha256(b""));
2103 assert_eq!(Sha256::default().finalize(), sha256(b""));
2104 }
2105
2106 #[test]
2107 fn rc4_known_vector() {
2108 let ct = rc4(b"Key", b"Plaintext");
2110 assert_eq!(hex(&ct), "bbf316e8d940af0ad3");
2111 assert_eq!(rc4(b"Key", &ct), b"Plaintext");
2113 }
2114
2115 const N: usize = 16; const P: i32 = -44;
2122 const ID0: &[u8] = b"0123456789abcdef";
2123
2124 fn owner_entry(owner_pw: &[u8], user_pw: &[u8]) -> Vec<u8> {
2126 owner_entry_with(N, owner_pw, user_pw)
2127 }
2128
2129 fn owner_entry_with(n: usize, owner_pw: &[u8], user_pw: &[u8]) -> Vec<u8> {
2131 let mut d = md5(&pad_password(owner_pw));
2132 for _ in 0..50 {
2133 d = md5(&d[..n]);
2134 }
2135 let rc4key = d[..n].to_vec();
2136 let mut o = rc4(&rc4key, &pad_password(user_pw));
2137 for i in 1u8..=19 {
2138 let k: Vec<u8> = rc4key.iter().map(|b| b ^ i).collect();
2139 o = rc4(&k, &o);
2140 }
2141 o
2142 }
2143
2144 fn file_key(o: &[u8], user_pw: &[u8]) -> Vec<u8> {
2146 file_key_with(N, o, user_pw)
2147 }
2148
2149 fn file_key_with(n: usize, o: &[u8], user_pw: &[u8]) -> Vec<u8> {
2151 let mut input = Vec::new();
2152 input.extend_from_slice(&pad_password(user_pw));
2153 input.extend_from_slice(o);
2154 input.extend_from_slice(&(P as u32).to_le_bytes());
2155 input.extend_from_slice(ID0);
2156 let mut d = md5(&input);
2157 for _ in 0..50 {
2158 d = md5(&d[..n]);
2159 }
2160 d[..n].to_vec()
2161 }
2162
2163 fn msg_of(doc: &crate::Document, num: u32) -> Vec<u8> {
2165 use crate::object::ObjRef;
2166 let obj = doc.get(ObjRef { num, gen: 0 }).unwrap();
2167 obj.as_dict()
2168 .unwrap()
2169 .get("Msg")
2170 .unwrap()
2171 .as_str_bytes()
2172 .unwrap()
2173 .to_vec()
2174 }
2175
2176 fn body_of(doc: &crate::Document, num: u32) -> Vec<u8> {
2178 use crate::object::ObjRef;
2179 let obj = doc.get(ObjRef { num, gen: 0 }).unwrap();
2180 doc.stream_data(obj.as_stream().unwrap()).unwrap()
2181 }
2182
2183 fn user_entry(key: &[u8]) -> Vec<u8> {
2185 let mut input = Vec::new();
2186 input.extend_from_slice(&PAD);
2187 input.extend_from_slice(ID0);
2188 let mut x = md5(&input).to_vec();
2189 x = rc4(key, &x);
2190 for i in 1u8..=19 {
2191 let k: Vec<u8> = key.iter().map(|b| b ^ i).collect();
2192 x = rc4(&k, &x);
2193 }
2194 x.resize(32, 0); x
2196 }
2197
2198 fn obj_key(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
2199 let mut input = key.to_vec();
2200 input.extend_from_slice(&num.to_le_bytes()[..3]);
2201 input.extend_from_slice(&gen.to_le_bytes()[..2]);
2202 md5(&input)[..(key.len() + 5).min(16)].to_vec()
2203 }
2204
2205 fn hexstr(b: &[u8]) -> String {
2206 let mut s = String::from("<");
2207 for x in b {
2208 s.push_str(&format!("{x:02x}"));
2209 }
2210 s.push('>');
2211 s
2212 }
2213
2214 fn encrypted_fixture(u_override: Option<Vec<u8>>) -> Vec<u8> {
2215 encrypted_fixture_with(b"", b"", u_override)
2216 }
2217
2218 fn encrypted_fixture_with(
2219 user_pw: &[u8],
2220 owner_pw: &[u8],
2221 u_override: Option<Vec<u8>>,
2222 ) -> Vec<u8> {
2223 use pdfboss_testkit::PdfBuilder;
2224 let o = owner_entry(owner_pw, user_pw);
2225 let key = file_key(&o, user_pw);
2226 let u = u_override.unwrap_or_else(|| user_entry(&key));
2227
2228 let msg = rc4(&obj_key(&key, 3, 0), b"Top secret message");
2229 let stream = rc4(&obj_key(&key, 4, 0), b"decrypted stream body");
2230
2231 let mut b = PdfBuilder::new().version(1, 4);
2232 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2233 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2234 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2235 b.stream(4, "", &stream);
2236 b.object(
2237 9,
2238 &format!(
2239 "<< /Filter /Standard /V 2 /R 3 /Length 128 /P {P} /O {} /U {} >>",
2240 hexstr(&o),
2241 hexstr(&u)
2242 ),
2243 );
2244 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2245 b.trailer_extra(&trailer).build(1)
2246 }
2247
2248 #[test]
2250 fn document_load_decrypts_standard_rc4() {
2251 use crate::object::ObjRef;
2252 use crate::Document;
2253
2254 let doc = Document::load(encrypted_fixture(None)).expect("empty password opens the file");
2255
2256 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2257 let msg = obj3
2258 .as_dict()
2259 .unwrap()
2260 .get("Msg")
2261 .unwrap()
2262 .as_str_bytes()
2263 .unwrap();
2264 assert_eq!(msg, b"Top secret message", "string decrypted");
2265
2266 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
2267 let data = doc.stream_data(obj4.as_stream().unwrap()).unwrap();
2268 assert_eq!(data, b"decrypted stream body", "stream decrypted");
2269 }
2270
2271 #[test]
2273 fn document_load_rejects_when_password_does_not_verify() {
2274 use crate::error::Error;
2275 use crate::Document;
2276
2277 let bad_u = vec![0u8; 32];
2280 let err = Document::load(encrypted_fixture(Some(bad_u)));
2281 assert!(matches!(err, Err(Error::Encrypted)));
2282 }
2283
2284 #[test]
2286 fn real_user_password_opens_an_rc4_file() {
2287 use crate::error::Error;
2288 use crate::object::ObjRef;
2289 use crate::Document;
2290
2291 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
2292 assert!(
2293 matches!(Document::load(bytes.clone()), Err(Error::Encrypted)),
2294 "without the password the file stays closed"
2295 );
2296 let doc = Document::load_with_password(bytes, "hunter2").expect("user password opens");
2297 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2298 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2299 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
2300 }
2301
2302 #[test]
2304 fn owner_password_opens_an_rc4_file() {
2305 use crate::object::ObjRef;
2306 use crate::Document;
2307
2308 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
2309 let doc =
2310 Document::load_with_password(bytes, "owner-secret").expect("owner password opens");
2311 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2312 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2313 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
2314 }
2315
2316 #[test]
2318 fn wrong_password_stays_encrypted() {
2319 use crate::error::Error;
2320 use crate::Document;
2321
2322 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
2323 let err = Document::load_with_password(bytes, "letmein");
2324 assert!(matches!(err, Err(Error::Encrypted)));
2325 }
2326
2327 #[test]
2329 fn real_passwords_open_an_aes256_r6_file() {
2330 use crate::error::Error;
2331 use crate::object::ObjRef;
2332 use crate::Document;
2333
2334 let bytes = encrypted_fixture_aesv3_with(6, "pässword".as_bytes(), b"owner-secret");
2335 assert!(
2336 matches!(Document::load(bytes.clone()), Err(Error::Encrypted)),
2337 "without the password the file stays closed"
2338 );
2339 for pw in ["pässword", "owner-secret"] {
2340 let doc = Document::load_with_password(bytes.clone(), pw)
2341 .unwrap_or_else(|_| panic!("{pw:?} opens the file"));
2342 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2343 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2344 assert_eq!(msg.as_str_bytes().unwrap(), b"AES-256 secret");
2345 }
2346 assert!(matches!(
2347 Document::load_with_password(bytes, "letmein"),
2348 Err(Error::Encrypted)
2349 ));
2350 }
2351
2352 #[test]
2354 fn empty_password_files_still_open_through_the_password_api() {
2355 use crate::object::ObjRef;
2356 use crate::Document;
2357
2358 let doc = Document::load_with_password(encrypted_fixture(None), "")
2362 .expect("the empty password opens through the password API too");
2363 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2364 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2365 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
2366 }
2367
2368 #[test]
2370 fn unsupported_handler_is_declined() {
2371 let mut enc = Dict::new();
2374 enc.insert(Name("Filter".into()), Object::Name(Name("Standard".into())));
2375 enc.insert(Name("V".into()), Object::Int(6));
2376 enc.insert(Name("R".into()), Object::Int(7));
2377 enc.insert(Name("O".into()), Object::String(vec![0; 48]));
2378 enc.insert(Name("U".into()), Object::String(vec![0; 48]));
2379 enc.insert(Name("P".into()), Object::Int(-4));
2380 assert!(Decryptor::from_standard(&enc, ID0).is_none());
2381 }
2382
2383 #[test]
2386 fn aes_fips197_block_vectors() {
2387 let pt: [u8; 16] = [
2389 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
2390 0xee, 0xff,
2391 ];
2392 let key128: Vec<u8> = (0u8..16).collect();
2393 let rks = aes_expand_key(&key128);
2394 let mut b = pt;
2395 aes_encrypt_block(&mut b, &rks);
2396 assert_eq!(hex(&b), "69c4e0d86a7b0430d8cdb78070b4c55a");
2397 aes_decrypt_block(&mut b, &rks, &aes_inv_sbox());
2398 assert_eq!(b, pt, "AES-128 decrypt inverts encrypt");
2399
2400 let key256: Vec<u8> = (0u8..32).collect();
2401 let rks = aes_expand_key(&key256);
2402 let mut b = pt;
2403 aes_encrypt_block(&mut b, &rks);
2404 assert_eq!(hex(&b), "8ea2b7ca516745bfeafc49904b496089");
2405 }
2406
2407 #[test]
2408 fn sha2_vectors() {
2409 assert_eq!(
2410 hex(&sha256(b"abc")),
2411 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
2412 );
2413 assert_eq!(
2414 hex(&sha512(b"abc")),
2415 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
2416 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
2417 );
2418 assert_eq!(
2419 hex(&sha384(b"abc")),
2420 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
2421 8086072ba1e7cc2358baeca134c825a7"
2422 );
2423 }
2424
2425 #[test]
2426 fn aes_cbc_roundtrip() {
2427 let key: Vec<u8> = (0u8..16).collect();
2428 let iv = [0x24u8; 16];
2429 let pt = b"a message spanning several AES blocks exactly?!!";
2430 let ct = aes_cbc_encrypt_blocks(&key, &iv, &pkcs7_pad(pt));
2431 let mut val = iv.to_vec(); val.extend_from_slice(&ct);
2433 assert_eq!(aes_cbc_decrypt(&key, &val), pt);
2434 }
2435
2436 fn obj_key_aes(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
2439 let mut input = key.to_vec();
2440 input.extend_from_slice(&num.to_le_bytes()[..3]);
2441 input.extend_from_slice(&gen.to_le_bytes()[..2]);
2442 input.extend_from_slice(b"sAlT");
2443 md5(&input)[..(key.len() + 5).min(16)].to_vec()
2444 }
2445
2446 fn aes_encrypt_pdf(key: &[u8], pt: &[u8], iv: &[u8; 16]) -> Vec<u8> {
2449 let mut out = iv.to_vec();
2450 out.extend_from_slice(&aes_cbc_encrypt_blocks(key, iv, &pkcs7_pad(pt)));
2451 out
2452 }
2453
2454 fn encrypted_fixture_aesv2() -> Vec<u8> {
2455 use pdfboss_testkit::PdfBuilder;
2456 let o = owner_entry(b"", b"");
2457 let key = file_key(&o, b""); let u = user_entry(&key);
2459 let iv = [0x11u8; 16];
2460 let msg = aes_encrypt_pdf(&obj_key_aes(&key, 3, 0), b"Top secret message", &iv);
2461 let stream = aes_encrypt_pdf(&obj_key_aes(&key, 4, 0), b"decrypted stream body", &iv);
2462
2463 let mut b = PdfBuilder::new().version(1, 5);
2464 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2465 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2466 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2467 b.stream(4, "", &stream);
2468 b.object(
2469 9,
2470 &format!(
2471 "<< /Filter /Standard /V 4 /R 4 /Length 128 /P {P} /O {} /U {} \
2472 /CF << /StdCF << /CFM /AESV2 /Length 16 >> >> /StmF /StdCF /StrF /StdCF >>",
2473 hexstr(&o),
2474 hexstr(&u)
2475 ),
2476 );
2477 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2478 b.trailer_extra(&trailer).build(1)
2479 }
2480
2481 #[test]
2483 fn document_load_decrypts_aesv2() {
2484 use crate::object::ObjRef;
2485 use crate::Document;
2486 let doc = Document::load(encrypted_fixture_aesv2()).expect("AESV2 empty password opens");
2487 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2488 let msg = obj3
2489 .as_dict()
2490 .unwrap()
2491 .get("Msg")
2492 .unwrap()
2493 .as_str_bytes()
2494 .unwrap();
2495 assert_eq!(msg, b"Top secret message");
2496 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
2497 assert_eq!(
2498 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
2499 b"decrypted stream body"
2500 );
2501 }
2502
2503 fn v4_fixture(
2511 n: usize,
2512 encrypt_entries: &str,
2513 body: impl FnOnce(&mut pdfboss_testkit::PdfBuilder, &[u8]),
2514 ) -> Vec<u8> {
2515 use pdfboss_testkit::PdfBuilder;
2516 let o = owner_entry_with(n, b"", b"");
2517 let key = file_key_with(n, &o, b"");
2518 let u = user_entry(&key);
2519 let mut b = PdfBuilder::new().version(1, 5);
2520 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2521 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2522 body(&mut b, &key);
2523 b.object(
2524 9,
2525 &format!(
2526 "<< /Filter /Standard /V 4 /R 4 /P {P} /O {} /U {} {encrypt_entries} >>",
2527 hexstr(&o),
2528 hexstr(&u)
2529 ),
2530 );
2531 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2532 b.trailer_extra(&trailer).build(1)
2533 }
2534
2535 const AESV2_CF: &str = "/CF << /StdCF << /CFM /AESV2 /Length 16 >> >>";
2536 const TWO_CF: &str =
2537 "/CF << /StdCF << /CFM /AESV2 /Length 16 >> /RcCF << /CFM /V2 /Length 16 >> >>";
2538 const IV: [u8; 16] = [0x11; 16];
2539
2540 #[test]
2544 fn identity_stream_filter_leaves_streams_as_stored() {
2545 use crate::Document;
2546 let data = v4_fixture(
2547 16,
2548 &format!("/Length 128 {AESV2_CF} /StmF /Identity /StrF /StdCF"),
2549 |b, key| {
2550 let msg = aes_encrypt_pdf(&obj_key_aes(key, 3, 0), b"Top secret message", &IV);
2551 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2552 b.stream(4, "", b"stored in the clear");
2553 },
2554 );
2555 let doc = Document::load(data).expect("an Identity stream filter is a valid V4 file");
2556 assert_eq!(msg_of(&doc, 3), b"Top secret message");
2557 assert_eq!(body_of(&doc, 4), b"stored in the clear");
2558 }
2559
2560 #[test]
2563 fn string_filter_is_chosen_independently_of_the_stream_filter() {
2564 use crate::Document;
2565 let data = v4_fixture(
2566 16,
2567 &format!("/Length 128 {TWO_CF} /StmF /StdCF /StrF /RcCF"),
2568 |b, key| {
2569 let msg = rc4(&obj_key(key, 3, 0), b"Top secret message");
2570 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2571 let stream =
2572 aes_encrypt_pdf(&obj_key_aes(key, 4, 0), b"decrypted stream body", &IV);
2573 b.stream(4, "", &stream);
2574 },
2575 );
2576 let doc = Document::load(data).expect("two crypt filters open");
2577 assert_eq!(msg_of(&doc, 3), b"Top secret message");
2578 assert_eq!(body_of(&doc, 4), b"decrypted stream body");
2579 }
2580
2581 #[test]
2584 fn embedded_file_filter_applies_to_embedded_file_streams() {
2585 use crate::Document;
2586 let data = v4_fixture(
2587 16,
2588 &format!("/Length 128 {TWO_CF} /StmF /StdCF /StrF /StdCF /EFF /RcCF"),
2589 |b, key| {
2590 let attached = rc4(&obj_key(key, 4, 0), b"attached file bytes");
2591 b.stream(4, "/Type /EmbeddedFile", &attached);
2592 let stream =
2593 aes_encrypt_pdf(&obj_key_aes(key, 5, 0), b"decrypted stream body", &IV);
2594 b.stream(5, "", &stream);
2595 },
2596 );
2597 let doc = Document::load(data).expect("an /EFF entry opens");
2598 assert_eq!(body_of(&doc, 4), b"attached file bytes");
2599 assert_eq!(body_of(&doc, 5), b"decrypted stream body");
2600 }
2601
2602 #[test]
2606 fn crypt_filter_length_sets_the_key_size() {
2607 use crate::Document;
2608 let data = v4_fixture(
2609 5,
2610 "/CF << /StdCF << /CFM /V2 /Length 5 >> >> /StmF /StdCF /StrF /StdCF",
2611 |b, key| {
2612 let msg = rc4(&obj_key(key, 3, 0), b"Top secret message");
2613 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2614 b.stream(4, "", &rc4(&obj_key(key, 4, 0), b"decrypted stream body"));
2615 },
2616 );
2617 let doc = Document::load(data).expect("a 40-bit V4 file opens");
2618 assert_eq!(msg_of(&doc, 3), b"Top secret message");
2619 assert_eq!(body_of(&doc, 4), b"decrypted stream body");
2620 }
2621
2622 #[test]
2626 fn aesv2_always_derives_a_16_byte_object_key() {
2627 use crate::Document;
2628 let object_key = |key: &[u8], num: u32| {
2629 let mut input = key.to_vec();
2630 input.extend_from_slice(&num.to_le_bytes()[..3]);
2631 input.extend_from_slice(&[0, 0]);
2632 input.extend_from_slice(b"sAlT");
2633 md5(&input).to_vec()
2634 };
2635 let data = v4_fixture(
2636 5,
2637 "/Length 40 /CF << /StdCF << /CFM /AESV2 /Length 5 >> >> /StmF /StdCF /StrF /StdCF",
2638 |b, key| {
2639 let msg = aes_encrypt_pdf(&object_key(key, 3), b"Top secret message", &IV);
2640 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2641 let stream = aes_encrypt_pdf(&object_key(key, 4), b"decrypted stream body", &IV);
2642 b.stream(4, "", &stream);
2643 },
2644 );
2645 let doc = Document::load(data).expect("a 40-bit AESV2 file opens");
2646 assert_eq!(msg_of(&doc, 3), b"Top secret message");
2647 assert_eq!(body_of(&doc, 4), b"decrypted stream body");
2648 }
2649
2650 #[test]
2655 fn a_stream_crypt_filter_naming_identity_is_left_as_stored() {
2656 use crate::Document;
2657 let data = v4_fixture(
2658 16,
2659 &format!("/Length 128 {AESV2_CF} /StmF /StdCF /StrF /StdCF"),
2660 |b, key| {
2661 b.stream(
2662 4,
2663 "/Filter /Crypt /DecodeParms << /Type /CryptFilterDecodeParms /Name /Identity >>",
2664 b"stored in the clear",
2665 );
2666 let stream =
2667 aes_encrypt_pdf(&obj_key_aes(key, 5, 0), b"decrypted stream body", &IV);
2668 b.stream(5, "", &stream);
2669 },
2670 );
2671 let doc = Document::load(data).expect("opens");
2672 assert_eq!(body_of(&doc, 4), b"stored in the clear");
2673 assert_eq!(body_of(&doc, 5), b"decrypted stream body");
2674 }
2675
2676 #[test]
2679 fn a_stream_crypt_filter_without_a_name_means_identity() {
2680 use crate::Document;
2681 let data = v4_fixture(
2682 16,
2683 &format!("/Length 128 {AESV2_CF} /StmF /StdCF /StrF /StdCF"),
2684 |b, _| {
2685 b.stream(
2686 4,
2687 "/Filter [/Crypt /ASCIIHexDecode]",
2688 b"73746F72656420617320686578>",
2689 );
2690 },
2691 );
2692 let doc = Document::load(data).expect("opens");
2693 assert_eq!(body_of(&doc, 4), b"stored as hex");
2694 }
2695
2696 #[test]
2700 fn a_stream_crypt_filter_naming_a_cf_entry_uses_the_file_key_as_is() {
2701 use crate::Document;
2702 let data = v4_fixture(
2703 16,
2704 &format!("/Length 128 {TWO_CF} /StmF /StdCF /StrF /StdCF"),
2705 |b, key| {
2706 b.stream(
2707 4,
2708 "/Filter /Crypt /DecodeParms << /Name /RcCF >>",
2709 &rc4(key, b"under the file key"),
2710 );
2711 },
2712 );
2713 let doc = Document::load(data).expect("opens");
2714 assert_eq!(body_of(&doc, 4), b"under the file key");
2715 }
2716
2717 fn encrypted_fixture_aesv3(r: i64) -> Vec<u8> {
2720 encrypted_fixture_aesv3_with(r, b"", b"")
2721 }
2722
2723 fn encrypted_fixture_aesv3_with(r: i64, user_pw: &[u8], owner_pw: &[u8]) -> Vec<u8> {
2724 encrypted_fixture_aesv3_with_metadata(r, user_pw, owner_pw, true, None)
2725 }
2726
2727 fn encrypted_fixture_aesv3_with_metadata(
2733 r: i64,
2734 user_pw: &[u8],
2735 owner_pw: &[u8],
2736 encrypt_metadata: bool,
2737 metadata: Option<&[u8]>,
2738 ) -> Vec<u8> {
2739 use pdfboss_testkit::PdfBuilder;
2740 let key = aesv3_file_key();
2741 let iv = [0x22u8; 16];
2742 let msg = aes_encrypt_pdf(&key, b"AES-256 secret", &iv);
2743 let stream = aes_encrypt_pdf(&key, b"AES-256 stream body", &iv);
2744
2745 let mut b = PdfBuilder::new().version(1, 7);
2746 let catalog = match metadata {
2747 Some(_) => "<< /Type /Catalog /Pages 2 0 R /Metadata 5 0 R >>",
2748 None => "<< /Type /Catalog /Pages 2 0 R >>",
2749 };
2750 b.object(1, catalog);
2751 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2752 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2753 b.stream(4, "", &stream);
2754 if let Some(metadata) = metadata {
2755 b.stream(5, "<< /Type /Metadata /Subtype /XML >>", metadata);
2756 }
2757 let encrypt_metadata_entry = if encrypt_metadata {
2758 ""
2759 } else {
2760 " /EncryptMetadata false"
2761 };
2762 b.object(
2763 9,
2764 &format!(
2765 "<< /Filter /Standard /V 5 /R {r} /Length 256 /P {P} {}{encrypt_metadata_entry} \
2766 /CF << /StdCF << /CFM /AESV3 /Length 32 >> >> /StmF /StdCF /StrF /StdCF >>",
2767 aesv3_password_entries(r, user_pw, owner_pw, &key),
2768 ),
2769 );
2770 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2771 b.trailer_extra(&trailer).build(1)
2772 }
2773
2774 fn aesv3_file_key() -> Vec<u8> {
2776 (0u8..32).map(|i| i ^ 0x5a).collect()
2777 }
2778
2779 fn aesv3_password_entries(r: i64, user_pw: &[u8], owner_pw: &[u8], key: &[u8]) -> String {
2782 let vsalt: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
2783 let ksalt: [u8; 8] = [9, 10, 11, 12, 13, 14, 15, 16];
2784 let mut u = hash_2b(r, user_pw, &vsalt, &[]); u.extend_from_slice(&vsalt);
2786 u.extend_from_slice(&ksalt);
2787 let intermediate = hash_2b(r, user_pw, &ksalt, &[]);
2788 let ue = aes_cbc_encrypt_blocks(&intermediate, &[0u8; 16], key);
2789 let ovsalt: [u8; 8] = [21, 22, 23, 24, 25, 26, 27, 28];
2791 let oksalt: [u8; 8] = [31, 32, 33, 34, 35, 36, 37, 38];
2792 let mut o = hash_2b(r, owner_pw, &ovsalt, &u[..48]);
2793 o.extend_from_slice(&ovsalt);
2794 o.extend_from_slice(&oksalt);
2795 let ointermediate = hash_2b(r, owner_pw, &oksalt, &u[..48]);
2796 let oe = aes_cbc_encrypt_blocks(&ointermediate, &[0u8; 16], key);
2797 format!(
2798 "/U {} /UE {} /O {} /OE {}",
2799 hexstr(&u),
2800 hexstr(&ue),
2801 hexstr(&o),
2802 hexstr(&oe)
2803 )
2804 }
2805
2806 #[test]
2810 fn an_indirect_cf_dictionary_is_followed() {
2811 use crate::Document;
2812 use pdfboss_testkit::PdfBuilder;
2813 let key = aesv3_file_key();
2814 let stream = aes_encrypt_pdf(&key, b"AES-256 stream body", &[0x22u8; 16]);
2815 let mut b = PdfBuilder::new().version(1, 7);
2816 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2817 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2818 b.stream(4, "", &stream);
2819 b.object(8, "<< /StdCF << /CFM /AESV3 /Length 32 >> >>");
2820 b.object(
2821 9,
2822 &format!(
2823 "<< /Filter /Standard /V 5 /R 6 /Length 256 /P {P} {} \
2824 /CF 8 0 R /StmF /StdCF /StrF /StdCF >>",
2825 aesv3_password_entries(6, b"", b"", &key),
2826 ),
2827 );
2828 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2829 let doc = Document::load(b.trailer_extra(&trailer).build(1))
2830 .expect("an indirect /CF still names the filters");
2831 assert_eq!(body_of(&doc, 4), b"AES-256 stream body");
2832 }
2833
2834 #[test]
2837 fn aesv3_identity_string_filter_leaves_strings_as_stored() {
2838 use crate::Document;
2839 use pdfboss_testkit::PdfBuilder;
2840 let key = aesv3_file_key();
2841 let stream = aes_encrypt_pdf(&key, b"AES-256 stream body", &[0x22u8; 16]);
2842 let mut b = PdfBuilder::new().version(1, 7);
2843 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2844 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2845 b.object(3, "<< /Msg (stored in the clear) >>");
2846 b.stream(4, "", &stream);
2847 b.object(
2848 9,
2849 &format!(
2850 "<< /Filter /Standard /V 5 /R 6 /Length 256 /P {P} {} \
2851 /CF << /StdCF << /CFM /AESV3 /Length 32 >> >> /StmF /StdCF /StrF /Identity >>",
2852 aesv3_password_entries(6, b"", b"", &key),
2853 ),
2854 );
2855 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2856 let doc = Document::load(b.trailer_extra(&trailer).build(1))
2857 .expect("an Identity string filter is a valid V5 file");
2858 assert_eq!(msg_of(&doc, 3), b"stored in the clear");
2859 assert_eq!(body_of(&doc, 4), b"AES-256 stream body");
2860 }
2861
2862 fn assert_aesv3_decrypts(r: i64) {
2863 use crate::object::ObjRef;
2864 use crate::Document;
2865 let doc = Document::load(encrypted_fixture_aesv3(r)).expect("AESV3 empty password opens");
2866 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2867 let msg = obj3
2868 .as_dict()
2869 .unwrap()
2870 .get("Msg")
2871 .unwrap()
2872 .as_str_bytes()
2873 .unwrap();
2874 assert_eq!(msg, b"AES-256 secret", "R{r} string");
2875 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
2876 assert_eq!(
2877 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
2878 b"AES-256 stream body",
2879 "R{r} stream"
2880 );
2881 }
2882
2883 #[test]
2885 fn document_load_decrypts_aesv3_r5() {
2886 assert_aesv3_decrypts(5);
2887 }
2888
2889 #[test]
2891 fn document_load_decrypts_aesv3_r6() {
2892 assert_aesv3_decrypts(6); }
2894
2895 #[test]
2897 fn encrypt_metadata_false_leaves_the_metadata_stream_plaintext() {
2898 use crate::object::ObjRef;
2899 use crate::Document;
2900
2901 const XMP: &[u8] = b"<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>\
2902 <x:xmpmeta xmlns:x='adobe:ns:meta/'><rdf:RDF \
2903 xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'><rdf:Description \
2904 xmlns:dc='http://purl.org/dc/elements/1.1/'><dc:title>XMP Secret \
2905 Title</dc:title></rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end='w'?>";
2906
2907 let bytes =
2908 encrypted_fixture_aesv3_with_metadata(6, b"user-pw", b"owner-pw", false, Some(XMP));
2909 let doc = Document::load_with_password(bytes, "user-pw").expect("user password opens");
2910
2911 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2912 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2913 assert_eq!(
2914 msg.as_str_bytes().unwrap(),
2915 b"AES-256 secret",
2916 "an ordinary string still decrypts under EncryptMetadata false"
2917 );
2918
2919 let obj5 = doc.get(ObjRef { num: 5, gen: 0 }).unwrap();
2920 let metadata = doc.stream_data(obj5.as_stream().unwrap()).unwrap();
2921 assert_eq!(
2922 metadata, XMP,
2923 "the metadata stream was stored in plaintext and must not be decrypted"
2924 );
2925 }
2926
2927 #[test]
2931 fn encrypt_in_place_reports_an_unavailable_random_source() {
2932 let mut obj = Object::String(b"secret".to_vec());
2933 let mut failing = |_: &mut [u8]| -> crate::error::Result<()> {
2934 Err(crate::error::Error::RandomUnavailable(
2935 "exhausted".to_owned(),
2936 ))
2937 };
2938 let result = encrypt_in_place(&mut obj, &[0u8; 32], &mut failing);
2939 assert!(matches!(
2940 result,
2941 Err(crate::error::Error::RandomUnavailable(_))
2942 ));
2943 }
2944
2945 #[test]
2953 fn r6_key_material_opens_under_aesv3_key() {
2954 let mut c = 0u8;
2955 let mut rng = |b: &mut [u8]| -> std::result::Result<(), std::convert::Infallible> {
2956 for x in b {
2957 c = c.wrapping_add(1);
2958 *x = c;
2959 }
2960 Ok(())
2961 };
2962 let material = match r6_key_material(b"user-pw", b"owner-pw", P, true, &mut rng) {
2963 Ok(material) => material,
2964 Err(never) => match never {},
2965 };
2966 let dict = aes256_encrypt_dict(&material, P);
2967
2968 let user_key = aesv3_key(&dict, 6, b"user-pw").expect("user password opens");
2969 assert_eq!(user_key, material.file_key.to_vec());
2970
2971 let owner_key = aesv3_key(&dict, 6, b"owner-pw").expect("owner password opens");
2972 assert_eq!(owner_key, material.file_key.to_vec());
2973
2974 assert!(aesv3_key(&dict, 6, b"wrong-pw").is_none());
2975
2976 assert!(perms_marker_valid(&material.file_key, &material.perms));
2977
2978 let mut without_perms = dict.clone();
2983 without_perms.remove("Perms");
2984 assert_eq!(
2985 aesv3_key(&without_perms, 6, b"user-pw"),
2986 Some(material.file_key.to_vec())
2987 );
2988 assert_eq!(
2989 aesv3_key(&without_perms, 6, b"owner-pw"),
2990 Some(material.file_key.to_vec())
2991 );
2992 }
2993
2994 #[test]
2997 fn permissions_all_grants_every_bit() {
2998 assert_eq!(Permissions::all().p_value(), -4);
3000 assert_eq!(Permissions::default().p_value(), -4);
3001 }
3002
3003 #[test]
3004 fn permissions_p_value_clears_exactly_its_own_bit() {
3005 let base = Permissions::all().p_value();
3006 assert_eq!(
3007 Permissions {
3008 print: false,
3009 ..Permissions::all()
3010 }
3011 .p_value(),
3012 base & !(1 << 2), );
3014 assert_eq!(
3015 Permissions {
3016 modify: false,
3017 ..Permissions::all()
3018 }
3019 .p_value(),
3020 base & !(1 << 3), );
3022 assert_eq!(
3023 Permissions {
3024 copy: false,
3025 ..Permissions::all()
3026 }
3027 .p_value(),
3028 base & !(1 << 4), );
3030 assert_eq!(
3031 Permissions {
3032 annotate: false,
3033 ..Permissions::all()
3034 }
3035 .p_value(),
3036 base & !(1 << 5), );
3038 assert_eq!(
3039 Permissions {
3040 fill_forms: false,
3041 ..Permissions::all()
3042 }
3043 .p_value(),
3044 base & !(1 << 8), );
3046 assert_eq!(
3047 Permissions {
3048 accessibility: false,
3049 ..Permissions::all()
3050 }
3051 .p_value(),
3052 base & !(1 << 9), );
3054 assert_eq!(
3055 Permissions {
3056 assemble: false,
3057 ..Permissions::all()
3058 }
3059 .p_value(),
3060 base & !(1 << 10), );
3062 assert_eq!(
3063 Permissions {
3064 print_hires: false,
3065 ..Permissions::all()
3066 }
3067 .p_value(),
3068 base & !(1 << 11), );
3070 }
3071
3072 #[allow(clippy::type_complexity, reason = "see Encryptor's rng field")]
3078 fn counter_rng() -> Box<dyn FnMut(&mut [u8]) + Send> {
3079 let mut c = 0u8;
3080 Box::new(move |buf: &mut [u8]| {
3081 for b in buf {
3082 c = c.wrapping_add(1);
3083 *b = c;
3084 }
3085 })
3086 }
3087
3088 fn decryptor_for(dict: &Dict, password: &[u8]) -> Decryptor {
3093 let key = aesv3_key(dict, 6, password).expect("password opens the produced dict");
3094 Decryptor {
3095 key,
3096 filters: CryptFilters::uniform(Cipher::Aesv3),
3097 encrypt_metadata: true,
3098 }
3099 }
3100
3101 #[test]
3102 fn encrypt_object_round_trips_dict_array_and_leaves_other_types_untouched() {
3103 use crate::object::ObjRef;
3104
3105 let (mut enc, dict) =
3106 Encryptor::aes256_with_rng("user-pw", "owner-pw", Permissions::all(), counter_rng());
3107
3108 let mut d = Dict::new();
3109 d.insert(
3110 Name("Msg".to_string()),
3111 Object::String(b"Top secret message".to_vec()),
3112 );
3113 d.insert(
3114 Name("List".to_string()),
3115 Object::Array(vec![
3116 Object::String(b"first".to_vec()),
3117 Object::String(b"second".to_vec()),
3118 ]),
3119 );
3120 d.insert(
3121 Name("Ref".to_string()),
3122 Object::Ref(ObjRef { num: 7, gen: 0 }),
3123 );
3124 d.insert(
3125 Name("Kind".to_string()),
3126 Object::Name(Name("Example".to_string())),
3127 );
3128 d.insert(Name("Count".to_string()), Object::Int(42));
3129 d.insert(Name("Scale".to_string()), Object::Real(1.5));
3130 d.insert(Name("On".to_string()), Object::Bool(true));
3131 d.insert(Name("Missing".to_string()), Object::Null);
3132 let original = Object::Dict(d);
3133
3134 let mut obj = original.clone();
3135 enc.encrypt_object(&mut obj, 3, 0).unwrap();
3136 assert_ne!(obj, original, "encryption must change the strings");
3137
3138 let (enc_dict, orig_dict) = (obj.as_dict().unwrap(), original.as_dict().unwrap());
3141 for key in ["Ref", "Kind", "Count", "Scale", "On", "Missing"] {
3142 assert_eq!(
3143 enc_dict.get(key),
3144 orig_dict.get(key),
3145 "{key} passes through untouched"
3146 );
3147 }
3148
3149 let decryptor = decryptor_for(&dict, b"user-pw");
3150 let mut roundtripped = obj.clone();
3151 decryptor.decrypt_object(&mut roundtripped, 3, 0);
3152 assert_eq!(roundtripped, original);
3153
3154 let owner_decryptor = decryptor_for(&dict, b"owner-pw");
3156 let mut via_owner = obj;
3157 owner_decryptor.decrypt_object(&mut via_owner, 3, 0);
3158 assert_eq!(via_owner, original);
3159 }
3160
3161 #[test]
3162 fn encrypt_object_round_trips_a_stream_and_its_dict() {
3163 use crate::object::Stream;
3164
3165 let (mut enc, dict) =
3166 Encryptor::aes256_with_rng("", "owner-pw", Permissions::all(), counter_rng());
3167
3168 let mut stream_dict = Dict::new();
3169 stream_dict.insert(
3170 Name("Producer".to_string()),
3171 Object::String(b"pdfboss".to_vec()),
3172 );
3173 let original = Object::Stream(Stream {
3174 dict: stream_dict,
3175 data: b"decrypted stream body".to_vec(),
3176 });
3177 let mut obj = original.clone();
3178 enc.encrypt_object(&mut obj, 4, 0).unwrap();
3179 let encrypted = obj.as_stream().unwrap();
3180 assert_ne!(encrypted.data, original.as_stream().unwrap().data);
3181 assert_ne!(
3182 encrypted.dict.get("Producer"),
3183 original.as_stream().unwrap().dict.get("Producer"),
3184 "the stream dict's own strings are encrypted too"
3185 );
3186
3187 let decryptor = decryptor_for(&dict, b"");
3188 let mut roundtripped = obj;
3189 decryptor.decrypt_object(&mut roundtripped, 4, 0);
3190 assert_eq!(roundtripped, original);
3191 }
3192
3193 #[test]
3197 fn encrypt_object_leaves_an_identity_crypt_stream_as_stored() {
3198 use crate::object::Stream;
3199
3200 let (mut enc, dict) =
3201 Encryptor::aes256_with_rng("", "owner-pw", Permissions::all(), counter_rng());
3202 let mut stream_dict = Dict::new();
3203 stream_dict.insert(
3204 Name("Filter".to_string()),
3205 Object::Name(Name("Crypt".to_string())),
3206 );
3207 let mut parms = Dict::new();
3208 parms.insert(
3209 Name("Name".to_string()),
3210 Object::Name(Name("Identity".to_string())),
3211 );
3212 stream_dict.insert(Name("DecodeParms".to_string()), Object::Dict(parms));
3213 let original = Object::Stream(Stream {
3214 dict: stream_dict,
3215 data: b"<?xpacket?> metadata in the clear".to_vec(),
3216 });
3217
3218 let mut obj = original.clone();
3219 enc.encrypt_object(&mut obj, 6, 0).unwrap();
3220 assert_eq!(obj, original, "an Identity stream is written as stored");
3221
3222 let decryptor = decryptor_for(&dict, b"");
3223 decryptor.decrypt_object(&mut obj, 6, 0);
3224 assert_eq!(obj, original, "and read back as stored");
3225 }
3226
3227 #[test]
3228 fn encrypt_object_round_trips_padding_edge_lengths() {
3229 let (mut enc, dict) =
3230 Encryptor::aes256_with_rng("pw", "owner", Permissions::all(), counter_rng());
3231 let decryptor = decryptor_for(&dict, b"pw");
3232
3233 for plaintext in [Vec::new(), vec![0x41], vec![0x42; 16]] {
3234 let original = Object::String(plaintext.clone());
3235 let mut obj = original.clone();
3236 enc.encrypt_object(&mut obj, 1, 0).unwrap();
3237 let mut roundtripped = obj;
3238 decryptor.decrypt_object(&mut roundtripped, 1, 0);
3239 assert_eq!(roundtripped, original, "{} bytes", plaintext.len());
3240 }
3241 }
3242}