1use std::collections::HashMap;
12
13use rpdfium_core::{Name, PdfSource};
14
15use crate::crypto::{self, CryptoError};
16use crate::object::{Object, ObjectId};
17use crate::store::ObjectStore;
18
19const PASSWORD_PADDING: [u8; 32] = [
21 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
22 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
23];
24
25#[derive(Debug, thiserror::Error)]
27pub enum SecurityError {
28 #[error("invalid password")]
30 InvalidPassword,
31 #[error("unsupported encryption version: V={0}, R={1}")]
33 UnsupportedVersion(u32, u32),
34 #[error("missing encryption dictionary key: {0}")]
36 MissingKey(String),
37 #[error("crypto error: {0}")]
39 Crypto(#[from] CryptoError),
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum CryptFilterMethod {
45 None,
47 V2,
49 Aesv2,
51 Aesv3,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct Permissions(i32);
62
63impl Permissions {
64 pub fn from_bits(bits: i32) -> Self {
66 Self(bits)
67 }
68
69 pub fn bits(self) -> i32 {
71 self.0
72 }
73
74 pub fn modify_content(self) -> bool {
76 self.0 & (1 << 3) != 0
77 }
78
79 pub fn modify_annotation(self) -> bool {
81 self.0 & (1 << 5) != 0
82 }
83
84 pub fn fill_form(self) -> bool {
86 self.0 & (1 << 8) != 0
87 }
88
89 pub fn extract_for_accessibility(self) -> bool {
91 self.0 & (1 << 9) != 0
92 }
93}
94
95pub struct SecurityHandler {
98 revision: u32,
99 key_length_bytes: usize,
100 encryption_key: Vec<u8>,
101 permissions: Permissions,
102 encrypt_metadata: bool,
103 stream_cf: CryptFilterMethod,
104 string_cf: CryptFilterMethod,
105 o_value: Vec<u8>,
107 u_value: Vec<u8>,
109 encoded_password: Vec<u8>,
112}
113
114impl SecurityHandler {
115 pub fn from_encrypt_dict<S: PdfSource>(
121 encrypt_dict: &HashMap<Name, Object>,
122 store: &ObjectStore<S>,
123 password: &str,
124 file_id: &[u8],
125 ) -> Result<Self, SecurityError> {
126 let v = get_int(encrypt_dict, store, &Name::v())? as u32;
128 let r = get_int(encrypt_dict, store, &Name::r())? as u32;
129 let p = get_int(encrypt_dict, store, &Name::p())?;
130
131 let o_bytes = get_string_bytes(encrypt_dict, store, &Name::o())?;
132 let u_bytes = get_string_bytes(encrypt_dict, store, &Name::u())?;
133
134 let key_length_bits =
136 get_optional_int(encrypt_dict, store, &Name::length()).unwrap_or(40) as usize;
137 let key_length_bytes = key_length_bits / 8;
138
139 if r <= 4 && !(5..=16).contains(&key_length_bytes) {
142 return Err(SecurityError::UnsupportedVersion(v, r));
143 }
144
145 let encrypt_metadata =
147 get_optional_bool(encrypt_dict, store, &Name::encrypt_metadata()).unwrap_or(true);
148
149 let (stream_cf, string_cf) = if v >= 4 {
151 let stm = parse_single_crypt_filter(encrypt_dict, store, &Name::stm_f());
152 let str_ = parse_single_crypt_filter(encrypt_dict, store, &Name::str_f());
153 (stm, str_)
154 } else if v == 1 || v == 2 || v == 3 {
155 (CryptFilterMethod::V2, CryptFilterMethod::V2)
156 } else {
157 (CryptFilterMethod::None, CryptFilterMethod::None)
158 };
159
160 match (v, r) {
161 (1, 2) | (2, 3) | (3, 3) | (4, 4) => {
162 let pwd_bytes = encode_password_latin1(password);
164 let key = derive_key_r2_r4(
165 &pwd_bytes,
166 &o_bytes,
167 p as i32,
168 file_id,
169 r,
170 key_length_bytes,
171 encrypt_metadata,
172 );
173
174 if verify_user_password_r2_r4(&key, &u_bytes, r, file_id) {
176 return Ok(Self {
177 revision: r,
178 key_length_bytes,
179 encryption_key: key,
180 permissions: Permissions::from_bits(p as i32),
181 encrypt_metadata,
182 stream_cf,
183 string_cf,
184 o_value: o_bytes.clone(),
185 u_value: u_bytes.clone(),
186 encoded_password: pwd_bytes,
187 });
188 }
189
190 let user_password =
192 recover_user_password_from_owner(&pwd_bytes, &o_bytes, r, key_length_bytes);
193 let key = derive_key_r2_r4(
194 &user_password,
195 &o_bytes,
196 p as i32,
197 file_id,
198 r,
199 key_length_bytes,
200 encrypt_metadata,
201 );
202
203 if verify_user_password_r2_r4(&key, &u_bytes, r, file_id) {
204 Ok(Self {
205 revision: r,
206 key_length_bytes,
207 encryption_key: key,
208 permissions: Permissions::from_bits(p as i32),
209 encrypt_metadata,
210 stream_cf,
211 string_cf,
212 o_value: o_bytes,
213 u_value: u_bytes,
214 encoded_password: user_password,
215 })
216 } else {
217 Err(SecurityError::InvalidPassword)
218 }
219 }
220 (5, 5) | (5, 6) => {
221 let oe_bytes = get_string_bytes(encrypt_dict, store, &Name::oe())?;
223 let ue_bytes = get_string_bytes(encrypt_dict, store, &Name::ue())?;
224
225 let key = if r == 5 {
226 derive_key_r5(password, &u_bytes, &ue_bytes, &o_bytes, &oe_bytes)?
227 } else {
228 derive_key_r6(password, &u_bytes, &ue_bytes, &o_bytes, &oe_bytes)?
229 };
230
231 match key {
232 Some(k) => {
233 let perms_bytes = get_string_bytes(encrypt_dict, store, &Name::perms())?;
245 if perms_bytes.len() < 16 {
246 return Err(SecurityError::MissingKey(
247 "Perms (too short, need ≥16 bytes)".into(),
248 ));
249 }
250 let decrypted = crypto::aes256_ecb_decrypt_block(&k, &perms_bytes[..16])?;
251 if &decrypted[9..12] != b"adb" {
255 return Err(SecurityError::InvalidPassword);
256 }
257 let perms_p = i32::from_le_bytes([
259 decrypted[0],
260 decrypted[1],
261 decrypted[2],
262 decrypted[3],
263 ]);
264 if perms_p != p as i32 {
265 return Err(SecurityError::InvalidPassword);
266 }
267
268 Ok(Self {
269 revision: r,
270 key_length_bytes: 32,
271 encryption_key: k,
272 permissions: Permissions::from_bits(p as i32),
273 encrypt_metadata,
274 stream_cf: CryptFilterMethod::Aesv3,
275 string_cf: CryptFilterMethod::Aesv3,
276 o_value: o_bytes,
277 u_value: u_bytes,
278 encoded_password: password.as_bytes().to_vec(),
279 })
280 }
281 None => Err(SecurityError::InvalidPassword),
282 }
283 }
284 _ => Err(SecurityError::UnsupportedVersion(v, r)),
285 }
286 }
287
288 pub fn permissions(&self) -> Permissions {
290 self.permissions
291 }
292
293 #[inline]
297 pub fn get_permissions(&self) -> Permissions {
298 self.permissions()
299 }
300
301 pub fn encoded_password(&self) -> &[u8] {
309 &self.encoded_password
310 }
311
312 #[inline]
316 pub fn get_encoded_password(&self) -> &[u8] {
317 self.encoded_password()
318 }
319
320 pub fn decrypt_string(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
322 if self.string_cf == CryptFilterMethod::None {
323 return data.to_vec();
324 }
325
326 if self.revision >= 5 {
327 crypto::aes256_cbc_decrypt(&self.encryption_key, data).unwrap_or_else(|_| data.to_vec())
329 } else {
330 let object_key = self.compute_object_key(obj_id, self.string_cf);
331 match self.string_cf {
332 CryptFilterMethod::V2 => {
333 crypto::rc4_crypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
334 }
335 CryptFilterMethod::Aesv2 => {
336 crypto::aes128_cbc_decrypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
337 }
338 CryptFilterMethod::Aesv3 => crypto::aes256_cbc_decrypt(&self.encryption_key, data)
339 .unwrap_or_else(|_| data.to_vec()),
340 CryptFilterMethod::None => data.to_vec(),
341 }
342 }
343 }
344
345 pub fn decrypt_stream(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
347 if self.stream_cf == CryptFilterMethod::None {
348 return data.to_vec();
349 }
350
351 if self.revision >= 5 {
352 crypto::aes256_cbc_decrypt(&self.encryption_key, data).unwrap_or_else(|_| data.to_vec())
353 } else {
354 let object_key = self.compute_object_key(obj_id, self.stream_cf);
355 match self.stream_cf {
356 CryptFilterMethod::V2 => {
357 crypto::rc4_crypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
358 }
359 CryptFilterMethod::Aesv2 => {
360 crypto::aes128_cbc_decrypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
361 }
362 CryptFilterMethod::Aesv3 => crypto::aes256_cbc_decrypt(&self.encryption_key, data)
363 .unwrap_or_else(|_| data.to_vec()),
364 CryptFilterMethod::None => data.to_vec(),
365 }
366 }
367 }
368
369 pub fn is_metadata_encrypted(&self) -> bool {
373 self.encrypt_metadata
374 }
375
376 pub fn revision(&self) -> u32 {
378 self.revision
379 }
380
381 pub fn crypt_filter_method(&self) -> CryptFilterMethod {
383 self.stream_cf
384 }
385
386 pub fn key_length_bytes(&self) -> usize {
388 self.key_length_bytes
389 }
390
391 pub fn encryption_key(&self) -> &[u8] {
393 &self.encryption_key
394 }
395
396 pub fn stream_crypt_filter(&self) -> CryptFilterMethod {
398 self.stream_cf
399 }
400
401 pub fn string_crypt_filter(&self) -> CryptFilterMethod {
403 self.string_cf
404 }
405
406 pub fn o_value(&self) -> &[u8] {
408 &self.o_value
409 }
410
411 pub fn u_value(&self) -> &[u8] {
413 &self.u_value
414 }
415
416 pub fn version(&self) -> u32 {
420 match self.revision {
421 2 => 1,
422 3 | 4 => {
423 if self.stream_cf == CryptFilterMethod::V2
424 && self.string_cf == CryptFilterMethod::V2
425 {
426 if self.key_length_bytes == 5 { 1 } else { 2 }
427 } else {
428 4
429 }
430 }
431 5 | 6 => 5,
432 _ => 0,
433 }
434 }
435
436 pub fn encrypt_string(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
442 if self.string_cf == CryptFilterMethod::None {
443 return data.to_vec();
444 }
445 self.encrypt_with_method(data, obj_id, self.string_cf)
446 }
447
448 pub fn encrypt_stream(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
450 if self.stream_cf == CryptFilterMethod::None {
451 return data.to_vec();
452 }
453 self.encrypt_with_method(data, obj_id, self.stream_cf)
454 }
455
456 fn encrypt_with_method(&self, data: &[u8], obj_id: ObjectId, cf: CryptFilterMethod) -> Vec<u8> {
474 let iv = Self::generate_iv();
475
476 if self.revision >= 5 {
477 let encrypted = crypto::aes256_cbc_encrypt(&self.encryption_key, &iv, data)
478 .expect("AES-256 encryption failed: key size validated at construction");
479 let mut result = iv.to_vec();
480 result.extend_from_slice(&encrypted);
481 result
482 } else {
483 let object_key = self.compute_object_key(obj_id, cf);
484 match cf {
485 CryptFilterMethod::V2 => crypto::rc4_crypt(&object_key, data)
486 .expect("RC4 encryption failed: key size validated at construction"),
487 CryptFilterMethod::Aesv2 => {
488 let encrypted = crypto::aes128_cbc_encrypt(&object_key, &iv, data)
489 .expect("AES-128 encryption failed: key size validated at construction");
490 let mut result = iv.to_vec();
491 result.extend_from_slice(&encrypted);
492 result
493 }
494 CryptFilterMethod::Aesv3 => {
495 let encrypted = crypto::aes256_cbc_encrypt(&self.encryption_key, &iv, data)
496 .expect("AES-256 encryption failed: key size validated at construction");
497 let mut result = iv.to_vec();
498 result.extend_from_slice(&encrypted);
499 result
500 }
501 CryptFilterMethod::None => data.to_vec(),
502 }
503 }
504 }
505
506 fn generate_iv() -> [u8; 16] {
517 let mut iv = [0u8; 16];
518 getrandom::fill(&mut iv).expect("OS RNG unavailable");
519 iv
520 }
521
522 fn compute_object_key(&self, obj_id: ObjectId, cf: CryptFilterMethod) -> Vec<u8> {
530 let obj_num = obj_id.number;
531 let gen_num = obj_id.generation;
532
533 let mut buf = Vec::with_capacity(self.encryption_key.len() + 9);
534 buf.extend_from_slice(&self.encryption_key);
535 buf.push((obj_num & 0xFF) as u8);
537 buf.push(((obj_num >> 8) & 0xFF) as u8);
538 buf.push(((obj_num >> 16) & 0xFF) as u8);
539 buf.push((gen_num & 0xFF) as u8);
541 buf.push(((gen_num >> 8) & 0xFF) as u8);
542
543 if cf == CryptFilterMethod::Aesv2 {
544 buf.extend_from_slice(&[0x73, 0x41, 0x6C, 0x54]);
546 }
547
548 let hash = crypto::md5(&buf);
549 let n = std::cmp::min(self.key_length_bytes + 5, 16);
550 hash[..n].to_vec()
551 }
552}
553
554fn encode_password_latin1(password: &str) -> Vec<u8> {
561 password
562 .chars()
563 .map(|c| {
564 let code = c as u32;
565 if code <= 255 {
566 code as u8
567 } else {
568 0x3F }
570 })
571 .collect()
572}
573
574fn pad_password(password: &[u8]) -> [u8; 32] {
576 let mut padded = [0u8; 32];
577 let copy_len = std::cmp::min(password.len(), 32);
578 padded[..copy_len].copy_from_slice(&password[..copy_len]);
579 if copy_len < 32 {
580 padded[copy_len..].copy_from_slice(&PASSWORD_PADDING[..(32 - copy_len)]);
581 }
582 padded
583}
584
585fn derive_key_r2_r4(
587 password: &[u8],
588 o_value: &[u8],
589 permissions: i32,
590 file_id: &[u8],
591 revision: u32,
592 key_length_bytes: usize,
593 encrypt_metadata: bool,
594) -> Vec<u8> {
595 let padded = pad_password(password);
596
597 let mut buf = Vec::with_capacity(32 + o_value.len() + 4 + file_id.len() + 4);
598 buf.extend_from_slice(&padded);
599 buf.extend_from_slice(o_value);
600 buf.extend_from_slice(&(permissions as u32).to_le_bytes());
601 buf.extend_from_slice(file_id);
602
603 if revision >= 4 && !encrypt_metadata {
604 buf.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
605 }
606
607 let mut hash = crypto::md5(&buf);
608
609 if revision >= 3 {
610 for _ in 0..50 {
611 hash = crypto::md5(&hash[..key_length_bytes]);
612 }
613 }
614
615 hash[..key_length_bytes].to_vec()
616}
617
618fn verify_user_password_r2(key: &[u8], u_value: &[u8]) -> bool {
624 let Ok(decrypted) = crypto::rc4_crypt(key, u_value) else {
625 return false;
626 };
627 let expected = crypto::md5(&PASSWORD_PADDING);
628 decrypted[..] == expected[..]
629}
630
631fn verify_user_password_r3_r4(key: &[u8], u_value: &[u8], file_id: &[u8]) -> bool {
637 let mut buf = Vec::with_capacity(32 + file_id.len());
639 buf.extend_from_slice(&PASSWORD_PADDING);
640 buf.extend_from_slice(file_id);
641 let hash = crypto::md5(&buf);
642
643 let Ok(mut result) = crypto::rc4_crypt(key, &hash) else {
645 return false;
646 };
647
648 for i in 1..=19u8 {
650 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
651 let Ok(next) = crypto::rc4_crypt(&modified_key, &result) else {
652 return false;
653 };
654 result = next;
655 }
656
657 u_value.len() >= 16 && result.len() >= 16 && result[..16] == u_value[..16]
659}
660
661fn verify_user_password_r2_r4(key: &[u8], u_value: &[u8], revision: u32, file_id: &[u8]) -> bool {
663 if revision == 2 {
664 verify_user_password_r2(key, u_value)
665 } else {
666 verify_user_password_r3_r4(key, u_value, file_id)
667 }
668}
669
670fn recover_user_password_from_owner(
676 owner_password: &[u8],
677 o_value: &[u8],
678 revision: u32,
679 key_length_bytes: usize,
680) -> Vec<u8> {
681 let padded = pad_password(owner_password);
682 let mut hash = crypto::md5(&padded);
683
684 if revision >= 3 {
685 for _ in 0..50 {
686 hash = crypto::md5(&hash[..key_length_bytes]);
687 }
688 }
689
690 let key = &hash[..key_length_bytes];
691
692 if revision == 2 {
693 crypto::rc4_crypt(key, o_value)
694 .expect("RC4 key size validated from MD5 hash (always 5-16 bytes)")
695 } else {
696 let mut result = o_value.to_vec();
697 for i in (0..=19u8).rev() {
698 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
699 result = crypto::rc4_crypt(&modified_key, &result)
700 .expect("RC4 key size validated from MD5 hash (always 5-16 bytes)");
701 }
702 result
703 }
704}
705
706fn derive_key_r5(
714 password: &str,
715 u_value: &[u8],
716 ue_value: &[u8],
717 o_value: &[u8],
718 oe_value: &[u8],
719) -> Result<Option<Vec<u8>>, CryptoError> {
720 let pwd = truncate_utf8_password(password);
721
722 if u_value.len() >= 48 && ue_value.len() >= 32 {
724 let validation_salt = &u_value[32..40];
725 let hash = compute_r5_hash(&pwd, validation_salt);
726 if hash[..] == u_value[..32] {
727 let key_salt = &u_value[40..48];
729 let key_hash = compute_r5_hash(&pwd, key_salt);
730 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(ue_value))?;
731 return Ok(Some(file_key));
732 }
733 }
734
735 if o_value.len() >= 48 && oe_value.len() >= 32 && u_value.len() >= 48 {
737 let validation_salt = &o_value[32..40];
738 let mut input = Vec::with_capacity(pwd.len() + 8 + 48);
739 input.extend_from_slice(&pwd);
740 input.extend_from_slice(validation_salt);
741 input.extend_from_slice(&u_value[..48]);
742 let hash = crypto::sha256(&input);
743 if hash[..] == o_value[..32] {
744 let key_salt = &o_value[40..48];
745 let mut key_input = Vec::with_capacity(pwd.len() + 8 + 48);
746 key_input.extend_from_slice(&pwd);
747 key_input.extend_from_slice(key_salt);
748 key_input.extend_from_slice(&u_value[..48]);
749 let key_hash = crypto::sha256(&key_input);
750 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(oe_value))?;
751 return Ok(Some(file_key));
752 }
753 }
754
755 Ok(None)
756}
757
758fn derive_key_r6(
762 password: &str,
763 u_value: &[u8],
764 ue_value: &[u8],
765 o_value: &[u8],
766 oe_value: &[u8],
767) -> Result<Option<Vec<u8>>, CryptoError> {
768 let pwd = truncate_utf8_password(password);
769
770 if u_value.len() >= 48 && ue_value.len() >= 32 {
772 let validation_salt = &u_value[32..40];
773 let hash = compute_r6_hash(&pwd, validation_salt, &[]);
774 if hash[..] == u_value[..32] {
775 let key_salt = &u_value[40..48];
777 let key_hash = compute_r6_hash(&pwd, key_salt, &[]);
778 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(ue_value))?;
779 return Ok(Some(file_key));
780 }
781 }
782
783 if o_value.len() >= 48 && oe_value.len() >= 32 && u_value.len() >= 48 {
785 let validation_salt = &o_value[32..40];
786 let hash = compute_r6_hash(&pwd, validation_salt, &u_value[..48]);
787 if hash[..] == o_value[..32] {
788 let key_salt = &o_value[40..48];
789 let key_hash = compute_r6_hash(&pwd, key_salt, &u_value[..48]);
790 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(oe_value))?;
791 return Ok(Some(file_key));
792 }
793 }
794
795 Ok(None)
796}
797
798fn big_endian_mod3(bytes: &[u8]) -> u32 {
800 bytes
801 .iter()
802 .take(16)
803 .fold(0u32, |acc, &b| (acc * 256 + b as u32) % 3)
804}
805
806fn compute_r6_hash(password: &[u8], salt: &[u8], u_value: &[u8]) -> [u8; 32] {
811 let mut input = Vec::with_capacity(password.len() + salt.len() + u_value.len());
813 input.extend_from_slice(password);
814 input.extend_from_slice(salt);
815 input.extend_from_slice(u_value);
816 let mut k = crypto::sha256(&input);
817
818 let mut round: u32 = 0;
819 loop {
820 let sequence_len = password.len() + k.len() + u_value.len();
822 let mut k1 = Vec::with_capacity(sequence_len * 64);
823 for _ in 0..64 {
824 k1.extend_from_slice(password);
825 k1.extend_from_slice(&k);
826 k1.extend_from_slice(u_value);
827 }
828
829 let aes_key = &k[..16];
831 let aes_iv = &k[16..32];
832 let e = crypto::aes128_cbc_encrypt(aes_key, aes_iv, &k1)
834 .expect("AES-128-CBC key/IV from SHA-256 are always valid");
835
836 let hash_select = big_endian_mod3(&e);
838
839 match hash_select {
841 0 => {
842 let h = crypto::sha256(&e);
843 k = h;
844 }
845 1 => {
846 let h = crypto::sha384(&e);
847 k.copy_from_slice(&h[..32]);
848 }
849 _ => {
850 let h = crypto::sha512(&e);
851 k.copy_from_slice(&h[..32]);
852 }
853 }
854
855 if round >= 64 {
857 let last_byte = *e.last().unwrap_or(&0);
858 if last_byte <= (round - 32) as u8 {
859 break;
860 }
861 }
862
863 round += 1;
864
865 if round >= 1000 {
867 break;
868 }
869 }
870
871 k
872}
873
874fn compute_r5_hash(password: &[u8], salt: &[u8]) -> [u8; 32] {
876 let mut input = Vec::with_capacity(password.len() + salt.len());
877 input.extend_from_slice(password);
878 input.extend_from_slice(salt);
879 crypto::sha256(&input)
880}
881
882fn truncate_utf8_password(password: &str) -> Vec<u8> {
884 let bytes = password.as_bytes();
885 if bytes.len() <= 127 {
886 bytes.to_vec()
887 } else {
888 bytes[..127].to_vec()
889 }
890}
891
892fn prepend_zero_iv(data: &[u8]) -> Vec<u8> {
894 let mut result = vec![0u8; 16];
895 result.extend_from_slice(data);
896 result
897}
898
899fn parse_single_crypt_filter<S: PdfSource>(
906 encrypt_dict: &HashMap<Name, Object>,
907 store: &ObjectStore<S>,
908 filter_key: &Name,
909) -> CryptFilterMethod {
910 let filter_name = encrypt_dict
911 .get(filter_key)
912 .and_then(|obj| store.deep_resolve(obj).ok())
913 .and_then(|obj| obj.as_name())
914 .cloned()
915 .unwrap_or_else(|| Name::from("StdCF"));
916
917 if filter_name == Name::from("Identity") {
918 return CryptFilterMethod::None;
919 }
920
921 let cf_dict = encrypt_dict
923 .get(&Name::cf())
924 .and_then(|obj| store.deep_resolve(obj).ok())
925 .and_then(|obj| obj.as_dict());
926
927 if let Some(cf) = cf_dict {
928 if let Some(filter_obj) = cf.get(&filter_name) {
929 if let Ok(filter_resolved) = store.deep_resolve(filter_obj) {
930 if let Some(filter_dict) = filter_resolved.as_dict() {
931 let method = filter_dict
932 .get(&Name::cfm())
933 .and_then(|obj| store.deep_resolve(obj).ok())
934 .and_then(|obj| obj.as_name())
935 .cloned();
936
937 if let Some(m) = method {
938 if m == Name::aesv2() {
939 return CryptFilterMethod::Aesv2;
940 } else if m == Name::aesv3() {
941 return CryptFilterMethod::Aesv3;
942 } else if m == Name::v2() {
943 return CryptFilterMethod::V2;
944 } else if m == Name::none() {
945 return CryptFilterMethod::None;
946 }
947 }
948 }
949 }
950 }
951 }
952
953 CryptFilterMethod::V2
955}
956
957fn get_int<S: PdfSource>(
962 dict: &HashMap<Name, Object>,
963 store: &ObjectStore<S>,
964 key: &Name,
965) -> Result<i64, SecurityError> {
966 dict.get(key)
967 .and_then(|obj| store.deep_resolve(obj).ok())
968 .and_then(|obj| obj.as_i64())
969 .ok_or_else(|| SecurityError::MissingKey(key.to_string()))
970}
971
972fn get_optional_int<S: PdfSource>(
973 dict: &HashMap<Name, Object>,
974 store: &ObjectStore<S>,
975 key: &Name,
976) -> Option<i64> {
977 dict.get(key)
978 .and_then(|obj| store.deep_resolve(obj).ok())
979 .and_then(|obj| obj.as_i64())
980}
981
982fn get_optional_bool<S: PdfSource>(
983 dict: &HashMap<Name, Object>,
984 store: &ObjectStore<S>,
985 key: &Name,
986) -> Option<bool> {
987 dict.get(key)
988 .and_then(|obj| store.deep_resolve(obj).ok())
989 .and_then(|obj| obj.as_bool())
990}
991
992fn get_string_bytes<S: PdfSource>(
993 dict: &HashMap<Name, Object>,
994 store: &ObjectStore<S>,
995 key: &Name,
996) -> Result<Vec<u8>, SecurityError> {
997 dict.get(key)
998 .and_then(|obj| store.deep_resolve(obj).ok())
999 .and_then(|obj| obj.as_string())
1000 .map(|s| s.as_bytes().to_vec())
1001 .ok_or_else(|| SecurityError::MissingKey(key.to_string()))
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006 use super::*;
1007
1008 #[test]
1009 fn test_password_padding_empty() {
1010 let padded = pad_password(b"");
1011 assert_eq!(padded, PASSWORD_PADDING);
1012 }
1013
1014 #[test]
1015 fn test_password_padding_short() {
1016 let padded = pad_password(b"test");
1017 assert_eq!(&padded[..4], b"test");
1018 assert_eq!(&padded[4..], &PASSWORD_PADDING[..28]);
1019 }
1020
1021 #[test]
1022 fn test_password_padding_exact_32() {
1023 let pwd = b"abcdefghijklmnopqrstuvwxyz012345"; let padded = pad_password(pwd);
1025 assert_eq!(&padded[..], &pwd[..]);
1026 }
1027
1028 #[test]
1029 fn test_password_padding_longer_than_32() {
1030 let pwd = b"abcdefghijklmnopqrstuvwxyz0123456789"; let padded = pad_password(pwd);
1032 assert_eq!(&padded[..], &pwd[..32]);
1033 }
1034
1035 #[test]
1036 fn test_key_derivation_r2_known() {
1037 let o_value = [0u8; 32];
1039 let file_id = b"test_file_id_123";
1040 let key = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
1041 assert_eq!(key.len(), 5);
1042 let key2 = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
1044 assert_eq!(key, key2);
1045 }
1046
1047 #[test]
1048 fn test_key_derivation_r3_known() {
1049 let o_value = [0u8; 32];
1050 let file_id = b"test_file_id_123";
1051 let key = derive_key_r2_r4(b"", &o_value, -44, file_id, 3, 16, true);
1052 assert_eq!(key.len(), 16);
1053 let key_r2 = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
1055 assert_ne!(key[..5], key_r2[..]);
1056 }
1057
1058 #[test]
1059 fn test_user_password_verification_r2_round_trip() {
1060 let o_value = [0x42u8; 32];
1062 let file_id = b"abcdef0123456789";
1063 let key = derive_key_r2_r4(b"password", &o_value, -4, file_id, 2, 5, true);
1064
1065 let expected_u = crypto::rc4_crypt(&key, &crypto::md5(&PASSWORD_PADDING)).unwrap();
1067 assert!(verify_user_password_r2(&key, &expected_u));
1068 }
1069
1070 #[test]
1071 fn test_user_password_verification_r2_wrong_password() {
1072 let o_value = [0x42u8; 32];
1073 let file_id = b"abcdef0123456789";
1074 let key = derive_key_r2_r4(b"password", &o_value, -4, file_id, 2, 5, true);
1075 let expected_u = crypto::rc4_crypt(&key, &crypto::md5(&PASSWORD_PADDING)).unwrap();
1076
1077 let wrong_key = derive_key_r2_r4(b"wrong", &o_value, -4, file_id, 2, 5, true);
1079 assert!(!verify_user_password_r2(&wrong_key, &expected_u));
1080 }
1081
1082 #[test]
1083 fn test_user_password_verification_r3_round_trip() {
1084 let o_value = [0x42u8; 32];
1085 let file_id = b"abcdef0123456789";
1086 let key = derive_key_r2_r4(b"pass", &o_value, -4, file_id, 3, 16, true);
1087
1088 let mut buf = Vec::new();
1090 buf.extend_from_slice(&PASSWORD_PADDING);
1091 buf.extend_from_slice(file_id);
1092 let hash = crypto::md5(&buf);
1093
1094 let mut result = crypto::rc4_crypt(&key, &hash).unwrap();
1095 for i in 1..=19u8 {
1096 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
1097 result = crypto::rc4_crypt(&modified_key, &result).unwrap();
1098 }
1099 let mut u_value = result;
1101 u_value.resize(32, 0);
1102
1103 assert!(verify_user_password_r3_r4(&key, &u_value, file_id));
1104 }
1105
1106 #[test]
1107 fn test_object_key_computation() {
1108 let handler = SecurityHandler {
1109 revision: 3,
1110 key_length_bytes: 5,
1111 encryption_key: vec![0x01, 0x02, 0x03, 0x04, 0x05],
1112 permissions: Permissions::from_bits(-4),
1113 encrypt_metadata: true,
1114 stream_cf: CryptFilterMethod::V2,
1115 string_cf: CryptFilterMethod::V2,
1116 o_value: Vec::new(),
1117 u_value: Vec::new(),
1118 encoded_password: Vec::new(),
1119 };
1120
1121 let obj_id = ObjectId::new(10, 0);
1122 let key = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1123
1124 assert_eq!(key.len(), 10);
1126
1127 let key2 = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1129 assert_eq!(key, key2);
1130
1131 let key3 = handler.compute_object_key(ObjectId::new(11, 0), CryptFilterMethod::V2);
1133 assert_ne!(key, key3);
1134 }
1135
1136 #[test]
1137 fn test_object_key_aesv2_includes_salt() {
1138 let handler = SecurityHandler {
1139 revision: 4,
1140 key_length_bytes: 16,
1141 encryption_key: vec![0xAA; 16],
1142 permissions: Permissions::from_bits(-4),
1143 encrypt_metadata: true,
1144 stream_cf: CryptFilterMethod::Aesv2,
1145 string_cf: CryptFilterMethod::V2,
1146 o_value: Vec::new(),
1147 u_value: Vec::new(),
1148 encoded_password: Vec::new(),
1149 };
1150
1151 let obj_id = ObjectId::new(1, 0);
1152 let key_rc4 = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1153 let key_aes = handler.compute_object_key(obj_id, CryptFilterMethod::Aesv2);
1154
1155 assert_ne!(key_rc4, key_aes);
1157 }
1158
1159 #[test]
1160 fn test_decrypt_string_rc4_round_trip() {
1161 let handler = SecurityHandler {
1162 revision: 3,
1163 key_length_bytes: 5,
1164 encryption_key: vec![0x01, 0x02, 0x03, 0x04, 0x05],
1165 permissions: Permissions::from_bits(-4),
1166 encrypt_metadata: true,
1167 stream_cf: CryptFilterMethod::V2,
1168 string_cf: CryptFilterMethod::V2,
1169 o_value: Vec::new(),
1170 u_value: Vec::new(),
1171 encoded_password: Vec::new(),
1172 };
1173
1174 let obj_id = ObjectId::new(1, 0);
1175 let plaintext = b"Hello, encrypted world!";
1176
1177 let object_key = handler.compute_object_key(obj_id, handler.string_cf);
1179 let encrypted = crypto::rc4_crypt(&object_key, plaintext).unwrap();
1180
1181 let decrypted = handler.decrypt_string(&encrypted, obj_id);
1183 assert_eq!(decrypted, plaintext);
1184 }
1185
1186 #[test]
1187 fn test_crypt_filter_method_none_passthrough() {
1188 let handler = SecurityHandler {
1189 revision: 4,
1190 key_length_bytes: 16,
1191 encryption_key: vec![0; 16],
1192 permissions: Permissions::from_bits(-4),
1193 encrypt_metadata: true,
1194 stream_cf: CryptFilterMethod::None,
1195 string_cf: CryptFilterMethod::None,
1196 o_value: Vec::new(),
1197 u_value: Vec::new(),
1198 encoded_password: Vec::new(),
1199 };
1200
1201 let data = b"unencrypted data";
1202 let obj_id = ObjectId::new(1, 0);
1203 assert_eq!(handler.decrypt_string(data, obj_id), data);
1204 assert_eq!(handler.decrypt_stream(data, obj_id), data);
1205 }
1206
1207 #[test]
1208 fn test_truncate_utf8_password_short() {
1209 let pwd = truncate_utf8_password("hello");
1210 assert_eq!(pwd, b"hello");
1211 }
1212
1213 #[test]
1214 fn test_truncate_utf8_password_long() {
1215 let long_pwd = "a".repeat(200);
1216 let pwd = truncate_utf8_password(&long_pwd);
1217 assert_eq!(pwd.len(), 127);
1218 }
1219
1220 #[test]
1221 fn test_compute_r6_hash_basic() {
1222 let hash = compute_r6_hash(b"password", &[0u8; 8], &[]);
1224 assert_eq!(hash.len(), 32);
1225 let hash2 = compute_r6_hash(b"password", &[0u8; 8], &[]);
1227 assert_eq!(hash, hash2);
1228 }
1229
1230 #[test]
1231 fn test_compute_r6_hash_differs_from_simple_sha256() {
1232 let salt = [0x01u8; 8];
1234 let r6_hash = compute_r6_hash(b"test", &salt, &[]);
1235 let simple_hash = crypto::sha256(&{
1236 let mut v = b"test".to_vec();
1237 v.extend_from_slice(&salt);
1238 v
1239 });
1240 assert_ne!(r6_hash, simple_hash);
1243 }
1244
1245 #[test]
1246 fn test_compute_r6_hash_with_u_value() {
1247 let salt = [0x42u8; 8];
1249 let hash_no_u = compute_r6_hash(b"pwd", &salt, &[]);
1250 let hash_with_u = compute_r6_hash(b"pwd", &salt, &[0xAAu8; 48]);
1251 assert_ne!(hash_no_u, hash_with_u);
1252 }
1253
1254 #[test]
1255 fn test_r6_user_password_round_trip() {
1256 let password = b"test123";
1258 let validation_salt = [0x11u8; 8];
1259 let key_salt = [0x22u8; 8];
1260 let file_key = [0x42u8; 32]; let u_hash = compute_r6_hash(password, &validation_salt, &[]);
1264 let mut u_value = Vec::with_capacity(48);
1265 u_value.extend_from_slice(&u_hash);
1266 u_value.extend_from_slice(&validation_salt);
1267 u_value.extend_from_slice(&key_salt);
1268
1269 let key_hash = compute_r6_hash(password, &key_salt, &[]);
1271 let iv = [0u8; 16];
1272 let ue_value = crypto::aes256_cbc_encrypt(&key_hash, &iv, &file_key).unwrap();
1273
1274 let result = derive_key_r6(
1276 "test123", &u_value, &ue_value, &[0u8; 48], &[0u8; 32], )
1279 .unwrap();
1280
1281 assert!(result.is_some());
1282 assert_eq!(result.unwrap(), file_key);
1283 }
1284
1285 #[test]
1286 fn test_r6_wrong_password_returns_none() {
1287 let password = b"correct";
1288 let validation_salt = [0x33u8; 8];
1289 let key_salt = [0x44u8; 8];
1290
1291 let u_hash = compute_r6_hash(password, &validation_salt, &[]);
1292 let mut u_value = Vec::with_capacity(48);
1293 u_value.extend_from_slice(&u_hash);
1294 u_value.extend_from_slice(&validation_salt);
1295 u_value.extend_from_slice(&key_salt);
1296
1297 let key_hash = compute_r6_hash(password, &key_salt, &[]);
1298 let ue_value = crypto::aes256_cbc_encrypt(&key_hash, &[0u8; 16], &[0u8; 32]).unwrap();
1299
1300 let result = derive_key_r6("wrong", &u_value, &ue_value, &[0u8; 48], &[0u8; 32]).unwrap();
1302
1303 assert!(result.is_none());
1304 }
1305
1306 #[test]
1307 fn test_owner_password_recovery_r2() {
1308 let user_pwd = b"user";
1310 let owner_pwd = b"owner";
1311 let key_len = 5;
1312
1313 let padded_owner = pad_password(owner_pwd);
1315 let hash = crypto::md5(&padded_owner);
1316 let owner_key = &hash[..key_len];
1317 let padded_user = pad_password(user_pwd);
1318 let o_value = crypto::rc4_crypt(owner_key, &padded_user).unwrap();
1319
1320 let recovered = recover_user_password_from_owner(owner_pwd, &o_value, 2, key_len);
1322 assert_eq!(&recovered[..], &padded_user[..]);
1323 }
1324
1325 #[test]
1330 fn test_password_padding_matches_pdf_spec() {
1331 let spec_padding: [u8; 32] = [
1333 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA,
1334 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE,
1335 0x64, 0x53, 0x69, 0x7A,
1336 ];
1337 assert_eq!(PASSWORD_PADDING, spec_padding);
1338 }
1339
1340 #[test]
1345 fn test_big_endian_mod3_basic() {
1346 assert_eq!(big_endian_mod3(&[0u8; 16]), 0);
1348 assert_eq!(big_endian_mod3(&[0xFF; 16]), big_endian_mod3(&[0xFF; 16]));
1350 }
1351
1352 #[test]
1353 fn test_big_endian_mod3_differs_from_sum_mod3() {
1354 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
1379 assert_eq!(big_endian_mod3(&bytes), 1);
1380 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2];
1381 assert_eq!(big_endian_mod3(&bytes), 2);
1382 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3];
1383 assert_eq!(big_endian_mod3(&bytes), 0);
1384 }
1385
1386 #[test]
1391 fn test_separate_strf_stmf_decrypt() {
1392 let handler = SecurityHandler {
1394 revision: 4,
1395 key_length_bytes: 16,
1396 encryption_key: vec![0xBB; 16],
1397 permissions: Permissions::from_bits(-4),
1398 encrypt_metadata: true,
1399 stream_cf: CryptFilterMethod::Aesv2,
1400 string_cf: CryptFilterMethod::V2,
1401 o_value: Vec::new(),
1402 u_value: Vec::new(),
1403 encoded_password: Vec::new(),
1404 };
1405
1406 assert_eq!(handler.crypt_filter_method(), CryptFilterMethod::Aesv2);
1408
1409 let obj_id = ObjectId::new(1, 0);
1410
1411 let plaintext = b"hello";
1413 let obj_key_str = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1414 let encrypted_str = crypto::rc4_crypt(&obj_key_str, plaintext).unwrap();
1415 let decrypted = handler.decrypt_string(&encrypted_str, obj_id);
1416 assert_eq!(decrypted, plaintext);
1417
1418 let obj_key_stm = handler.compute_object_key(obj_id, CryptFilterMethod::Aesv2);
1420 assert_ne!(obj_key_str, obj_key_stm); }
1422
1423 #[test]
1428 fn test_encode_password_latin1_ascii() {
1429 let encoded = encode_password_latin1("hello");
1430 assert_eq!(encoded, b"hello");
1431 }
1432
1433 #[test]
1434 fn test_encode_password_latin1_latin_chars() {
1435 let encoded = encode_password_latin1("\u{00E9}");
1437 assert_eq!(encoded, vec![0xE9]);
1438 }
1439
1440 #[test]
1441 fn test_encode_password_latin1_non_latin() {
1442 let encoded = encode_password_latin1("\u{4E2D}");
1444 assert_eq!(encoded, vec![0x3F]);
1445 }
1446
1447 #[test]
1448 fn test_encode_password_latin1_mixed() {
1449 let encoded = encode_password_latin1("a\u{00FC}\u{4E2D}b");
1451 assert_eq!(encoded, vec![b'a', 0xFC, 0x3F, b'b']);
1452 }
1453
1454 #[test]
1459 fn test_encode_password_latin1_empty() {
1460 let encoded = encode_password_latin1("");
1461 assert!(encoded.is_empty());
1462 }
1463
1464 #[test]
1465 fn test_encode_password_latin1_ascii_alphanumeric() {
1466 let encoded = encode_password_latin1("ABC123");
1467 assert_eq!(encoded, b"ABC123");
1468 }
1469
1470 #[test]
1471 fn test_encode_password_latin1_0xff() {
1472 let encoded = encode_password_latin1("\u{00FF}");
1474 assert_eq!(encoded, vec![0xFF]);
1475 }
1476
1477 #[test]
1478 fn test_encode_password_latin1_over_range() {
1479 let encoded = encode_password_latin1("\u{0100}");
1481 assert_eq!(encoded, vec![0x3F]); }
1483
1484 #[test]
1485 fn test_truncate_utf8_password_empty() {
1486 let pwd = truncate_utf8_password("");
1487 assert!(pwd.is_empty());
1488 }
1489
1490 #[test]
1491 fn test_truncate_utf8_password_exact_127() {
1492 let input = "a".repeat(127);
1493 let pwd = truncate_utf8_password(&input);
1494 assert_eq!(pwd.len(), 127);
1495 assert_eq!(pwd, input.as_bytes());
1496 }
1497
1498 #[test]
1499 fn test_truncate_utf8_password_over_127() {
1500 let input = "a".repeat(128);
1501 let pwd = truncate_utf8_password(&input);
1502 assert_eq!(pwd.len(), 127);
1503 }
1504
1505 #[test]
1506 fn test_perms_validation_construct_and_verify() {
1507 let permissions: i32 = -4;
1512 let mut perms_plain = [0u8; 16];
1513 perms_plain[0..4].copy_from_slice(&permissions.to_le_bytes());
1514 perms_plain[8] = b'T'; perms_plain[9] = b'a';
1517 perms_plain[10] = b'd';
1518 perms_plain[11] = b'b';
1519
1520 let file_key = [0x42u8; 32];
1522 use aes::cipher::{BlockEncrypt, KeyInit};
1525 let cipher = aes::Aes256::new_from_slice(&file_key).unwrap();
1526 let mut block = aes::cipher::generic_array::GenericArray::clone_from_slice(&perms_plain);
1527 cipher.encrypt_block(&mut block);
1528 let encrypted_perms: [u8; 16] = block.into();
1529
1530 let decrypted = crypto::aes256_ecb_decrypt_block(&file_key, &encrypted_perms).unwrap();
1532
1533 assert_eq!(decrypted[8], b'T');
1535 assert_eq!(&decrypted[9..12], b"adb");
1536 let recovered_p =
1537 i32::from_le_bytes([decrypted[0], decrypted[1], decrypted[2], decrypted[3]]);
1538 assert_eq!(recovered_p, permissions);
1539 }
1540
1541 #[test]
1542 fn test_get_permissions_alias_delegates_to_permissions() {
1543 let handler = SecurityHandler {
1544 revision: 3,
1545 key_length_bytes: 5,
1546 encryption_key: vec![0x01; 5],
1547 permissions: Permissions::from_bits(-4),
1548 encrypt_metadata: true,
1549 stream_cf: CryptFilterMethod::V2,
1550 string_cf: CryptFilterMethod::V2,
1551 o_value: Vec::new(),
1552 u_value: Vec::new(),
1553 encoded_password: b"secret".to_vec(),
1554 };
1555 assert_eq!(handler.get_permissions(), handler.permissions());
1556 }
1557
1558 #[test]
1559 fn test_encoded_password_stored_and_accessible() {
1560 let handler = SecurityHandler {
1561 revision: 3,
1562 key_length_bytes: 5,
1563 encryption_key: vec![0x01; 5],
1564 permissions: Permissions::from_bits(-4),
1565 encrypt_metadata: true,
1566 stream_cf: CryptFilterMethod::V2,
1567 string_cf: CryptFilterMethod::V2,
1568 o_value: Vec::new(),
1569 u_value: Vec::new(),
1570 encoded_password: b"my_password".to_vec(),
1571 };
1572 assert_eq!(handler.encoded_password(), b"my_password");
1573 }
1574
1575 #[test]
1585 fn test_security_handler_stores_encoded_password_user_path() {
1586 let password = "test";
1588 let pwd_bytes = encode_password_latin1(password);
1589 let o_value = [0x42u8; 32];
1590 let file_id = b"abcdef0123456789";
1591 let key = derive_key_r2_r4(&pwd_bytes, &o_value, -4, file_id, 3, 5, true);
1592
1593 let mut buf = Vec::new();
1595 buf.extend_from_slice(&PASSWORD_PADDING);
1596 buf.extend_from_slice(file_id);
1597 let hash = crypto::md5(&buf);
1598 let mut result = crypto::rc4_crypt(&key, &hash).unwrap();
1599 for i in 1..=19u8 {
1600 let modified: Vec<u8> = key.iter().map(|b| b ^ i).collect();
1601 result = crypto::rc4_crypt(&modified, &result).unwrap();
1602 }
1603 let mut u_value = result;
1604 u_value.resize(32, 0);
1605
1606 let handler = SecurityHandler {
1608 revision: 3,
1609 key_length_bytes: 5,
1610 encryption_key: key,
1611 permissions: Permissions::from_bits(-4),
1612 encrypt_metadata: true,
1613 stream_cf: CryptFilterMethod::V2,
1614 string_cf: CryptFilterMethod::V2,
1615 o_value: o_value.to_vec(),
1616 u_value,
1617 encoded_password: pwd_bytes.clone(),
1618 };
1619
1620 assert_eq!(handler.encoded_password(), pwd_bytes.as_slice());
1621 assert_eq!(handler.encoded_password(), b"test");
1623 }
1624
1625 #[test]
1630 fn test_security_handler_get_permissions_alias_r3() {
1631 let handler = SecurityHandler {
1632 revision: 3,
1633 key_length_bytes: 5,
1634 encryption_key: vec![0x01; 5],
1635 permissions: Permissions::from_bits(-3904),
1636 encrypt_metadata: true,
1637 stream_cf: CryptFilterMethod::V2,
1638 string_cf: CryptFilterMethod::V2,
1639 o_value: Vec::new(),
1640 u_value: Vec::new(),
1641 encoded_password: b"owner".to_vec(),
1642 };
1643 assert_eq!(handler.get_permissions().bits(), -3904);
1644 assert_eq!(handler.get_permissions(), handler.permissions());
1645 }
1646}