Skip to main content

oxidize_pdf/encryption/
standard_security.rs

1//! Standard Security Handler implementation according to ISO 32000-1/32000-2
2//!
3//! # Security Considerations
4//!
5//! This implementation includes several security hardening measures:
6//!
7//! - **Constant-time comparison**: Password validation uses `subtle::ConstantTimeEq`
8//!   to prevent timing side-channel attacks that could leak password information.
9//!
10//! - **Memory zeroization**: Sensitive data (`EncryptionKey`, `UserPassword`,
11//!   `OwnerPassword`) implements `Zeroize` to ensure secrets are cleared from
12//!   memory when dropped, preventing memory dump attacks.
13//!
14//! - **Cryptographically secure RNG**: Salt generation uses `rand::rng()` which
15//!   provides OS-level entropy suitable for cryptographic operations.
16
17#![allow(clippy::needless_range_loop)]
18
19use crate::encryption::{generate_iv, Aes, AesKey, Permissions, Rc4, Rc4Key};
20use crate::error::Result;
21use crate::objects::ObjectId;
22use rand::Rng;
23use sha2::{Digest, Sha256, Sha384, Sha512};
24use subtle::ConstantTimeEq;
25use zeroize::{Zeroize, ZeroizeOnDrop};
26
27/// Padding used in password processing
28const PADDING: [u8; 32] = [
29    0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
30    0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
31];
32
33/// User password
34///
35/// # Security
36/// Implements `Zeroize` and `ZeroizeOnDrop` to ensure password is cleared from memory.
37#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
38pub struct UserPassword(pub String);
39
40/// Owner password
41///
42/// # Security
43/// Implements `Zeroize` and `ZeroizeOnDrop` to ensure password is cleared from memory.
44#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
45pub struct OwnerPassword(pub String);
46
47/// Encryption key
48///
49/// # Security
50/// Implements `Zeroize` and `ZeroizeOnDrop` to ensure key bytes are cleared from memory.
51#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
52pub struct EncryptionKey {
53    /// Key bytes
54    pub key: Vec<u8>,
55}
56
57impl EncryptionKey {
58    /// Create from bytes
59    pub fn new(key: Vec<u8>) -> Self {
60        Self { key }
61    }
62
63    /// Get key length in bytes
64    pub fn len(&self) -> usize {
65        self.key.len()
66    }
67
68    /// Check if empty
69    pub fn is_empty(&self) -> bool {
70        self.key.is_empty()
71    }
72
73    /// Get key as bytes
74    pub fn as_bytes(&self) -> &[u8] {
75        &self.key
76    }
77}
78
79/// Security handler revision
80#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
81pub enum SecurityHandlerRevision {
82    /// Revision 2 (RC4 40-bit)
83    R2 = 2,
84    /// Revision 3 (RC4 128-bit)
85    R3 = 3,
86    /// Revision 4 (RC4 128-bit with metadata encryption control)
87    R4 = 4,
88    /// Revision 5 (AES-256 with improved password validation)
89    R5 = 5,
90    /// Revision 6 (AES-256 with Unicode password support)
91    R6 = 6,
92}
93
94/// Standard Security Handler
95pub struct StandardSecurityHandler {
96    /// Revision
97    pub revision: SecurityHandlerRevision,
98    /// Key length in bytes
99    pub key_length: usize,
100}
101
102impl StandardSecurityHandler {
103    /// Create handler for RC4 40-bit encryption
104    pub fn rc4_40bit() -> Self {
105        Self {
106            revision: SecurityHandlerRevision::R2,
107            key_length: 5,
108        }
109    }
110
111    /// Create handler for RC4 128-bit encryption
112    pub fn rc4_128bit() -> Self {
113        Self {
114            revision: SecurityHandlerRevision::R3,
115            key_length: 16,
116        }
117    }
118
119    /// Create handler for AES-256 encryption (Revision 5)
120    pub fn aes_256_r5() -> Self {
121        Self {
122            revision: SecurityHandlerRevision::R5,
123            key_length: 32,
124        }
125    }
126
127    /// Create handler for AES-256 encryption (Revision 6)
128    pub fn aes_256_r6() -> Self {
129        Self {
130            revision: SecurityHandlerRevision::R6,
131            key_length: 32,
132        }
133    }
134
135    /// Pad or truncate password to 32 bytes
136    fn pad_password(password: &str) -> [u8; 32] {
137        let mut padded = [0u8; 32];
138        let password_bytes = password.as_bytes();
139        let len = password_bytes.len().min(32);
140
141        // Copy password bytes
142        padded[..len].copy_from_slice(&password_bytes[..len]);
143
144        // Fill remaining with padding
145        if len < 32 {
146            padded[len..].copy_from_slice(&PADDING[..32 - len]);
147        }
148
149        padded
150    }
151
152    /// Compute owner password hash (O entry)
153    pub fn compute_owner_hash(
154        &self,
155        owner_password: &OwnerPassword,
156        user_password: &UserPassword,
157    ) -> Vec<u8> {
158        // Step 1: Pad passwords
159        let owner_pad = Self::pad_password(&owner_password.0);
160        let user_pad = Self::pad_password(&user_password.0);
161
162        // Step 2: Create MD5 hash of owner password
163        let mut hash = md5::compute(&owner_pad).to_vec();
164
165        // Step 3: For revision 3+, do 50 additional iterations
166        if self.revision >= SecurityHandlerRevision::R3 {
167            for _ in 0..50 {
168                hash = md5::compute(&hash).to_vec();
169            }
170        }
171
172        // Step 4: Create RC4 key from hash (truncated to key length)
173        let rc4_key = Rc4Key::from_slice(&hash[..self.key_length]);
174
175        // Step 5: Encrypt user password with RC4
176        let mut result = rc4_encrypt(&rc4_key, &user_pad);
177
178        // Step 6: For revision 3+, do 19 additional iterations
179        if self.revision >= SecurityHandlerRevision::R3 {
180            for i in 1..=19 {
181                let mut key_bytes = hash[..self.key_length].to_vec();
182                for j in 0..self.key_length {
183                    key_bytes[j] ^= i as u8;
184                }
185                let iter_key = Rc4Key::from_slice(&key_bytes);
186                result = rc4_encrypt(&iter_key, &result);
187            }
188        }
189
190        result
191    }
192
193    /// Compute user password hash (U entry)
194    pub fn compute_user_hash(
195        &self,
196        user_password: &UserPassword,
197        owner_hash: &[u8],
198        permissions: Permissions,
199        file_id: Option<&[u8]>,
200    ) -> Result<Vec<u8>> {
201        // Compute encryption key
202        let key = self.compute_encryption_key(user_password, owner_hash, permissions, file_id)?;
203
204        match self.revision {
205            SecurityHandlerRevision::R2 => {
206                // For R2, encrypt padding with key
207                let rc4_key = Rc4Key::from_slice(&key.key);
208                Ok(rc4_encrypt(&rc4_key, &PADDING))
209            }
210            SecurityHandlerRevision::R3 | SecurityHandlerRevision::R4 => {
211                // For R3/R4, compute MD5 hash including file ID
212                let mut data = Vec::new();
213                data.extend_from_slice(&PADDING);
214
215                if let Some(id) = file_id {
216                    data.extend_from_slice(id);
217                }
218
219                let hash = md5::compute(&data);
220
221                // Encrypt hash with RC4
222                let rc4_key = Rc4Key::from_slice(&key.key);
223                let mut result = rc4_encrypt(&rc4_key, hash.as_ref());
224
225                // Do 19 additional iterations
226                for i in 1..=19 {
227                    let mut key_bytes = key.key.clone();
228                    for j in 0..key_bytes.len() {
229                        key_bytes[j] ^= i as u8;
230                    }
231                    let iter_key = Rc4Key::from_slice(&key_bytes);
232                    result = rc4_encrypt(&iter_key, &result);
233                }
234
235                // Result is 32 bytes (16 bytes encrypted hash + 16 bytes arbitrary data)
236                result.resize(32, 0);
237                Ok(result)
238            }
239            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
240                // For R5/R6, use AES-based hash computation
241                let aes_key = self.compute_aes_encryption_key(
242                    user_password,
243                    owner_hash,
244                    permissions,
245                    file_id,
246                )?;
247                let hash = sha256(&aes_key.key);
248
249                // For AES revisions, return the hash directly (simplified)
250                Ok(hash)
251            }
252        }
253    }
254
255    /// Compute encryption key from user password
256    pub fn compute_encryption_key(
257        &self,
258        user_password: &UserPassword,
259        owner_hash: &[u8],
260        permissions: Permissions,
261        file_id: Option<&[u8]>,
262    ) -> Result<EncryptionKey> {
263        match self.revision {
264            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
265                // For AES revisions, use AES-specific key computation
266                self.compute_aes_encryption_key(user_password, owner_hash, permissions, file_id)
267            }
268            _ => {
269                // For RC4 revisions, use MD5-based key computation
270                // Step 1: Pad password
271                let padded = Self::pad_password(&user_password.0);
272
273                // Step 2: Create hash input
274                let mut data = Vec::new();
275                data.extend_from_slice(&padded);
276                data.extend_from_slice(owner_hash);
277                data.extend_from_slice(&permissions.bits().to_le_bytes());
278
279                if let Some(id) = file_id {
280                    data.extend_from_slice(id);
281                }
282
283                #[cfg(debug_assertions)]
284                {
285                    eprintln!("[DEBUG compute_key] padded[0..8]: {:02x?}", &padded[..8]);
286                    eprintln!("[DEBUG compute_key] owner_hash len: {}", owner_hash.len());
287                    eprintln!(
288                        "[DEBUG compute_key] P bytes: {:02x?}",
289                        permissions.bits().to_le_bytes()
290                    );
291                    eprintln!("[DEBUG compute_key] data len before MD5: {}", data.len());
292                    // Print full data for comparison
293                    let data_hex: String = data.iter().map(|b| format!("{:02x}", b)).collect();
294                    eprintln!("[DEBUG compute_key] full data hex: {}", data_hex);
295
296                    // Verify specific expected hash for debugging
297                    if data_hex == "7573657228bf4e5e4e758a4164004e56fffa01082e2e00b6d0683e802f0ca9fe94e8094419662a774442fb072e3d9f19e9d130ec09a4d0061e78fe920f7ab62ffcffffff9c5b2a0606f918182e6c5cc0cac374d6" {
298                        eprintln!("[DEBUG compute_key] DATA MATCHES EXPECTED - should produce eee5568378306e35...");
299                    }
300                }
301
302                // For R4 with metadata not encrypted, add extra bytes
303                if self.revision == SecurityHandlerRevision::R4 {
304                    // In a full implementation, check EncryptMetadata flag
305                    // For now, assume metadata is encrypted
306                }
307
308                // Step 3: Create MD5 hash
309                let mut hash = md5::compute(&data).to_vec();
310
311                #[cfg(debug_assertions)]
312                {
313                    eprintln!(
314                        "[DEBUG compute_key] initial hash[0..8]: {:02x?}",
315                        &hash[..8]
316                    );
317                    let hash_hex: String = hash.iter().map(|b| format!("{:02x}", b)).collect();
318                    eprintln!("[DEBUG compute_key] full hash: {}", hash_hex);
319                    eprintln!("[DEBUG compute_key] key_length: {}", self.key_length);
320                }
321
322                // Step 4: For revision 3+, do 50 additional iterations
323                if self.revision >= SecurityHandlerRevision::R3 {
324                    for _ in 0..50 {
325                        hash = md5::compute(&hash[..self.key_length]).to_vec();
326                    }
327                }
328
329                // Step 5: Truncate to key length
330                hash.truncate(self.key_length);
331
332                #[cfg(debug_assertions)]
333                {
334                    eprintln!("[DEBUG compute_key] final key: {:02x?}", &hash);
335                }
336
337                Ok(EncryptionKey::new(hash))
338            }
339        }
340    }
341
342    /// Encrypt a string
343    pub fn encrypt_string(&self, data: &[u8], key: &EncryptionKey, obj_id: &ObjectId) -> Vec<u8> {
344        match self.revision {
345            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
346                // For AES, use encrypt_aes and handle the Result
347                self.encrypt_aes(data, key, obj_id).unwrap_or_default()
348            }
349            _ => {
350                // For RC4
351                let obj_key = self.compute_object_key(key, obj_id);
352                let rc4_key = Rc4Key::from_slice(&obj_key);
353                rc4_encrypt(&rc4_key, data)
354            }
355        }
356    }
357
358    /// Decrypt a string
359    pub fn decrypt_string(&self, data: &[u8], key: &EncryptionKey, obj_id: &ObjectId) -> Vec<u8> {
360        match self.revision {
361            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
362                // For AES, use decrypt_aes and handle the Result
363                self.decrypt_aes(data, key, obj_id).unwrap_or_default()
364            }
365            _ => {
366                // RC4 is symmetric
367                self.encrypt_string(data, key, obj_id)
368            }
369        }
370    }
371
372    /// Encrypt a stream
373    pub fn encrypt_stream(&self, data: &[u8], key: &EncryptionKey, obj_id: &ObjectId) -> Vec<u8> {
374        // For both RC4 and AES, stream encryption is the same as string encryption
375        self.encrypt_string(data, key, obj_id)
376    }
377
378    /// Decrypt a stream
379    pub fn decrypt_stream(&self, data: &[u8], key: &EncryptionKey, obj_id: &ObjectId) -> Vec<u8> {
380        match self.revision {
381            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
382                // For AES, use decrypt_aes and handle the Result
383                self.decrypt_aes(data, key, obj_id).unwrap_or_default()
384            }
385            _ => {
386                // For RC4, decrypt is same as encrypt
387                self.decrypt_string(data, key, obj_id)
388            }
389        }
390    }
391
392    /// Encrypt data using AES (for Rev 5/6)
393    pub fn encrypt_aes(
394        &self,
395        data: &[u8],
396        key: &EncryptionKey,
397        obj_id: &ObjectId,
398    ) -> Result<Vec<u8>> {
399        if self.revision < SecurityHandlerRevision::R5 {
400            return Err(crate::error::PdfError::EncryptionError(
401                "AES encryption only supported for Rev 5+".to_string(),
402            ));
403        }
404
405        let obj_key = self.compute_aes_object_key(key, obj_id)?;
406        let aes_key = AesKey::new_256(obj_key)?;
407        let aes = Aes::new(aes_key);
408
409        let iv = generate_iv();
410        let mut result = Vec::new();
411        result.extend_from_slice(&iv);
412
413        let encrypted = aes.encrypt_cbc(data, &iv).map_err(|e| {
414            crate::error::PdfError::EncryptionError(format!("AES encryption failed: {e}"))
415        })?;
416
417        result.extend_from_slice(&encrypted);
418        Ok(result)
419    }
420
421    /// Decrypt data using AES (for Rev 5/6)
422    pub fn decrypt_aes(
423        &self,
424        data: &[u8],
425        key: &EncryptionKey,
426        obj_id: &ObjectId,
427    ) -> Result<Vec<u8>> {
428        if self.revision < SecurityHandlerRevision::R5 {
429            return Err(crate::error::PdfError::EncryptionError(
430                "AES decryption only supported for Rev 5+".to_string(),
431            ));
432        }
433
434        if data.len() < 16 {
435            return Err(crate::error::PdfError::EncryptionError(
436                "AES encrypted data must be at least 16 bytes (IV)".to_string(),
437            ));
438        }
439
440        let iv = &data[0..16];
441        let encrypted_data = &data[16..];
442
443        let obj_key = self.compute_aes_object_key(key, obj_id)?;
444        let aes_key = AesKey::new_256(obj_key)?;
445        let aes = Aes::new(aes_key);
446
447        aes.decrypt_cbc(encrypted_data, iv).map_err(|e| {
448            crate::error::PdfError::EncryptionError(format!("AES decryption failed: {e}"))
449        })
450    }
451
452    /// Compute AES object-specific encryption key for Rev 5/6
453    fn compute_aes_object_key(&self, key: &EncryptionKey, obj_id: &ObjectId) -> Result<Vec<u8>> {
454        if self.revision < SecurityHandlerRevision::R5 {
455            return Err(crate::error::PdfError::EncryptionError(
456                "AES object key computation only for Rev 5+".to_string(),
457            ));
458        }
459
460        // For Rev 5/6, use SHA-256 for key derivation
461        let mut data = Vec::new();
462        data.extend_from_slice(&key.key);
463        data.extend_from_slice(&obj_id.number().to_le_bytes());
464        data.extend_from_slice(&obj_id.generation().to_le_bytes());
465
466        // Add salt for AES
467        data.extend_from_slice(b"sAlT"); // Standard salt for AES
468
469        Ok(sha256(&data))
470    }
471
472    /// Compute encryption key for AES Rev 5/6
473    pub fn compute_aes_encryption_key(
474        &self,
475        user_password: &UserPassword,
476        owner_hash: &[u8],
477        permissions: Permissions,
478        file_id: Option<&[u8]>,
479    ) -> Result<EncryptionKey> {
480        if self.revision < SecurityHandlerRevision::R5 {
481            return Err(crate::error::PdfError::EncryptionError(
482                "AES key computation only for Rev 5+".to_string(),
483            ));
484        }
485
486        // For Rev 5/6, use more secure key derivation
487        let mut data = Vec::new();
488
489        // Use UTF-8 encoding for passwords in Rev 5/6
490        let password_bytes = user_password.0.as_bytes();
491        data.extend_from_slice(password_bytes);
492
493        // Add validation data
494        data.extend_from_slice(owner_hash);
495        data.extend_from_slice(&permissions.bits().to_le_bytes());
496
497        if let Some(id) = file_id {
498            data.extend_from_slice(id);
499        }
500
501        // Use SHA-256 for stronger hashing
502        let mut hash = sha256(&data);
503
504        // Perform additional iterations for Rev 5/6 (simplified)
505        for _ in 0..100 {
506            hash = sha256(&hash);
507        }
508
509        // AES-256 requires 32 bytes
510        hash.truncate(32);
511
512        Ok(EncryptionKey::new(hash))
513    }
514
515    /// Validate user password for AES Rev 5/6
516    pub fn validate_aes_user_password(
517        &self,
518        password: &UserPassword,
519        user_hash: &[u8],
520        permissions: Permissions,
521        file_id: Option<&[u8]>,
522    ) -> Result<bool> {
523        if self.revision < SecurityHandlerRevision::R5 {
524            return Err(crate::error::PdfError::EncryptionError(
525                "AES password validation only for Rev 5+".to_string(),
526            ));
527        }
528
529        let computed_key =
530            self.compute_aes_encryption_key(password, user_hash, permissions, file_id)?;
531
532        // Compare first 32 bytes of computed hash with stored hash
533        let computed_hash = sha256(&computed_key.key);
534
535        Ok(user_hash.len() >= 32 && computed_hash[..32] == user_hash[..32])
536    }
537
538    // ========================================================================
539    // R5/R6 Password Validation (ISO 32000-1 §7.6.4.3.4)
540    // ========================================================================
541
542    /// Compute R5 user password hash (U entry) - Algorithm 8
543    ///
544    /// Returns 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
545    ///
546    /// # Algorithm
547    /// 1. Generate random validation_salt (8 bytes)
548    /// 2. Generate random key_salt (8 bytes)
549    /// 3. Compute hash: SHA-256(password + validation_salt)
550    /// 4. Apply 64 iterations of SHA-256
551    /// 5. Return hash[0..32] + validation_salt + key_salt
552    pub fn compute_r5_user_hash(&self, user_password: &UserPassword) -> Result<Vec<u8>> {
553        if self.revision != SecurityHandlerRevision::R5 {
554            return Err(crate::error::PdfError::EncryptionError(
555                "R5 user hash only for Revision 5".to_string(),
556            ));
557        }
558
559        // Generate cryptographically secure random salts
560        let validation_salt = generate_salt(R5_SALT_LENGTH);
561        let key_salt = generate_salt(R5_SALT_LENGTH);
562
563        // Compute hash: SHA-256(password + validation_salt)
564        let mut data = Vec::new();
565        data.extend_from_slice(user_password.0.as_bytes());
566        data.extend_from_slice(&validation_salt);
567
568        let mut hash = sha256(&data);
569
570        // Apply R5 iterations of SHA-256 (PDF spec §7.6.4.3.4)
571        for _ in 0..R5_HASH_ITERATIONS {
572            hash = sha256(&hash);
573        }
574
575        // Construct U entry: hash[0..32] + validation_salt + key_salt
576        let mut u_entry = Vec::with_capacity(48);
577        u_entry.extend_from_slice(&hash[..32]);
578        u_entry.extend_from_slice(&validation_salt);
579        u_entry.extend_from_slice(&key_salt);
580
581        debug_assert_eq!(u_entry.len(), 48);
582        Ok(u_entry)
583    }
584
585    /// Validate R5 user password - Algorithm 11
586    ///
587    /// Returns Ok(true) if password is correct, Ok(false) if incorrect.
588    ///
589    /// # Algorithm
590    /// 1. Extract validation_salt from U[32..40]
591    /// 2. Compute hash: SHA-256(password + validation_salt)
592    /// 3. Apply 64 iterations of SHA-256
593    /// 4. Compare result with U[0..32] using constant-time comparison
594    ///
595    /// # Security
596    /// Uses constant-time comparison (`subtle::ConstantTimeEq`) to prevent
597    /// timing side-channel attacks that could leak password information.
598    pub fn validate_r5_user_password(
599        &self,
600        password: &UserPassword,
601        u_entry: &[u8],
602    ) -> Result<bool> {
603        if u_entry.len() != U_ENTRY_LENGTH {
604            return Err(crate::error::PdfError::EncryptionError(format!(
605                "R5 U entry must be {} bytes, got {}",
606                U_ENTRY_LENGTH,
607                u_entry.len()
608            )));
609        }
610
611        // Extract validation_salt from U
612        let validation_salt = &u_entry[U_VALIDATION_SALT_START..U_VALIDATION_SALT_END];
613
614        // Compute hash: SHA-256(password + validation_salt)
615        let mut data = Vec::new();
616        data.extend_from_slice(password.0.as_bytes());
617        data.extend_from_slice(validation_salt);
618
619        let mut hash = sha256(&data);
620
621        // Apply same R5 iterations as compute
622        for _ in 0..R5_HASH_ITERATIONS {
623            hash = sha256(&hash);
624        }
625
626        // SECURITY: Constant-time comparison prevents timing attacks
627        let stored_hash = &u_entry[..U_HASH_LENGTH];
628        let computed_hash = &hash[..U_HASH_LENGTH];
629        Ok(bool::from(computed_hash.ct_eq(stored_hash)))
630    }
631
632    /// Compute R5 UE entry (encrypted encryption key)
633    ///
634    /// The UE entry stores the encryption key encrypted with a key derived
635    /// from the user password.
636    ///
637    /// # Algorithm
638    /// 1. Extract key_salt from U[40..48]
639    /// 2. Compute intermediate key: SHA-256(password + key_salt)
640    /// 3. Encrypt encryption_key with intermediate_key using AES-256-CBC (zero IV)
641    pub fn compute_r5_ue_entry(
642        &self,
643        user_password: &UserPassword,
644        u_entry: &[u8],
645        encryption_key: &EncryptionKey,
646    ) -> Result<Vec<u8>> {
647        if u_entry.len() != U_ENTRY_LENGTH {
648            return Err(crate::error::PdfError::EncryptionError(format!(
649                "U entry must be {} bytes",
650                U_ENTRY_LENGTH
651            )));
652        }
653        if encryption_key.len() != UE_ENTRY_LENGTH {
654            return Err(crate::error::PdfError::EncryptionError(format!(
655                "Encryption key must be {} bytes for R5",
656                UE_ENTRY_LENGTH
657            )));
658        }
659
660        // Extract key_salt from U
661        let key_salt = &u_entry[U_KEY_SALT_START..U_KEY_SALT_END];
662
663        // Compute intermediate key: SHA-256(password + key_salt)
664        let mut data = Vec::new();
665        data.extend_from_slice(user_password.0.as_bytes());
666        data.extend_from_slice(key_salt);
667
668        let intermediate_key = sha256(&data);
669
670        // Encrypt encryption_key with intermediate_key using AES-256-CBC
671        // Zero IV as per PDF spec, no padding since 32 bytes is block-aligned
672        let aes_key = AesKey::new_256(intermediate_key)?;
673        let aes = Aes::new(aes_key);
674        let iv = [0u8; 16];
675
676        let encrypted = aes
677            .encrypt_cbc_raw(encryption_key.as_bytes(), &iv)
678            .map_err(|e| {
679                crate::error::PdfError::EncryptionError(format!("UE encryption failed: {}", e))
680            })?;
681
682        // UE is exactly 32 bytes (no padding, 32 bytes = 2 AES blocks)
683        Ok(encrypted)
684    }
685
686    /// Recover encryption key from R5 UE entry
687    ///
688    /// # Algorithm
689    /// 1. Extract key_salt from U[40..48]
690    /// 2. Compute intermediate key: SHA-256(password + key_salt)
691    /// 3. Decrypt UE with intermediate_key using AES-256-CBC (zero IV)
692    pub fn recover_r5_encryption_key(
693        &self,
694        user_password: &UserPassword,
695        u_entry: &[u8],
696        ue_entry: &[u8],
697    ) -> Result<EncryptionKey> {
698        if ue_entry.len() != UE_ENTRY_LENGTH {
699            return Err(crate::error::PdfError::EncryptionError(format!(
700                "UE entry must be {} bytes, got {}",
701                UE_ENTRY_LENGTH,
702                ue_entry.len()
703            )));
704        }
705        if u_entry.len() != U_ENTRY_LENGTH {
706            return Err(crate::error::PdfError::EncryptionError(format!(
707                "U entry must be {} bytes",
708                U_ENTRY_LENGTH
709            )));
710        }
711
712        // Extract key_salt from U
713        let key_salt = &u_entry[U_KEY_SALT_START..U_KEY_SALT_END];
714
715        // Compute intermediate key: SHA-256(password + key_salt)
716        let mut data = Vec::new();
717        data.extend_from_slice(user_password.0.as_bytes());
718        data.extend_from_slice(key_salt);
719
720        let intermediate_key = sha256(&data);
721
722        // Decrypt UE to get encryption key
723        // UE is 32 bytes = 2 AES blocks, encrypted with CBC and zero IV
724        let aes_key = AesKey::new_256(intermediate_key)?;
725        let aes = Aes::new(aes_key);
726        let iv = [0u8; 16];
727
728        let decrypted = aes.decrypt_cbc_raw(ue_entry, &iv).map_err(|e| {
729            crate::error::PdfError::EncryptionError(format!("UE decryption failed: {}", e))
730        })?;
731
732        Ok(EncryptionKey::new(decrypted))
733    }
734
735    // ========================================================================
736    // R6 Password Validation (ISO 32000-2 §7.6.4.4)
737    // ========================================================================
738
739    /// Compute R6 user password hash (U entry) using SHA-512
740    ///
741    /// R6 uses SHA-512 (first 32 bytes) instead of SHA-256 for stronger security.
742    /// Returns 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
743    ///
744    /// # Algorithm (ISO 32000-2)
745    /// 1. Generate random validation_salt (8 bytes)
746    /// 2. Generate random key_salt (8 bytes)
747    /// 3. Compute hash using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
748    /// 4. Return hash[0..32] + validation_salt + key_salt
749    pub fn compute_r6_user_hash(&self, user_password: &UserPassword) -> Result<Vec<u8>> {
750        if self.revision != SecurityHandlerRevision::R6 {
751            return Err(crate::error::PdfError::EncryptionError(
752                "R6 user hash only for Revision 6".to_string(),
753            ));
754        }
755
756        // Generate cryptographically secure random salts
757        let validation_salt = generate_salt(R6_SALT_LENGTH);
758        let key_salt = generate_salt(R6_SALT_LENGTH);
759
760        // Compute hash using Algorithm 2.B (ISO 32000-2:2020)
761        // For user password creation, u_entry is empty
762        let hash = compute_hash_r6_algorithm_2b(
763            user_password.0.as_bytes(),
764            &validation_salt,
765            &[], // No U entry for user password creation
766        )?;
767
768        // Construct U entry: hash[0..32] + validation_salt + key_salt
769        let mut u_entry = Vec::with_capacity(48);
770        u_entry.extend_from_slice(&hash[..32]);
771        u_entry.extend_from_slice(&validation_salt);
772        u_entry.extend_from_slice(&key_salt);
773
774        debug_assert_eq!(u_entry.len(), 48);
775        Ok(u_entry)
776    }
777
778    /// Validate R6 user password using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
779    ///
780    /// Returns Ok(true) if password is correct, Ok(false) if incorrect.
781    ///
782    /// # Algorithm
783    /// 1. Extract validation_salt from U[32..40]
784    /// 2. Compute hash using Algorithm 2.B with the validation_salt
785    /// 3. Compare result with U[0..32] using constant-time comparison
786    ///
787    /// # Security
788    /// Uses constant-time comparison (`subtle::ConstantTimeEq`) to prevent
789    /// timing side-channel attacks that could leak password information.
790    pub fn validate_r6_user_password(
791        &self,
792        password: &UserPassword,
793        u_entry: &[u8],
794    ) -> Result<bool> {
795        if u_entry.len() != U_ENTRY_LENGTH {
796            return Err(crate::error::PdfError::EncryptionError(format!(
797                "R6 U entry must be {} bytes, got {}",
798                U_ENTRY_LENGTH,
799                u_entry.len()
800            )));
801        }
802
803        // Extract validation_salt from U[32..40]
804        let validation_salt = &u_entry[U_VALIDATION_SALT_START..U_VALIDATION_SALT_END];
805
806        // Compute hash using Algorithm 2.B (ISO 32000-2:2020)
807        // For user password validation, u_entry is empty per spec
808        let hash = compute_hash_r6_algorithm_2b(password.0.as_bytes(), validation_salt, &[])?;
809
810        // SECURITY: Constant-time comparison prevents timing attacks
811        let stored_hash = &u_entry[..U_HASH_LENGTH];
812        let computed_hash = &hash[..U_HASH_LENGTH];
813        Ok(bool::from(computed_hash.ct_eq(stored_hash)))
814    }
815
816    /// Compute R6 UE entry (encrypted encryption key) using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
817    ///
818    /// # Algorithm
819    /// 1. Extract key_salt from U[40..48]
820    /// 2. Compute intermediate key using Algorithm 2.B(password, key_salt, u_entry)
821    /// 3. Encrypt encryption_key using AES-256-CBC with intermediate_key and IV = 0
822    pub fn compute_r6_ue_entry(
823        &self,
824        user_password: &UserPassword,
825        u_entry: &[u8],
826        encryption_key: &EncryptionKey,
827    ) -> Result<Vec<u8>> {
828        if u_entry.len() != U_ENTRY_LENGTH {
829            return Err(crate::error::PdfError::EncryptionError(format!(
830                "U entry must be {} bytes",
831                U_ENTRY_LENGTH
832            )));
833        }
834        if encryption_key.len() != UE_ENTRY_LENGTH {
835            return Err(crate::error::PdfError::EncryptionError(format!(
836                "Encryption key must be {} bytes for R6",
837                UE_ENTRY_LENGTH
838            )));
839        }
840
841        // Extract key_salt from U[40..48]
842        let key_salt = &u_entry[U_KEY_SALT_START..U_KEY_SALT_END];
843
844        // Compute intermediate key using Algorithm 2.B (ISO 32000-2:2020)
845        // For key derivation, we pass the full U entry as the third parameter
846        let hash = compute_hash_r6_algorithm_2b(user_password.0.as_bytes(), key_salt, u_entry)?;
847        let intermediate_key = hash[..U_HASH_LENGTH].to_vec();
848
849        // Encrypt encryption_key with intermediate_key using AES-256-CBC, IV = 0
850        let aes_key = AesKey::new_256(intermediate_key)?;
851        let aes = Aes::new(aes_key);
852        let iv = [0u8; 16];
853
854        let encrypted = aes
855            .encrypt_cbc_raw(encryption_key.as_bytes(), &iv)
856            .map_err(|e| {
857                crate::error::PdfError::EncryptionError(format!("UE encryption failed: {}", e))
858            })?;
859
860        Ok(encrypted)
861    }
862
863    /// Recover encryption key from R6 UE entry using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
864    ///
865    /// # Algorithm
866    /// 1. Extract key_salt from U[40..48]
867    /// 2. Compute intermediate key using Algorithm 2.B(password, key_salt, u_entry)
868    /// 3. Decrypt UE using AES-256-CBC with intermediate_key and IV = 0
869    pub fn recover_r6_encryption_key(
870        &self,
871        user_password: &UserPassword,
872        u_entry: &[u8],
873        ue_entry: &[u8],
874    ) -> Result<EncryptionKey> {
875        if ue_entry.len() != UE_ENTRY_LENGTH {
876            return Err(crate::error::PdfError::EncryptionError(format!(
877                "UE entry must be {} bytes, got {}",
878                UE_ENTRY_LENGTH,
879                ue_entry.len()
880            )));
881        }
882        if u_entry.len() != U_ENTRY_LENGTH {
883            return Err(crate::error::PdfError::EncryptionError(format!(
884                "U entry must be {} bytes",
885                U_ENTRY_LENGTH
886            )));
887        }
888
889        // Extract key_salt from U[40..48]
890        let key_salt = &u_entry[U_KEY_SALT_START..U_KEY_SALT_END];
891
892        // Compute intermediate key using Algorithm 2.B (ISO 32000-2:2020)
893        // For key derivation, we pass the full U entry as the third parameter
894        let hash = compute_hash_r6_algorithm_2b(user_password.0.as_bytes(), key_salt, u_entry)?;
895        let intermediate_key = hash[..U_HASH_LENGTH].to_vec();
896
897        // Decrypt UE to get encryption key using AES-256-CBC with IV = 0
898        let aes_key = AesKey::new_256(intermediate_key)?;
899        let aes = Aes::new(aes_key);
900        let iv = [0u8; 16];
901
902        let decrypted = aes.decrypt_cbc_raw(ue_entry, &iv).map_err(|e| {
903            crate::error::PdfError::EncryptionError(format!("UE decryption failed: {}", e))
904        })?;
905
906        Ok(EncryptionKey::new(decrypted))
907    }
908
909    // ========================================================================
910    // R6 Perms Entry (ISO 32000-2 Table 25)
911    // ========================================================================
912
913    /// Compute R6 Perms entry (encrypted permissions)
914    ///
915    /// The Perms entry is a 16-byte value that encrypts permissions using AES-256-ECB.
916    /// This allows verification that permissions haven't been tampered with.
917    ///
918    /// # Plaintext Structure (16 bytes)
919    /// - Bytes 0-3: Permissions (P value, little-endian)
920    /// - Bytes 4-7: 0xFFFFFFFF (fixed marker)
921    /// - Bytes 8-10: "adb" (literal verification string)
922    /// - Byte 11: 'T' or 'F' (EncryptMetadata flag)
923    /// - Bytes 12-15: 0x00 (padding)
924    pub fn compute_r6_perms_entry(
925        &self,
926        permissions: Permissions,
927        encryption_key: &EncryptionKey,
928        encrypt_metadata: bool,
929    ) -> Result<Vec<u8>> {
930        if self.revision != SecurityHandlerRevision::R6 {
931            return Err(crate::error::PdfError::EncryptionError(
932                "Perms entry only for Revision 6".to_string(),
933            ));
934        }
935        if encryption_key.len() != UE_ENTRY_LENGTH {
936            return Err(crate::error::PdfError::EncryptionError(format!(
937                "Encryption key must be {} bytes for R6 Perms",
938                UE_ENTRY_LENGTH
939            )));
940        }
941
942        // Construct plaintext: P + 0xFFFFFFFF + "adb" + T/F + padding
943        let mut plaintext = vec![0u8; PERMS_ENTRY_LENGTH];
944
945        // Permissions (4 bytes, little-endian)
946        let p_bytes = (permissions.bits() as u32).to_le_bytes();
947        plaintext[PERMS_P_START..PERMS_P_END].copy_from_slice(&p_bytes);
948
949        // Fixed marker bytes (0xFFFFFFFF)
950        plaintext[PERMS_MARKER_START..PERMS_MARKER_END].copy_from_slice(&PERMS_MARKER);
951
952        // Literal "adb" verification string
953        plaintext[PERMS_LITERAL_START..PERMS_LITERAL_END].copy_from_slice(PERMS_LITERAL);
954
955        // EncryptMetadata flag
956        plaintext[PERMS_ENCRYPT_META_BYTE] = if encrypt_metadata { b'T' } else { b'F' };
957
958        // Bytes 12-15 remain 0x00 (padding)
959
960        // Encrypt with AES-256-ECB
961        let aes_key = AesKey::new_256(encryption_key.key.clone())?;
962        let aes = Aes::new(aes_key);
963
964        let encrypted = aes.encrypt_ecb(&plaintext).map_err(|e| {
965            crate::error::PdfError::EncryptionError(format!("Perms encryption failed: {}", e))
966        })?;
967
968        Ok(encrypted)
969    }
970
971    /// Validate R6 Perms entry by decrypting and checking structure
972    ///
973    /// Returns Ok(true) if the Perms entry is valid and matches expected permissions.
974    /// Returns Ok(false) if decryption succeeds but structure/permissions don't match.
975    /// Returns Err if decryption fails.
976    ///
977    /// # Security
978    /// Uses constant-time comparison (`subtle::ConstantTimeEq`) for permissions
979    /// comparison to prevent timing side-channel attacks.
980    pub fn validate_r6_perms(
981        &self,
982        perms_entry: &[u8],
983        encryption_key: &EncryptionKey,
984        expected_permissions: Permissions,
985    ) -> Result<bool> {
986        if perms_entry.len() != PERMS_ENTRY_LENGTH {
987            return Err(crate::error::PdfError::EncryptionError(format!(
988                "Perms entry must be {} bytes, got {}",
989                PERMS_ENTRY_LENGTH,
990                perms_entry.len()
991            )));
992        }
993        if encryption_key.len() != UE_ENTRY_LENGTH {
994            return Err(crate::error::PdfError::EncryptionError(format!(
995                "Encryption key must be {} bytes",
996                UE_ENTRY_LENGTH
997            )));
998        }
999
1000        // Decrypt with AES-256-ECB
1001        let aes_key = AesKey::new_256(encryption_key.key.clone())?;
1002        let aes = Aes::new(aes_key);
1003
1004        let decrypted = aes.decrypt_ecb(perms_entry).map_err(|e| {
1005            crate::error::PdfError::EncryptionError(format!("Perms decryption failed: {}", e))
1006        })?;
1007
1008        // Verify fixed marker
1009        if decrypted[PERMS_MARKER_START..PERMS_MARKER_END] != PERMS_MARKER {
1010            return Ok(false);
1011        }
1012
1013        // Verify literal "adb"
1014        if &decrypted[PERMS_LITERAL_START..PERMS_LITERAL_END] != PERMS_LITERAL {
1015            return Ok(false);
1016        }
1017
1018        // SECURITY: Constant-time comparison for permissions
1019        let expected_bytes = (expected_permissions.bits() as u32).to_le_bytes();
1020        let actual_bytes = &decrypted[PERMS_P_START..PERMS_P_END];
1021        Ok(bool::from(expected_bytes.ct_eq(actual_bytes)))
1022    }
1023
1024    /// Extract EncryptMetadata flag from decrypted Perms entry
1025    ///
1026    /// Returns Ok(Some(true)) if EncryptMetadata='T', Ok(Some(false)) if 'F',
1027    /// Ok(None) if Perms structure is invalid.
1028    pub fn extract_r6_encrypt_metadata(
1029        &self,
1030        perms_entry: &[u8],
1031        encryption_key: &EncryptionKey,
1032    ) -> Result<Option<bool>> {
1033        if perms_entry.len() != PERMS_ENTRY_LENGTH || encryption_key.len() != UE_ENTRY_LENGTH {
1034            return Ok(None);
1035        }
1036
1037        let aes_key = AesKey::new_256(encryption_key.key.clone())?;
1038        let aes = Aes::new(aes_key);
1039
1040        let decrypted = match aes.decrypt_ecb(perms_entry) {
1041            Ok(d) => d,
1042            Err(_) => return Ok(None),
1043        };
1044
1045        // Verify structure before extracting flag
1046        if decrypted[PERMS_MARKER_START..PERMS_MARKER_END] != PERMS_MARKER
1047            || &decrypted[PERMS_LITERAL_START..PERMS_LITERAL_END] != PERMS_LITERAL
1048        {
1049            return Ok(None);
1050        }
1051
1052        // Extract EncryptMetadata flag
1053        match decrypted[PERMS_ENCRYPT_META_BYTE] {
1054            b'T' => Ok(Some(true)),
1055            b'F' => Ok(Some(false)),
1056            _ => Ok(None), // Invalid flag value
1057        }
1058    }
1059
1060    // ========================================================================
1061    // R5/R6 Owner Password Support (ISO 32000-1 §7.6.4.3.3)
1062    // ========================================================================
1063
1064    /// Compute R5 owner password hash (O entry)
1065    ///
1066    /// Algorithm 9 (ISO 32000-1): Creates 48-byte O entry
1067    /// - Bytes 0-31: SHA-256(owner_password || validation_salt)
1068    /// - Bytes 32-39: validation_salt (8 random bytes)
1069    /// - Bytes 40-47: key_salt (8 random bytes)
1070    pub fn compute_r5_owner_hash(
1071        &self,
1072        owner_password: &OwnerPassword,
1073        _user_password: &UserPassword,
1074    ) -> Result<Vec<u8>> {
1075        if self.revision != SecurityHandlerRevision::R5 {
1076            return Err(crate::error::PdfError::EncryptionError(
1077                "R5 owner hash only for Revision 5".to_string(),
1078            ));
1079        }
1080
1081        // Generate random salts
1082        let validation_salt = generate_salt(R5_SALT_LENGTH);
1083        let key_salt = generate_salt(R5_SALT_LENGTH);
1084
1085        // Compute hash: SHA-256(owner_password || validation_salt)
1086        let mut data = Vec::new();
1087        data.extend_from_slice(owner_password.0.as_bytes());
1088        data.extend_from_slice(&validation_salt);
1089
1090        let hash = sha256(&data);
1091
1092        // Construct O entry: hash[0..32] + validation_salt + key_salt
1093        let mut o_entry = Vec::with_capacity(U_ENTRY_LENGTH);
1094        o_entry.extend_from_slice(&hash[..U_HASH_LENGTH]);
1095        o_entry.extend_from_slice(&validation_salt);
1096        o_entry.extend_from_slice(&key_salt);
1097
1098        debug_assert_eq!(o_entry.len(), U_ENTRY_LENGTH);
1099        Ok(o_entry)
1100    }
1101
1102    /// Validate R5 owner password
1103    ///
1104    /// Algorithm 12 (ISO 32000-1): Validates owner password against O entry
1105    pub fn validate_r5_owner_password(
1106        &self,
1107        owner_password: &OwnerPassword,
1108        o_entry: &[u8],
1109    ) -> Result<bool> {
1110        if o_entry.len() != U_ENTRY_LENGTH {
1111            return Err(crate::error::PdfError::EncryptionError(format!(
1112                "R5 O entry must be {} bytes, got {}",
1113                U_ENTRY_LENGTH,
1114                o_entry.len()
1115            )));
1116        }
1117
1118        // Extract validation_salt from O (bytes 32-39)
1119        let validation_salt = &o_entry[U_VALIDATION_SALT_START..U_VALIDATION_SALT_END];
1120
1121        // Compute hash: SHA-256(owner_password || validation_salt)
1122        let mut data = Vec::new();
1123        data.extend_from_slice(owner_password.0.as_bytes());
1124        data.extend_from_slice(validation_salt);
1125
1126        let hash = sha256(&data);
1127
1128        // SECURITY: Constant-time comparison prevents timing attacks
1129        let stored_hash = &o_entry[..U_HASH_LENGTH];
1130        Ok(bool::from(hash[..U_HASH_LENGTH].ct_eq(stored_hash)))
1131    }
1132
1133    /// Compute R5 OE entry (encrypted encryption key with owner password)
1134    ///
1135    /// OE = AES-256-CBC(encryption_key, key=intermediate_key, iv=zeros)
1136    /// where intermediate_key = SHA-256(owner_password || key_salt)
1137    pub fn compute_r5_oe_entry(
1138        &self,
1139        owner_password: &OwnerPassword,
1140        o_entry: &[u8],
1141        encryption_key: &[u8],
1142    ) -> Result<Vec<u8>> {
1143        if o_entry.len() != U_ENTRY_LENGTH {
1144            return Err(crate::error::PdfError::EncryptionError(format!(
1145                "O entry must be {} bytes",
1146                U_ENTRY_LENGTH
1147            )));
1148        }
1149        if encryption_key.len() != UE_ENTRY_LENGTH {
1150            return Err(crate::error::PdfError::EncryptionError(format!(
1151                "Encryption key must be {} bytes",
1152                UE_ENTRY_LENGTH
1153            )));
1154        }
1155
1156        // Extract key_salt from O (bytes 40-47)
1157        let key_salt = &o_entry[U_KEY_SALT_START..U_KEY_SALT_END];
1158
1159        // Compute intermediate key: SHA-256(owner_password || key_salt)
1160        let mut data = Vec::new();
1161        data.extend_from_slice(owner_password.0.as_bytes());
1162        data.extend_from_slice(key_salt);
1163
1164        let intermediate_key = sha256(&data);
1165
1166        // Encrypt encryption_key with intermediate_key using AES-256-CBC
1167        let aes = Aes::new(AesKey::new_256(intermediate_key)?);
1168        let iv = [0u8; 16];
1169
1170        let encrypted = aes.encrypt_cbc_raw(encryption_key, &iv).map_err(|e| {
1171            crate::error::PdfError::EncryptionError(format!("OE encryption failed: {}", e))
1172        })?;
1173
1174        // OE is first 32 bytes of encrypted output
1175        Ok(encrypted[..UE_ENTRY_LENGTH].to_vec())
1176    }
1177
1178    /// Recover encryption key from R5 OE entry using owner password
1179    pub fn recover_r5_owner_encryption_key(
1180        &self,
1181        owner_password: &OwnerPassword,
1182        o_entry: &[u8],
1183        oe_entry: &[u8],
1184    ) -> Result<Vec<u8>> {
1185        if o_entry.len() != U_ENTRY_LENGTH {
1186            return Err(crate::error::PdfError::EncryptionError(format!(
1187                "O entry must be {} bytes",
1188                U_ENTRY_LENGTH
1189            )));
1190        }
1191        if oe_entry.len() != UE_ENTRY_LENGTH {
1192            return Err(crate::error::PdfError::EncryptionError(format!(
1193                "OE entry must be {} bytes",
1194                UE_ENTRY_LENGTH
1195            )));
1196        }
1197
1198        // Extract key_salt from O (bytes 40-47)
1199        let key_salt = &o_entry[U_KEY_SALT_START..U_KEY_SALT_END];
1200
1201        // Compute intermediate key
1202        let mut data = Vec::new();
1203        data.extend_from_slice(owner_password.0.as_bytes());
1204        data.extend_from_slice(key_salt);
1205
1206        let intermediate_key = sha256(&data);
1207
1208        // Decrypt OE to get encryption key
1209        let aes = Aes::new(AesKey::new_256(intermediate_key)?);
1210        let iv = [0u8; 16];
1211
1212        let decrypted = aes.decrypt_cbc_raw(oe_entry, &iv).map_err(|e| {
1213            crate::error::PdfError::EncryptionError(format!("OE decryption failed: {}", e))
1214        })?;
1215
1216        Ok(decrypted)
1217    }
1218
1219    /// Compute R6 owner password hash (O entry)
1220    ///
1221    /// R6 uses Algorithm 2.B (complex hash) for owner password too
1222    pub fn compute_r6_owner_hash(
1223        &self,
1224        owner_password: &OwnerPassword,
1225        u_entry: &[u8],
1226    ) -> Result<Vec<u8>> {
1227        if self.revision != SecurityHandlerRevision::R6 {
1228            return Err(crate::error::PdfError::EncryptionError(
1229                "R6 owner hash only for Revision 6".to_string(),
1230            ));
1231        }
1232        if u_entry.len() != U_ENTRY_LENGTH {
1233            return Err(crate::error::PdfError::EncryptionError(format!(
1234                "U entry must be {} bytes for R6 O computation",
1235                U_ENTRY_LENGTH
1236            )));
1237        }
1238
1239        // Generate random salts
1240        let validation_salt = generate_salt(R6_SALT_LENGTH);
1241        let key_salt = generate_salt(R6_SALT_LENGTH);
1242
1243        // For R6, use Algorithm 2.B: hash = Alg2B(owner_password || validation_salt || U[0..48])
1244        let mut input = Vec::new();
1245        input.extend_from_slice(owner_password.0.as_bytes());
1246        input.extend_from_slice(&validation_salt);
1247        input.extend_from_slice(u_entry);
1248
1249        let hash = compute_hash_r6_algorithm_2b(&input, owner_password.0.as_bytes(), u_entry)?;
1250
1251        // Construct O entry: hash[0..32] + validation_salt + key_salt
1252        let mut o_entry = Vec::with_capacity(U_ENTRY_LENGTH);
1253        o_entry.extend_from_slice(&hash[..U_HASH_LENGTH]);
1254        o_entry.extend_from_slice(&validation_salt);
1255        o_entry.extend_from_slice(&key_salt);
1256
1257        debug_assert_eq!(o_entry.len(), U_ENTRY_LENGTH);
1258        Ok(o_entry)
1259    }
1260
1261    /// Validate R6 owner password
1262    ///
1263    /// Uses Algorithm 2.B to validate owner password
1264    pub fn validate_r6_owner_password(
1265        &self,
1266        owner_password: &OwnerPassword,
1267        o_entry: &[u8],
1268        u_entry: &[u8],
1269    ) -> Result<bool> {
1270        if o_entry.len() != U_ENTRY_LENGTH {
1271            return Err(crate::error::PdfError::EncryptionError(format!(
1272                "R6 O entry must be {} bytes",
1273                U_ENTRY_LENGTH
1274            )));
1275        }
1276        if u_entry.len() != U_ENTRY_LENGTH {
1277            return Err(crate::error::PdfError::EncryptionError(format!(
1278                "R6 U entry must be {} bytes",
1279                U_ENTRY_LENGTH
1280            )));
1281        }
1282
1283        // Extract validation_salt from O (bytes 32-39)
1284        let validation_salt = &o_entry[U_VALIDATION_SALT_START..U_VALIDATION_SALT_END];
1285
1286        // Compute hash using Algorithm 2.B
1287        let mut input = Vec::new();
1288        input.extend_from_slice(owner_password.0.as_bytes());
1289        input.extend_from_slice(validation_salt);
1290        input.extend_from_slice(u_entry);
1291
1292        let hash = compute_hash_r6_algorithm_2b(&input, owner_password.0.as_bytes(), u_entry)?;
1293
1294        // SECURITY: Constant-time comparison prevents timing attacks
1295        let stored_hash = &o_entry[..U_HASH_LENGTH];
1296        Ok(bool::from(hash[..U_HASH_LENGTH].ct_eq(stored_hash)))
1297    }
1298
1299    /// Compute R6 OE entry (encrypted encryption key with owner password)
1300    ///
1301    /// Uses Algorithm 2.B to derive intermediate key
1302    pub fn compute_r6_oe_entry(
1303        &self,
1304        owner_password: &OwnerPassword,
1305        o_entry: &[u8],
1306        u_entry: &[u8],
1307        encryption_key: &[u8],
1308    ) -> Result<Vec<u8>> {
1309        if o_entry.len() != U_ENTRY_LENGTH {
1310            return Err(crate::error::PdfError::EncryptionError(format!(
1311                "O entry must be {} bytes",
1312                U_ENTRY_LENGTH
1313            )));
1314        }
1315        if u_entry.len() != U_ENTRY_LENGTH {
1316            return Err(crate::error::PdfError::EncryptionError(format!(
1317                "U entry must be {} bytes",
1318                U_ENTRY_LENGTH
1319            )));
1320        }
1321        if encryption_key.len() != UE_ENTRY_LENGTH {
1322            return Err(crate::error::PdfError::EncryptionError(format!(
1323                "Encryption key must be {} bytes",
1324                UE_ENTRY_LENGTH
1325            )));
1326        }
1327
1328        // Extract key_salt from O (bytes 40-47)
1329        let key_salt = &o_entry[U_KEY_SALT_START..U_KEY_SALT_END];
1330
1331        // Compute intermediate key using Algorithm 2.B
1332        let mut input = Vec::new();
1333        input.extend_from_slice(owner_password.0.as_bytes());
1334        input.extend_from_slice(key_salt);
1335        input.extend_from_slice(u_entry);
1336
1337        let intermediate_key =
1338            compute_hash_r6_algorithm_2b(&input, owner_password.0.as_bytes(), u_entry)?;
1339
1340        // Encrypt encryption_key with intermediate_key using AES-256-CBC
1341        let aes = Aes::new(AesKey::new_256(intermediate_key[..32].to_vec())?);
1342        let iv = [0u8; 16];
1343
1344        let encrypted = aes.encrypt_cbc_raw(encryption_key, &iv).map_err(|e| {
1345            crate::error::PdfError::EncryptionError(format!("OE encryption failed: {}", e))
1346        })?;
1347
1348        Ok(encrypted[..UE_ENTRY_LENGTH].to_vec())
1349    }
1350
1351    /// Recover encryption key from R6 OE entry using owner password
1352    pub fn recover_r6_owner_encryption_key(
1353        &self,
1354        owner_password: &OwnerPassword,
1355        o_entry: &[u8],
1356        u_entry: &[u8],
1357        oe_entry: &[u8],
1358    ) -> Result<Vec<u8>> {
1359        if o_entry.len() != U_ENTRY_LENGTH {
1360            return Err(crate::error::PdfError::EncryptionError(format!(
1361                "O entry must be {} bytes",
1362                U_ENTRY_LENGTH
1363            )));
1364        }
1365        if u_entry.len() != U_ENTRY_LENGTH {
1366            return Err(crate::error::PdfError::EncryptionError(format!(
1367                "U entry must be {} bytes",
1368                U_ENTRY_LENGTH
1369            )));
1370        }
1371        if oe_entry.len() != UE_ENTRY_LENGTH {
1372            return Err(crate::error::PdfError::EncryptionError(format!(
1373                "OE entry must be {} bytes",
1374                UE_ENTRY_LENGTH
1375            )));
1376        }
1377
1378        // Extract key_salt from O (bytes 40-47)
1379        let key_salt = &o_entry[U_KEY_SALT_START..U_KEY_SALT_END];
1380
1381        // Compute intermediate key using Algorithm 2.B
1382        let mut input = Vec::new();
1383        input.extend_from_slice(owner_password.0.as_bytes());
1384        input.extend_from_slice(key_salt);
1385        input.extend_from_slice(u_entry);
1386
1387        let intermediate_key =
1388            compute_hash_r6_algorithm_2b(&input, owner_password.0.as_bytes(), u_entry)?;
1389
1390        // Decrypt OE to get encryption key
1391        let aes = Aes::new(AesKey::new_256(intermediate_key[..32].to_vec())?);
1392        let iv = [0u8; 16];
1393
1394        let decrypted = aes.decrypt_cbc_raw(oe_entry, &iv).map_err(|e| {
1395            crate::error::PdfError::EncryptionError(format!("OE decryption failed: {}", e))
1396        })?;
1397
1398        Ok(decrypted)
1399    }
1400
1401    /// Compute object-specific encryption key (Algorithm 1, ISO 32000-1 §7.6.2)
1402    pub fn compute_object_key(&self, key: &EncryptionKey, obj_id: &ObjectId) -> Vec<u8> {
1403        let mut data = Vec::new();
1404        data.extend_from_slice(&key.key);
1405        data.extend_from_slice(&obj_id.number().to_le_bytes()[..3]); // Low 3 bytes
1406        data.extend_from_slice(&obj_id.generation().to_le_bytes()[..2]); // Low 2 bytes
1407
1408        let hash = md5::compute(&data);
1409        let key_len = (key.len() + 5).min(16);
1410        hash[..key_len].to_vec()
1411    }
1412
1413    /// Validate user password (Algorithm 6, ISO 32000-1 §7.6.3.4)
1414    ///
1415    /// Returns Ok(true) if password is correct, Ok(false) if incorrect.
1416    /// Returns Err only on internal errors.
1417    pub fn validate_user_password(
1418        &self,
1419        password: &UserPassword,
1420        user_hash: &[u8],
1421        owner_hash: &[u8],
1422        permissions: Permissions,
1423        file_id: Option<&[u8]>,
1424    ) -> Result<bool> {
1425        // Compute encryption key from provided password
1426        let key = self.compute_encryption_key(password, owner_hash, permissions, file_id)?;
1427
1428        match self.revision {
1429            SecurityHandlerRevision::R2 => {
1430                // For R2: Encrypt padding with key and compare with U
1431                let rc4_key = Rc4Key::from_slice(&key.key);
1432                let encrypted_padding = rc4_encrypt(&rc4_key, &PADDING);
1433
1434                // Compare with stored user hash
1435                Ok(user_hash.len() >= 32 && encrypted_padding[..] == user_hash[..32])
1436            }
1437            SecurityHandlerRevision::R3 | SecurityHandlerRevision::R4 => {
1438                // For R3/R4: Compute MD5 hash including file ID
1439                let mut data = Vec::new();
1440                data.extend_from_slice(&PADDING);
1441
1442                if let Some(id) = file_id {
1443                    data.extend_from_slice(id);
1444                }
1445
1446                let hash = md5::compute(&data);
1447
1448                // Encrypt hash with RC4
1449                let rc4_key = Rc4Key::from_slice(&key.key);
1450                let mut encrypted = rc4_encrypt(&rc4_key, hash.as_ref());
1451
1452                // Do 19 additional iterations with modified keys
1453                for i in 1..=19 {
1454                    let mut key_bytes = key.key.clone();
1455                    for byte in &mut key_bytes {
1456                        *byte ^= i as u8;
1457                    }
1458                    let iter_key = Rc4Key::from_slice(&key_bytes);
1459                    encrypted = rc4_encrypt(&iter_key, &encrypted);
1460                }
1461
1462                // Compare first 16 bytes of result with first 16 bytes of U
1463                Ok(user_hash.len() >= 16 && encrypted[..16] == user_hash[..16])
1464            }
1465            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
1466                // For R5/R6, use AES-based validation
1467                self.validate_aes_user_password(password, user_hash, permissions, file_id)
1468            }
1469        }
1470    }
1471
1472    /// Validate owner password (Algorithm 7, ISO 32000-1 §7.6.3.4)
1473    ///
1474    /// Returns Ok(true) if password is correct, Ok(false) if incorrect.
1475    /// Returns Err only on internal errors.
1476    ///
1477    /// Note: For owner password validation, we first decrypt the user password
1478    /// from the owner hash, then validate that user password.
1479    ///
1480    /// # Parameters
1481    /// - `owner_password`: The owner password to validate
1482    /// - `owner_hash`: The O entry from the encryption dictionary
1483    /// - `_user_password`: Unused for R2-R4 (recovered from owner_hash), ignored for R5/R6
1484    /// - `_permissions`: Unused for R5/R6 (not part of validation)
1485    /// - `_file_id`: Unused for R5/R6 (not part of validation)
1486    /// - `u_entry`: Required for R6 (U entry needed for Algorithm 2.B), ignored for R2-R5
1487    pub fn validate_owner_password(
1488        &self,
1489        owner_password: &OwnerPassword,
1490        owner_hash: &[u8],
1491        _user_password: &UserPassword, // Will be recovered from owner_hash
1492        _permissions: Permissions,
1493        _file_id: Option<&[u8]>,
1494        u_entry: Option<&[u8]>,
1495    ) -> Result<bool> {
1496        match self.revision {
1497            SecurityHandlerRevision::R2
1498            | SecurityHandlerRevision::R3
1499            | SecurityHandlerRevision::R4 => {
1500                // Step 1: Pad owner password
1501                let owner_pad = Self::pad_password(&owner_password.0);
1502
1503                // Step 2: Create MD5 hash of owner password
1504                let mut hash = md5::compute(&owner_pad).to_vec();
1505
1506                // Step 3: For revision 3+, do 50 additional iterations
1507                if self.revision >= SecurityHandlerRevision::R3 {
1508                    for _ in 0..50 {
1509                        hash = md5::compute(&hash).to_vec();
1510                    }
1511                }
1512
1513                // Step 4: Create RC4 key from hash (truncated to key length)
1514                let rc4_key = Rc4Key::from_slice(&hash[..self.key_length]);
1515
1516                // Step 5: Decrypt owner hash to get user password
1517                let mut decrypted = owner_hash[..32].to_vec();
1518
1519                // For R3+, do 19 iterations in reverse
1520                if self.revision >= SecurityHandlerRevision::R3 {
1521                    for i in (0..20).rev() {
1522                        let mut key_bytes = hash[..self.key_length].to_vec();
1523                        for byte in &mut key_bytes {
1524                            *byte ^= i as u8;
1525                        }
1526                        let iter_key = Rc4Key::from_slice(&key_bytes);
1527                        decrypted = rc4_encrypt(&iter_key, &decrypted);
1528                    }
1529                } else {
1530                    // For R2, single decryption
1531                    decrypted = rc4_encrypt(&rc4_key, &decrypted);
1532                }
1533
1534                // Step 6: The decrypted data should be the padded user password
1535                // Try to validate by computing what the owner hash SHOULD be
1536                // with this owner password, and compare
1537
1538                // Extract potential user password (remove padding)
1539                let user_pwd_bytes = decrypted
1540                    .iter()
1541                    .take_while(|&&b| b != 0x28 || decrypted.starts_with(&PADDING))
1542                    .copied()
1543                    .collect::<Vec<u8>>();
1544
1545                let recovered_user =
1546                    UserPassword(String::from_utf8_lossy(&user_pwd_bytes).to_string());
1547
1548                // Compute what owner hash should be with this owner password
1549                let computed_owner = self.compute_owner_hash(owner_password, &recovered_user);
1550
1551                // Compare with stored owner hash
1552                Ok(computed_owner[..32] == owner_hash[..32])
1553            }
1554            SecurityHandlerRevision::R5 => {
1555                // R5 uses simple SHA-256 validation (Algorithm 12)
1556                // owner_hash is the O entry (48 bytes)
1557                self.validate_r5_owner_password(owner_password, owner_hash)
1558            }
1559            SecurityHandlerRevision::R6 => {
1560                // R6 uses Algorithm 2.B which requires U entry
1561                let u = u_entry.ok_or_else(|| {
1562                    crate::error::PdfError::EncryptionError(
1563                        "R6 owner password validation requires U entry".to_string(),
1564                    )
1565                })?;
1566                self.validate_r6_owner_password(owner_password, owner_hash, u)
1567            }
1568        }
1569    }
1570}
1571
1572/// Helper function for RC4 encryption
1573fn rc4_encrypt(key: &Rc4Key, data: &[u8]) -> Vec<u8> {
1574    let mut cipher = Rc4::new(key);
1575    cipher.process(data)
1576}
1577
1578// Use the md5 crate for actual MD5 hashing (required for PDF encryption)
1579
1580/// SHA-256 implementation using RustCrypto (production-grade)
1581///
1582/// Returns a 32-byte hash of the input data according to FIPS 180-4.
1583/// Used for R5 password validation and key derivation.
1584fn sha256(data: &[u8]) -> Vec<u8> {
1585    Sha256::digest(data).to_vec()
1586}
1587
1588/// SHA-384 implementation using RustCrypto (production-grade)
1589///
1590/// Returns a 48-byte hash of the input data according to FIPS 180-4.
1591/// Used for R6 Algorithm 2.B hash rotation.
1592fn sha384(data: &[u8]) -> Vec<u8> {
1593    Sha384::digest(data).to_vec()
1594}
1595
1596/// SHA-512 implementation using RustCrypto (production-grade)
1597///
1598/// Returns a 64-byte hash of the input data according to FIPS 180-4.
1599/// Used for R6 password validation and key derivation.
1600fn sha512(data: &[u8]) -> Vec<u8> {
1601    Sha512::digest(data).to_vec()
1602}
1603
1604// ============================================================================
1605// Algorithm 2.B - R6 Key Derivation (ISO 32000-2:2020 §7.6.4.3.4)
1606// ============================================================================
1607
1608/// Minimum number of rounds for Algorithm 2.B
1609const ALGORITHM_2B_MIN_ROUNDS: usize = 64;
1610
1611/// Maximum rounds (DoS protection, not in spec but common implementation)
1612const ALGORITHM_2B_MAX_ROUNDS: usize = 2048;
1613
1614/// Maximum password length (ISO 32000-2 §7.6.3.3.2 recommends 127 bytes)
1615/// This prevents DoS via massive allocation: 1MB password × 64 repetitions = 64MB/round
1616const ALGORITHM_2B_MAX_PASSWORD_LEN: usize = 127;
1617
1618/// Number of bytes used for hash function selection (spec: first 16 bytes as BigInteger mod 3)
1619const HASH_SELECTOR_BYTES: usize = 16;
1620
1621/// Compute R6 password hash using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
1622///
1623/// This is the correct R6 key derivation algorithm used by qpdf, Adobe Acrobat,
1624/// and other compliant PDF processors. It uses AES-128-CBC encryption within
1625/// the iteration loop and dynamically selects SHA-256/384/512 based on output.
1626///
1627/// # Algorithm Overview
1628/// 1. Initial hash: K = SHA-256(password + salt + U\[0..48\])
1629/// 2. Loop (minimum 64 rounds):
1630///    a. Construct k1 = (password + K + U\[0..48\]), repeat 64 times
1631///    b. E = AES-128-CBC-encrypt(k1, key=K\[0..16\], iv=K\[16..32\])
1632///    c. Select hash: SHA-256/384/512 based on sum(E\[0..16\]) mod 3
1633///    d. K = hash(E)
1634///    e. Check termination: round >= 64 AND E\[last\] <= (round - 32)
1635/// 3. Return K\[0..32\]
1636///
1637/// # Parameters
1638/// - `password`: User password bytes (UTF-8 encoded)
1639/// - `salt`: 8-byte salt (validation_salt or key_salt from U entry)
1640/// - `u_entry`: Full 48-byte U entry (or empty slice for initial computation)
1641///
1642/// # Returns
1643/// 32-byte derived key
1644///
1645/// # Security Notes
1646/// - Maximum 2048 rounds to prevent DoS attacks
1647/// - Variable iteration count makes brute-force harder
1648/// - AES encryption + hash rotation provides strong KDF
1649///
1650/// # References
1651/// - ISO 32000-2:2020 §7.6.4.3.4 "Algorithm 2.B: Computing a hash (R6)"
1652pub fn compute_hash_r6_algorithm_2b(
1653    password: &[u8],
1654    salt: &[u8],
1655    u_entry: &[u8],
1656) -> Result<Vec<u8>> {
1657    // Security: Validate password length to prevent DoS via massive allocations
1658    if password.len() > ALGORITHM_2B_MAX_PASSWORD_LEN {
1659        return Err(crate::error::PdfError::EncryptionError(format!(
1660            "Password too long ({} bytes, max {})",
1661            password.len(),
1662            ALGORITHM_2B_MAX_PASSWORD_LEN
1663        )));
1664    }
1665
1666    // Step 1: Initial hash K = SHA-256(password + salt + U[0..48])
1667    let mut input = Vec::with_capacity(password.len() + salt.len() + u_entry.len().min(48));
1668    input.extend_from_slice(password);
1669    input.extend_from_slice(salt);
1670    if !u_entry.is_empty() {
1671        input.extend_from_slice(&u_entry[..u_entry.len().min(48)]);
1672    }
1673
1674    let mut k = sha256(&input);
1675
1676    // Step 2: Iteration loop
1677    let mut round: usize = 0;
1678    loop {
1679        // 2a. Construct input sequence: password + K + U[0..48], repeated
1680        // The spec says to create a sequence that will be encrypted
1681        let mut k1_unit = Vec::new();
1682        k1_unit.extend_from_slice(password);
1683        k1_unit.extend_from_slice(&k);
1684        if !u_entry.is_empty() {
1685            k1_unit.extend_from_slice(&u_entry[..u_entry.len().min(48)]);
1686        }
1687
1688        // Repeat 64 times to create input for AES
1689        let mut k1 = Vec::with_capacity(k1_unit.len() * 64);
1690        for _ in 0..64 {
1691            k1.extend_from_slice(&k1_unit);
1692        }
1693
1694        // Zero-pad to AES block size (16 bytes) per ISO 32000-2 §7.6.4.3.4
1695        // NOTE: This is zero-padding, NOT PKCS#7 - the spec requires raw AES without padding removal
1696        while k1.len() % 16 != 0 {
1697            k1.push(0);
1698        }
1699
1700        // 2b. AES-128-CBC encryption
1701        // Key: first 16 bytes of K, IV: next 16 bytes of K
1702        if k.len() < 32 {
1703            // Extend K if needed (shouldn't happen with proper hashes)
1704            while k.len() < 32 {
1705                k.push(0);
1706            }
1707        }
1708
1709        let aes_key = AesKey::new_128(k[..16].to_vec()).map_err(|e| {
1710            crate::error::PdfError::EncryptionError(format!(
1711                "Algorithm 2.B: Failed to create AES key: {}",
1712                e
1713            ))
1714        })?;
1715        let aes = Aes::new(aes_key);
1716        let iv = &k[16..32];
1717
1718        let e = aes.encrypt_cbc_raw(&k1, iv).map_err(|e| {
1719            crate::error::PdfError::EncryptionError(format!(
1720                "Algorithm 2.B: AES encryption failed: {}",
1721                e
1722            ))
1723        })?;
1724
1725        // 2c. Select hash function based on first 16 bytes of E as BigInteger mod 3
1726        // Per iText/Adobe implementation: interpret E[0..HASH_SELECTOR_BYTES] as big-endian integer
1727        // Mathematical equivalence: sum(bytes) mod 3 == BigInteger(bytes) mod 3
1728        // because 256 mod 3 = 1, therefore 256^k mod 3 = 1 for all k
1729        let hash_selector = {
1730            let sum: u64 = e[..HASH_SELECTOR_BYTES.min(e.len())]
1731                .iter()
1732                .map(|&b| b as u64)
1733                .sum();
1734            (sum % 3) as u8
1735        };
1736
1737        k = match hash_selector {
1738            0 => sha256(&e),
1739            1 => sha384(&e),
1740            2 => sha512(&e),
1741            _ => unreachable!("Modulo 3 can only be 0, 1, or 2"),
1742        };
1743
1744        // 2d. Check termination condition
1745        // Terminate when: round >= 64 AND E[last] <= (round - 32)
1746        let last_byte = *e.last().unwrap_or(&0);
1747        round += 1;
1748
1749        if round >= ALGORITHM_2B_MIN_ROUNDS {
1750            // The termination condition from ISO spec:
1751            // "the last byte value of the last iteration is less than or equal to
1752            // the number of iterations minus 32"
1753            if (last_byte as usize) <= round.saturating_sub(32) {
1754                break;
1755            }
1756        }
1757
1758        // Safety: Prevent infinite loop (DoS protection)
1759        if round >= ALGORITHM_2B_MAX_ROUNDS {
1760            break;
1761        }
1762    }
1763
1764    // Step 3: Return first 32 bytes of final K
1765    // K might be > 32 bytes if last hash was SHA-384 or SHA-512
1766    Ok(k[..32.min(k.len())].to_vec())
1767}
1768
1769/// R5 salt length in bytes (PDF spec §7.6.4.3.4)
1770const R5_SALT_LENGTH: usize = 8;
1771
1772/// R5 SHA-256 iteration count (ISO 32000-2:2020 Algorithm 8/11)
1773/// NOTE: R5 does NOT use iterations - hash is simply SHA-256(password + salt)
1774/// The 64 iterations are only for R6 which uses Algorithm 2.B
1775const R5_HASH_ITERATIONS: usize = 0;
1776
1777/// R6 salt length in bytes (PDF spec ISO 32000-2)
1778const R6_SALT_LENGTH: usize = 8;
1779
1780// ============================================================================
1781// R5/R6 U Entry Structure Constants (48 bytes total)
1782// ============================================================================
1783
1784/// Length of the hash portion in U entry (SHA-256/SHA-512 truncated to 32 bytes)
1785const U_HASH_LENGTH: usize = 32;
1786
1787/// Start offset of validation salt in U entry
1788const U_VALIDATION_SALT_START: usize = 32;
1789
1790/// End offset of validation salt in U entry
1791const U_VALIDATION_SALT_END: usize = 40;
1792
1793/// Start offset of key salt in U entry
1794const U_KEY_SALT_START: usize = 40;
1795
1796/// End offset of key salt in U entry
1797const U_KEY_SALT_END: usize = 48;
1798
1799/// Total length of U entry for R5/R6
1800const U_ENTRY_LENGTH: usize = 48;
1801
1802/// Length of UE entry (encrypted encryption key)
1803const UE_ENTRY_LENGTH: usize = 32;
1804
1805// ============================================================================
1806// R6 Perms Entry Structure Constants (16 bytes total)
1807// ============================================================================
1808
1809/// Length of Perms entry
1810const PERMS_ENTRY_LENGTH: usize = 16;
1811
1812/// Start offset of permissions value in decrypted Perms (little-endian u32)
1813const PERMS_P_START: usize = 0;
1814
1815/// End offset of permissions value in decrypted Perms
1816const PERMS_P_END: usize = 4;
1817
1818/// Start offset of fixed marker (0xFFFFFFFF) in decrypted Perms
1819const PERMS_MARKER_START: usize = 4;
1820
1821/// End offset of fixed marker in decrypted Perms
1822const PERMS_MARKER_END: usize = 8;
1823
1824/// Start offset of "adb" literal in decrypted Perms
1825const PERMS_LITERAL_START: usize = 8;
1826
1827/// End offset of "adb" literal in decrypted Perms
1828const PERMS_LITERAL_END: usize = 11;
1829
1830/// Offset of EncryptMetadata flag byte ('T' or 'F') in decrypted Perms
1831const PERMS_ENCRYPT_META_BYTE: usize = 11;
1832
1833/// Fixed marker value in Perms entry
1834const PERMS_MARKER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
1835
1836/// Literal verification string in Perms entry
1837const PERMS_LITERAL: &[u8; 3] = b"adb";
1838
1839/// Generate cryptographically secure random salt using OS CSPRNG
1840///
1841/// Uses `rand::rng()` which provides a thread-local CSPRNG (ChaCha12) seeded
1842/// from the OS random number generator. This is suitable for PDF encryption salts.
1843///
1844/// # Security
1845/// - Uses ChaCha12 PRNG seeded from OS entropy (rand 0.9 implementation)
1846/// - Provides cryptographic-quality randomness for salt generation
1847/// - Each call produces independent random bytes
1848fn generate_salt(len: usize) -> Vec<u8> {
1849    let mut salt = vec![0u8; len];
1850    rand::rng().fill_bytes(&mut salt);
1851    salt
1852}
1853
1854#[cfg(test)]
1855mod tests {
1856    use super::*;
1857
1858    #[test]
1859    fn test_pad_password() {
1860        let padded = StandardSecurityHandler::pad_password("test");
1861        assert_eq!(padded.len(), 32);
1862        assert_eq!(&padded[..4], b"test");
1863        assert_eq!(&padded[4..8], &PADDING[..4]);
1864    }
1865
1866    #[test]
1867    fn test_pad_password_long() {
1868        let long_password = "a".repeat(40);
1869        let padded = StandardSecurityHandler::pad_password(&long_password);
1870        assert_eq!(padded.len(), 32);
1871        assert_eq!(&padded[..32], &long_password.as_bytes()[..32]);
1872    }
1873
1874    #[test]
1875    fn test_rc4_40bit_handler() {
1876        let handler = StandardSecurityHandler::rc4_40bit();
1877        assert_eq!(handler.revision, SecurityHandlerRevision::R2);
1878        assert_eq!(handler.key_length, 5);
1879    }
1880
1881    #[test]
1882    fn test_rc4_128bit_handler() {
1883        let handler = StandardSecurityHandler::rc4_128bit();
1884        assert_eq!(handler.revision, SecurityHandlerRevision::R3);
1885        assert_eq!(handler.key_length, 16);
1886    }
1887
1888    #[test]
1889    fn test_owner_hash_computation() {
1890        let handler = StandardSecurityHandler::rc4_40bit();
1891        let owner_pwd = OwnerPassword("owner".to_string());
1892        let user_pwd = UserPassword("user".to_string());
1893
1894        let hash = handler.compute_owner_hash(&owner_pwd, &user_pwd);
1895        assert_eq!(hash.len(), 32);
1896    }
1897
1898    #[test]
1899    fn test_encryption_key_computation() {
1900        let handler = StandardSecurityHandler::rc4_40bit();
1901        let user_pwd = UserPassword("user".to_string());
1902        let owner_hash = vec![0u8; 32];
1903        let permissions = Permissions::new();
1904
1905        let key = handler
1906            .compute_encryption_key(&user_pwd, &owner_hash, permissions, None)
1907            .unwrap();
1908
1909        assert_eq!(key.len(), 5);
1910    }
1911
1912    #[test]
1913    fn test_aes_256_r5_handler() {
1914        let handler = StandardSecurityHandler::aes_256_r5();
1915        assert_eq!(handler.revision, SecurityHandlerRevision::R5);
1916        assert_eq!(handler.key_length, 32);
1917    }
1918
1919    #[test]
1920    fn test_aes_256_r6_handler() {
1921        let handler = StandardSecurityHandler::aes_256_r6();
1922        assert_eq!(handler.revision, SecurityHandlerRevision::R6);
1923        assert_eq!(handler.key_length, 32);
1924    }
1925
1926    #[test]
1927    fn test_aes_encryption_key_computation() {
1928        let handler = StandardSecurityHandler::aes_256_r5();
1929        let user_pwd = UserPassword("testuser".to_string());
1930        let owner_hash = vec![0u8; 32];
1931        let permissions = Permissions::new();
1932
1933        let key = handler
1934            .compute_aes_encryption_key(&user_pwd, &owner_hash, permissions, None)
1935            .unwrap();
1936
1937        assert_eq!(key.len(), 32);
1938    }
1939
1940    #[test]
1941    fn test_aes_encrypt_decrypt() {
1942        let handler = StandardSecurityHandler::aes_256_r5();
1943        let key = EncryptionKey::new(vec![0u8; 32]);
1944        let obj_id = ObjectId::new(1, 0);
1945        let data = b"Hello AES encryption!";
1946
1947        let encrypted = handler.encrypt_aes(data, &key, &obj_id).unwrap();
1948        assert_ne!(encrypted.as_slice(), data);
1949        assert!(encrypted.len() > data.len()); // Should include IV
1950
1951        // Note: This simplified AES implementation is for demonstration only
1952        let _decrypted = handler.decrypt_aes(&encrypted, &key, &obj_id);
1953        // For now, just test that the operations complete without panicking
1954    }
1955
1956    #[test]
1957    fn test_aes_with_rc4_handler_fails() {
1958        let handler = StandardSecurityHandler::rc4_128bit();
1959        let key = EncryptionKey::new(vec![0u8; 16]);
1960        let obj_id = ObjectId::new(1, 0);
1961        let data = b"test data";
1962
1963        // Should fail because handler is not Rev 5+
1964        assert!(handler.encrypt_aes(data, &key, &obj_id).is_err());
1965        assert!(handler.decrypt_aes(data, &key, &obj_id).is_err());
1966    }
1967
1968    #[test]
1969    fn test_aes_decrypt_invalid_data() {
1970        let handler = StandardSecurityHandler::aes_256_r5();
1971        let key = EncryptionKey::new(vec![0u8; 32]);
1972        let obj_id = ObjectId::new(1, 0);
1973
1974        // Data too short (no IV)
1975        let short_data = vec![0u8; 10];
1976        assert!(handler.decrypt_aes(&short_data, &key, &obj_id).is_err());
1977    }
1978
1979    #[test]
1980    fn test_sha256_deterministic() {
1981        let data1 = b"test data";
1982        let data2 = b"test data";
1983        let data3 = b"different data";
1984
1985        let hash1 = sha256(data1);
1986        let hash2 = sha256(data2);
1987        let hash3 = sha256(data3);
1988
1989        assert_eq!(hash1.len(), 32);
1990        assert_eq!(hash2.len(), 32);
1991        assert_eq!(hash3.len(), 32);
1992
1993        assert_eq!(hash1, hash2); // Same input should give same output
1994        assert_ne!(hash1, hash3); // Different input should give different output
1995    }
1996
1997    #[test]
1998    fn test_security_handler_revision_ordering() {
1999        assert!(SecurityHandlerRevision::R2 < SecurityHandlerRevision::R3);
2000        assert!(SecurityHandlerRevision::R3 < SecurityHandlerRevision::R4);
2001        assert!(SecurityHandlerRevision::R4 < SecurityHandlerRevision::R5);
2002        assert!(SecurityHandlerRevision::R5 < SecurityHandlerRevision::R6);
2003    }
2004
2005    #[test]
2006    fn test_aes_password_validation() {
2007        let handler = StandardSecurityHandler::aes_256_r5();
2008        let password = UserPassword("testpassword".to_string());
2009        let user_hash = vec![0u8; 32]; // Simplified hash
2010        let permissions = Permissions::new();
2011
2012        // This is a basic test - in practice, the validation would be more complex
2013        let result = handler.validate_aes_user_password(&password, &user_hash, permissions, None);
2014        assert!(result.is_ok());
2015    }
2016
2017    // ===== Additional Comprehensive Tests =====
2018
2019    #[test]
2020    fn test_user_password_debug() {
2021        let pwd = UserPassword("debug_test".to_string());
2022        let debug_str = format!("{pwd:?}");
2023        assert!(debug_str.contains("UserPassword"));
2024        assert!(debug_str.contains("debug_test"));
2025    }
2026
2027    #[test]
2028    fn test_owner_password_debug() {
2029        let pwd = OwnerPassword("owner_debug".to_string());
2030        let debug_str = format!("{pwd:?}");
2031        assert!(debug_str.contains("OwnerPassword"));
2032        assert!(debug_str.contains("owner_debug"));
2033    }
2034
2035    #[test]
2036    fn test_encryption_key_debug() {
2037        let key = EncryptionKey::new(vec![0x01, 0x02, 0x03]);
2038        let debug_str = format!("{key:?}");
2039        assert!(debug_str.contains("EncryptionKey"));
2040    }
2041
2042    #[test]
2043    fn test_security_handler_revision_equality() {
2044        assert_eq!(SecurityHandlerRevision::R2, SecurityHandlerRevision::R2);
2045        assert_ne!(SecurityHandlerRevision::R2, SecurityHandlerRevision::R3);
2046    }
2047
2048    #[test]
2049    fn test_security_handler_revision_values() {
2050        assert_eq!(SecurityHandlerRevision::R2 as u8, 2);
2051        assert_eq!(SecurityHandlerRevision::R3 as u8, 3);
2052        assert_eq!(SecurityHandlerRevision::R4 as u8, 4);
2053        assert_eq!(SecurityHandlerRevision::R5 as u8, 5);
2054        assert_eq!(SecurityHandlerRevision::R6 as u8, 6);
2055    }
2056
2057    #[test]
2058    fn test_pad_password_various_lengths() {
2059        for len in 0..=40 {
2060            let password = "x".repeat(len);
2061            let padded = StandardSecurityHandler::pad_password(&password);
2062            assert_eq!(padded.len(), 32);
2063
2064            if len <= 32 {
2065                assert_eq!(&padded[..len], password.as_bytes());
2066            } else {
2067                assert_eq!(&padded[..], &password.as_bytes()[..32]);
2068            }
2069        }
2070    }
2071
2072    #[test]
2073    fn test_pad_password_unicode() {
2074        let padded = StandardSecurityHandler::pad_password("café");
2075        assert_eq!(padded.len(), 32);
2076        // UTF-8 encoding of "café" is 5 bytes
2077        assert_eq!(&padded[..5], "café".as_bytes());
2078    }
2079
2080    #[test]
2081    fn test_compute_owner_hash_different_users() {
2082        let handler = StandardSecurityHandler::rc4_128bit();
2083        let owner = OwnerPassword("owner".to_string());
2084        let user1 = UserPassword("user1".to_string());
2085        let user2 = UserPassword("user2".to_string());
2086
2087        let hash1 = handler.compute_owner_hash(&owner, &user1);
2088        let hash2 = handler.compute_owner_hash(&owner, &user2);
2089
2090        assert_ne!(hash1, hash2); // Different user passwords should produce different hashes
2091    }
2092
2093    #[test]
2094    fn test_compute_user_hash_r4() {
2095        let handler = StandardSecurityHandler {
2096            revision: SecurityHandlerRevision::R4,
2097            key_length: 16,
2098        };
2099        let user = UserPassword("r4test".to_string());
2100        let owner_hash = vec![0xAA; 32];
2101        let permissions = Permissions::new();
2102
2103        let hash = handler
2104            .compute_user_hash(&user, &owner_hash, permissions, None)
2105            .unwrap();
2106        assert_eq!(hash.len(), 32);
2107    }
2108
2109    #[test]
2110    fn test_compute_user_hash_r6() {
2111        let handler = StandardSecurityHandler::aes_256_r6();
2112        let user = UserPassword("r6test".to_string());
2113        let owner_hash = vec![0xBB; 32];
2114        let permissions = Permissions::all();
2115
2116        let hash = handler
2117            .compute_user_hash(&user, &owner_hash, permissions, None)
2118            .unwrap();
2119        assert_eq!(hash.len(), 32);
2120    }
2121
2122    #[test]
2123    fn test_encryption_key_with_file_id_affects_result() {
2124        let handler = StandardSecurityHandler::rc4_128bit();
2125        let user = UserPassword("test".to_string());
2126        let owner_hash = vec![0xFF; 32];
2127        let permissions = Permissions::new();
2128        let file_id = b"unique_file_id_12345";
2129
2130        let key_with_id = handler
2131            .compute_encryption_key(&user, &owner_hash, permissions, Some(file_id))
2132            .unwrap();
2133        let key_without_id = handler
2134            .compute_encryption_key(&user, &owner_hash, permissions, None)
2135            .unwrap();
2136
2137        assert_ne!(key_with_id.key, key_without_id.key);
2138    }
2139
2140    #[test]
2141    fn test_encrypt_string_empty() {
2142        let handler = StandardSecurityHandler::rc4_40bit();
2143        let key = EncryptionKey::new(vec![0x01, 0x02, 0x03, 0x04, 0x05]);
2144        let obj_id = ObjectId::new(1, 0);
2145
2146        let encrypted = handler.encrypt_string(b"", &key, &obj_id);
2147        assert_eq!(encrypted.len(), 0);
2148    }
2149
2150    #[test]
2151    fn test_encrypt_decrypt_large_data() {
2152        let handler = StandardSecurityHandler::rc4_128bit();
2153        let key = EncryptionKey::new(vec![0xAA; 16]);
2154        let obj_id = ObjectId::new(42, 0);
2155        let large_data = vec![0x55; 10000]; // 10KB
2156
2157        let encrypted = handler.encrypt_string(&large_data, &key, &obj_id);
2158        assert_eq!(encrypted.len(), large_data.len());
2159        assert_ne!(encrypted, large_data);
2160
2161        let decrypted = handler.decrypt_string(&encrypted, &key, &obj_id);
2162        assert_eq!(decrypted, large_data);
2163    }
2164
2165    #[test]
2166    fn test_stream_encryption_different_from_string() {
2167        // For current implementation they're the same, but test separately
2168        let handler = StandardSecurityHandler::rc4_128bit();
2169        let key = EncryptionKey::new(vec![0x11; 16]);
2170        let obj_id = ObjectId::new(5, 1);
2171        let data = b"Stream content test";
2172
2173        let encrypted_string = handler.encrypt_string(data, &key, &obj_id);
2174        let encrypted_stream = handler.encrypt_stream(data, &key, &obj_id);
2175
2176        assert_eq!(encrypted_string, encrypted_stream); // Currently same implementation
2177    }
2178
2179    #[test]
2180    fn test_aes_encryption_with_different_object_ids() {
2181        let handler = StandardSecurityHandler::aes_256_r5();
2182        let key = EncryptionKey::new(vec![0x77; 32]);
2183        let obj_id1 = ObjectId::new(10, 0);
2184        let obj_id2 = ObjectId::new(11, 0);
2185        let data = b"AES test data";
2186
2187        let encrypted1 = handler.encrypt_aes(data, &key, &obj_id1).unwrap();
2188        let encrypted2 = handler.encrypt_aes(data, &key, &obj_id2).unwrap();
2189
2190        // Different object IDs should produce different ciphertexts
2191        assert_ne!(encrypted1, encrypted2);
2192    }
2193
2194    #[test]
2195    fn test_aes_decrypt_invalid_iv_length() {
2196        let handler = StandardSecurityHandler::aes_256_r5();
2197        let key = EncryptionKey::new(vec![0x88; 32]);
2198        let obj_id = ObjectId::new(1, 0);
2199
2200        // Data too short to contain IV
2201        let short_data = vec![0u8; 10];
2202        assert!(handler.decrypt_aes(&short_data, &key, &obj_id).is_err());
2203
2204        // Exactly 16 bytes (only IV, no encrypted data)
2205        let iv_only = vec![0u8; 16];
2206        let result = handler.decrypt_aes(&iv_only, &key, &obj_id);
2207        // This might succeed with empty decrypted data or fail depending on implementation
2208        if let Ok(decrypted) = result {
2209            assert_eq!(decrypted.len(), 0);
2210        }
2211    }
2212
2213    #[test]
2214    fn test_aes_validate_password_wrong_hash_length() {
2215        let handler = StandardSecurityHandler::aes_256_r5();
2216        let password = UserPassword("test".to_string());
2217        let short_hash = vec![0u8; 16]; // Too short
2218        let permissions = Permissions::new();
2219
2220        let result = handler
2221            .validate_aes_user_password(&password, &short_hash, permissions, None)
2222            .unwrap();
2223        assert!(!result); // Should return false for invalid hash
2224    }
2225
2226    #[test]
2227    fn test_permissions_affect_encryption_key() {
2228        let handler = StandardSecurityHandler::rc4_128bit();
2229        let user = UserPassword("same_user".to_string());
2230        let owner_hash = vec![0xCC; 32];
2231
2232        let perms1 = Permissions::new();
2233        let perms2 = Permissions::all();
2234
2235        let key1 = handler
2236            .compute_encryption_key(&user, &owner_hash, perms1, None)
2237            .unwrap();
2238        let key2 = handler
2239            .compute_encryption_key(&user, &owner_hash, perms2, None)
2240            .unwrap();
2241
2242        assert_ne!(key1.key, key2.key); // Different permissions should affect the key
2243    }
2244
2245    #[test]
2246    fn test_different_handlers_produce_different_keys() {
2247        let user = UserPassword("test".to_string());
2248        let owner_hash = vec![0xDD; 32];
2249        let permissions = Permissions::new();
2250
2251        let handler_r2 = StandardSecurityHandler::rc4_40bit();
2252        let handler_r3 = StandardSecurityHandler::rc4_128bit();
2253
2254        let key_r2 = handler_r2
2255            .compute_encryption_key(&user, &owner_hash, permissions, None)
2256            .unwrap();
2257        let key_r3 = handler_r3
2258            .compute_encryption_key(&user, &owner_hash, permissions, None)
2259            .unwrap();
2260
2261        assert_ne!(key_r2.len(), key_r3.len()); // Different key lengths
2262        assert_eq!(key_r2.len(), 5);
2263        assert_eq!(key_r3.len(), 16);
2264    }
2265
2266    #[test]
2267    fn test_full_workflow_aes_r6() {
2268        let handler = StandardSecurityHandler::aes_256_r6();
2269        let user_pwd = UserPassword("user_r6".to_string());
2270        let permissions = Permissions::new();
2271        let file_id = b"test_file_r6";
2272
2273        // For AES R5/R6, owner hash computation is different - use a dummy hash
2274        let owner_hash = vec![0x42; 32]; // AES uses 32-byte hashes
2275
2276        // Compute user hash
2277        let user_hash = handler
2278            .compute_user_hash(&user_pwd, &owner_hash, permissions, Some(file_id))
2279            .unwrap();
2280        assert_eq!(user_hash.len(), 32);
2281
2282        // Compute encryption key
2283        let key = handler
2284            .compute_aes_encryption_key(&user_pwd, &owner_hash, permissions, Some(file_id))
2285            .unwrap();
2286        assert_eq!(key.len(), 32);
2287
2288        // Test string encryption (uses AES for R6)
2289        let obj_id = ObjectId::new(100, 5);
2290        let content = b"R6 AES encryption test";
2291        let encrypted = handler.encrypt_string(content, &key, &obj_id);
2292
2293        // With AES, encrypted should be empty on error or have data
2294        if !encrypted.is_empty() {
2295            assert_ne!(encrypted.as_slice(), content);
2296        }
2297    }
2298
2299    #[test]
2300    fn test_md5_compute_consistency() {
2301        let data = b"consistent data for md5";
2302        let hash1 = md5::compute(data);
2303        let hash2 = md5::compute(data);
2304
2305        assert_eq!(hash1, hash2);
2306        assert_eq!(hash1.len(), 16);
2307    }
2308
2309    #[test]
2310    fn test_sha256_consistency() {
2311        let data = b"consistent data for sha256";
2312        let hash1 = sha256(data);
2313        let hash2 = sha256(data);
2314
2315        assert_eq!(hash1, hash2);
2316        assert_eq!(hash1.len(), 32);
2317    }
2318
2319    #[test]
2320    fn test_rc4_encrypt_helper() {
2321        let key = Rc4Key::from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05]);
2322        let data = b"test rc4 helper";
2323
2324        let encrypted = rc4_encrypt(&key, data);
2325        assert_ne!(encrypted.as_slice(), data);
2326
2327        // RC4 is symmetric
2328        let decrypted = rc4_encrypt(&key, &encrypted);
2329        assert_eq!(decrypted.as_slice(), data);
2330    }
2331
2332    #[test]
2333    fn test_edge_case_max_object_generation() {
2334        let handler = StandardSecurityHandler::rc4_128bit();
2335        let key = EncryptionKey::new(vec![0xEE; 16]);
2336        let obj_id = ObjectId::new(0xFFFFFF, 0xFFFF); // Max values
2337        let data = b"edge case";
2338
2339        let encrypted = handler.encrypt_string(data, &key, &obj_id);
2340        let decrypted = handler.decrypt_string(&encrypted, &key, &obj_id);
2341        assert_eq!(decrypted.as_slice(), data);
2342    }
2343
2344    // ===== SHA-256/512 NIST Vector Tests (Phase 1.3 - RustCrypto Integration) =====
2345
2346    #[test]
2347    fn test_sha256_nist_empty_string() {
2348        // NIST FIPS 180-4 test vector: SHA-256("")
2349        let hash = sha256(b"");
2350        let expected: [u8; 32] = [
2351            0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
2352            0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
2353            0x78, 0x52, 0xb8, 0x55,
2354        ];
2355        assert_eq!(
2356            hash.as_slice(),
2357            expected.as_slice(),
2358            "SHA-256('') must match NIST test vector"
2359        );
2360    }
2361
2362    #[test]
2363    fn test_sha256_nist_abc() {
2364        // NIST FIPS 180-4 test vector: SHA-256("abc")
2365        let hash = sha256(b"abc");
2366        let expected: [u8; 32] = [
2367            0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
2368            0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
2369            0xf2, 0x00, 0x15, 0xad,
2370        ];
2371        assert_eq!(
2372            hash.as_slice(),
2373            expected.as_slice(),
2374            "SHA-256('abc') must match NIST test vector"
2375        );
2376    }
2377
2378    #[test]
2379    fn test_sha512_nist_abc() {
2380        // NIST FIPS 180-4 test vector: SHA-512("abc")
2381        let hash = sha512(b"abc");
2382        let expected: [u8; 64] = [
2383            0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20,
2384            0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6,
2385            0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba,
2386            0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
2387            0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f,
2388        ];
2389        assert_eq!(
2390            hash.as_slice(),
2391            expected.as_slice(),
2392            "SHA-512('abc') must match NIST test vector"
2393        );
2394    }
2395
2396    #[test]
2397    fn test_sha512_length() {
2398        let hash = sha512(b"test data");
2399        assert_eq!(hash.len(), 64, "SHA-512 must produce 64 bytes");
2400    }
2401
2402    #[test]
2403    fn test_sha512_deterministic() {
2404        let data1 = b"sha512 test data";
2405        let data2 = b"sha512 test data";
2406        let data3 = b"different data";
2407
2408        let hash1 = sha512(data1);
2409        let hash2 = sha512(data2);
2410        let hash3 = sha512(data3);
2411
2412        assert_eq!(hash1, hash2, "Same input must produce same SHA-512 hash");
2413        assert_ne!(hash1, hash3, "Different input must produce different hash");
2414    }
2415
2416    // ===== Phase 2.1: R5 User Password Tests (Algorithm 8 & 11) =====
2417
2418    #[test]
2419    fn test_r5_user_hash_computation() {
2420        let handler = StandardSecurityHandler::aes_256_r5();
2421        let password = UserPassword("test_password".to_string());
2422
2423        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2424
2425        // U entry must be exactly 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
2426        assert_eq!(u_entry.len(), 48, "R5 U entry must be 48 bytes");
2427    }
2428
2429    #[test]
2430    fn test_r5_user_password_validation_correct() {
2431        let handler = StandardSecurityHandler::aes_256_r5();
2432        let password = UserPassword("correct_password".to_string());
2433
2434        // Compute U entry with the password
2435        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2436
2437        // Validate with same password should succeed
2438        let is_valid = handler
2439            .validate_r5_user_password(&password, &u_entry)
2440            .unwrap();
2441        assert!(is_valid, "Correct password must validate");
2442    }
2443
2444    #[test]
2445    fn test_r5_user_password_validation_incorrect() {
2446        let handler = StandardSecurityHandler::aes_256_r5();
2447        let correct_password = UserPassword("correct_password".to_string());
2448        let wrong_password = UserPassword("wrong_password".to_string());
2449
2450        // Compute U entry with correct password
2451        let u_entry = handler.compute_r5_user_hash(&correct_password).unwrap();
2452
2453        // Validate with wrong password should fail
2454        let is_valid = handler
2455            .validate_r5_user_password(&wrong_password, &u_entry)
2456            .unwrap();
2457        assert!(!is_valid, "Wrong password must not validate");
2458    }
2459
2460    #[test]
2461    fn test_r5_user_hash_random_salts() {
2462        let handler = StandardSecurityHandler::aes_256_r5();
2463        let password = UserPassword("same_password".to_string());
2464
2465        // Compute U entry twice - salts should be different
2466        let u_entry1 = handler.compute_r5_user_hash(&password).unwrap();
2467        let u_entry2 = handler.compute_r5_user_hash(&password).unwrap();
2468
2469        // Hash portion should be different (due to random salts)
2470        assert_ne!(
2471            &u_entry1[..32],
2472            &u_entry2[..32],
2473            "Different random salts should produce different hashes"
2474        );
2475
2476        // Validation salt should be different
2477        assert_ne!(
2478            &u_entry1[32..40],
2479            &u_entry2[32..40],
2480            "Validation salts must be random"
2481        );
2482
2483        // But both should validate with the same password
2484        assert!(handler
2485            .validate_r5_user_password(&password, &u_entry1)
2486            .unwrap());
2487        assert!(handler
2488            .validate_r5_user_password(&password, &u_entry2)
2489            .unwrap());
2490    }
2491
2492    #[test]
2493    fn test_r5_user_hash_invalid_entry_length() {
2494        let handler = StandardSecurityHandler::aes_256_r5();
2495        let password = UserPassword("test".to_string());
2496
2497        // Try to validate with wrong length U entry
2498        let short_entry = vec![0u8; 32]; // Too short
2499        let result = handler.validate_r5_user_password(&password, &short_entry);
2500        assert!(result.is_err(), "Short U entry must fail");
2501
2502        let long_entry = vec![0u8; 64]; // Too long
2503        let result = handler.validate_r5_user_password(&password, &long_entry);
2504        assert!(result.is_err(), "Long U entry must fail");
2505    }
2506
2507    #[test]
2508    fn test_r5_empty_password() {
2509        let handler = StandardSecurityHandler::aes_256_r5();
2510        let empty_password = UserPassword("".to_string());
2511
2512        // Empty password should work (common for user-only encryption)
2513        let u_entry = handler.compute_r5_user_hash(&empty_password).unwrap();
2514        assert_eq!(u_entry.len(), 48);
2515
2516        let is_valid = handler
2517            .validate_r5_user_password(&empty_password, &u_entry)
2518            .unwrap();
2519        assert!(is_valid, "Empty password must validate correctly");
2520
2521        // Non-empty password should fail
2522        let non_empty = UserPassword("not_empty".to_string());
2523        let is_valid = handler
2524            .validate_r5_user_password(&non_empty, &u_entry)
2525            .unwrap();
2526        assert!(!is_valid, "Non-empty password must not validate");
2527    }
2528
2529    // ===== Phase 2.2: R5 UE Entry Tests (Encryption Key Storage) =====
2530
2531    #[test]
2532    fn test_r5_ue_entry_computation() {
2533        let handler = StandardSecurityHandler::aes_256_r5();
2534        let password = UserPassword("ue_test_password".to_string());
2535        let encryption_key = EncryptionKey::new(vec![0xAB; 32]);
2536
2537        // Compute U entry first
2538        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2539
2540        // Compute UE entry
2541        let ue_entry = handler
2542            .compute_r5_ue_entry(&password, &u_entry, &encryption_key)
2543            .unwrap();
2544
2545        // UE entry must be exactly 32 bytes
2546        assert_eq!(ue_entry.len(), 32, "R5 UE entry must be 32 bytes");
2547
2548        // UE should be different from the original key (it's encrypted)
2549        assert_ne!(
2550            ue_entry.as_slice(),
2551            encryption_key.as_bytes(),
2552            "UE must be encrypted"
2553        );
2554    }
2555
2556    #[test]
2557    fn test_r5_encryption_key_recovery() {
2558        let handler = StandardSecurityHandler::aes_256_r5();
2559        let password = UserPassword("recovery_test".to_string());
2560        let original_key = EncryptionKey::new(vec![0x42; 32]);
2561
2562        // Compute U entry
2563        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2564
2565        // Compute UE entry
2566        let ue_entry = handler
2567            .compute_r5_ue_entry(&password, &u_entry, &original_key)
2568            .unwrap();
2569
2570        // Recover the key
2571        let recovered_key = handler
2572            .recover_r5_encryption_key(&password, &u_entry, &ue_entry)
2573            .unwrap();
2574
2575        // Recovered key must match original
2576        assert_eq!(
2577            recovered_key.as_bytes(),
2578            original_key.as_bytes(),
2579            "Recovered key must match original"
2580        );
2581    }
2582
2583    #[test]
2584    fn test_r5_ue_wrong_password_fails() {
2585        let handler = StandardSecurityHandler::aes_256_r5();
2586        let correct_password = UserPassword("correct".to_string());
2587        let wrong_password = UserPassword("wrong".to_string());
2588        let original_key = EncryptionKey::new(vec![0x99; 32]);
2589
2590        // Compute U and UE with correct password
2591        let u_entry = handler.compute_r5_user_hash(&correct_password).unwrap();
2592        let ue_entry = handler
2593            .compute_r5_ue_entry(&correct_password, &u_entry, &original_key)
2594            .unwrap();
2595
2596        // Try to recover with wrong password
2597        let recovered_key = handler
2598            .recover_r5_encryption_key(&wrong_password, &u_entry, &ue_entry)
2599            .unwrap();
2600
2601        // Key should be different (wrong decryption)
2602        assert_ne!(
2603            recovered_key.as_bytes(),
2604            original_key.as_bytes(),
2605            "Wrong password must produce wrong key"
2606        );
2607    }
2608
2609    #[test]
2610    fn test_r5_ue_invalid_length() {
2611        let handler = StandardSecurityHandler::aes_256_r5();
2612        let password = UserPassword("test".to_string());
2613        let u_entry = vec![0u8; 48]; // Valid U entry length
2614
2615        // Try to recover with wrong length UE entry
2616        let short_ue = vec![0u8; 16]; // Too short
2617        let result = handler.recover_r5_encryption_key(&password, &u_entry, &short_ue);
2618        assert!(result.is_err(), "Short UE entry must fail");
2619
2620        let long_ue = vec![0u8; 64]; // Too long
2621        let result = handler.recover_r5_encryption_key(&password, &u_entry, &long_ue);
2622        assert!(result.is_err(), "Long UE entry must fail");
2623    }
2624
2625    #[test]
2626    fn test_r5_ue_invalid_u_length() {
2627        let handler = StandardSecurityHandler::aes_256_r5();
2628        let password = UserPassword("test".to_string());
2629        let encryption_key = EncryptionKey::new(vec![0x11; 32]);
2630
2631        // Try to compute UE with wrong length U entry
2632        let short_u = vec![0u8; 32]; // Too short
2633        let result = handler.compute_r5_ue_entry(&password, &short_u, &encryption_key);
2634        assert!(
2635            result.is_err(),
2636            "Short U entry must fail for UE computation"
2637        );
2638    }
2639
2640    #[test]
2641    fn test_r5_full_workflow_u_ue() {
2642        let handler = StandardSecurityHandler::aes_256_r5();
2643        let password = UserPassword("full_workflow_test".to_string());
2644        let encryption_key = EncryptionKey::new((0..32).collect::<Vec<u8>>());
2645
2646        // Step 1: Compute U entry (password verification data)
2647        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2648        assert_eq!(u_entry.len(), 48);
2649
2650        // Step 2: Verify password validates
2651        assert!(handler
2652            .validate_r5_user_password(&password, &u_entry)
2653            .unwrap());
2654
2655        // Step 3: Compute UE entry (encrypted key storage)
2656        let ue_entry = handler
2657            .compute_r5_ue_entry(&password, &u_entry, &encryption_key)
2658            .unwrap();
2659        assert_eq!(ue_entry.len(), 32);
2660
2661        // Step 4: Recover key from UE
2662        let recovered = handler
2663            .recover_r5_encryption_key(&password, &u_entry, &ue_entry)
2664            .unwrap();
2665
2666        // Step 5: Verify recovered key matches original
2667        assert_eq!(
2668            recovered.as_bytes(),
2669            encryption_key.as_bytes(),
2670            "Full R5 workflow: recovered key must match original"
2671        );
2672    }
2673
2674    // ===== Phase 3.1: R6 User Password Tests (SHA-512 based) =====
2675
2676    #[test]
2677    fn test_r6_user_hash_computation() {
2678        let handler = StandardSecurityHandler::aes_256_r6();
2679        let password = UserPassword("r6_test_password".to_string());
2680
2681        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2682
2683        // U entry must be exactly 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
2684        assert_eq!(u_entry.len(), 48, "R6 U entry must be 48 bytes");
2685    }
2686
2687    #[test]
2688    fn test_r6_user_password_validation_correct() {
2689        let handler = StandardSecurityHandler::aes_256_r6();
2690        let password = UserPassword("r6_correct_password".to_string());
2691
2692        // Compute U entry with the password
2693        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2694
2695        // Validate with same password should succeed
2696        let is_valid = handler
2697            .validate_r6_user_password(&password, &u_entry)
2698            .unwrap();
2699        assert!(is_valid, "Correct R6 password must validate");
2700    }
2701
2702    #[test]
2703    fn test_r6_user_password_validation_incorrect() {
2704        let handler = StandardSecurityHandler::aes_256_r6();
2705        let correct_password = UserPassword("r6_correct".to_string());
2706        let wrong_password = UserPassword("r6_wrong".to_string());
2707
2708        // Compute U entry with correct password
2709        let u_entry = handler.compute_r6_user_hash(&correct_password).unwrap();
2710
2711        // Validate with wrong password should fail
2712        let is_valid = handler
2713            .validate_r6_user_password(&wrong_password, &u_entry)
2714            .unwrap();
2715        assert!(!is_valid, "Wrong R6 password must not validate");
2716    }
2717
2718    #[test]
2719    fn test_r6_uses_sha512_not_sha256() {
2720        // Verify R6 produces different hash than R5 for same password
2721        let handler_r5 = StandardSecurityHandler::aes_256_r5();
2722        let handler_r6 = StandardSecurityHandler::aes_256_r6();
2723        let password = UserPassword("same_password_both_revisions".to_string());
2724
2725        let u_r5 = handler_r5.compute_r5_user_hash(&password).unwrap();
2726        let u_r6 = handler_r6.compute_r6_user_hash(&password).unwrap();
2727
2728        // Hash portions (first 32 bytes) should be different
2729        // Note: Salts are random, but even with same salt the hash algorithm differs
2730        assert_ne!(
2731            &u_r5[..32],
2732            &u_r6[..32],
2733            "R5 (SHA-256) and R6 (SHA-512) must produce different hashes"
2734        );
2735    }
2736
2737    #[test]
2738    fn test_r6_unicode_password() {
2739        let handler = StandardSecurityHandler::aes_256_r6();
2740        let unicode_password = UserPassword("café🔒日本語".to_string());
2741
2742        let u_entry = handler.compute_r6_user_hash(&unicode_password).unwrap();
2743        assert_eq!(u_entry.len(), 48);
2744
2745        // Validate with same Unicode password
2746        let is_valid = handler
2747            .validate_r6_user_password(&unicode_password, &u_entry)
2748            .unwrap();
2749        assert!(is_valid, "Unicode password must validate");
2750
2751        // Different Unicode password should fail
2752        let different_unicode = UserPassword("café🔓日本語".to_string()); // Different emoji
2753        let is_valid = handler
2754            .validate_r6_user_password(&different_unicode, &u_entry)
2755            .unwrap();
2756        assert!(!is_valid, "Different Unicode password must not validate");
2757    }
2758
2759    // ===== Phase 3.1: R6 UE Entry Tests =====
2760
2761    #[test]
2762    fn test_r6_ue_entry_computation() {
2763        let handler = StandardSecurityHandler::aes_256_r6();
2764        let password = UserPassword("r6_ue_test".to_string());
2765        let encryption_key = EncryptionKey::new(vec![0xCD; 32]);
2766
2767        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2768        let ue_entry = handler
2769            .compute_r6_ue_entry(&password, &u_entry, &encryption_key)
2770            .unwrap();
2771
2772        assert_eq!(ue_entry.len(), 32, "R6 UE entry must be 32 bytes");
2773    }
2774
2775    #[test]
2776    fn test_r6_encryption_key_recovery() {
2777        let handler = StandardSecurityHandler::aes_256_r6();
2778        let password = UserPassword("r6_recovery_test".to_string());
2779        let original_key = EncryptionKey::new(vec![0xEF; 32]);
2780
2781        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2782        let ue_entry = handler
2783            .compute_r6_ue_entry(&password, &u_entry, &original_key)
2784            .unwrap();
2785
2786        let recovered_key = handler
2787            .recover_r6_encryption_key(&password, &u_entry, &ue_entry)
2788            .unwrap();
2789
2790        assert_eq!(
2791            recovered_key.as_bytes(),
2792            original_key.as_bytes(),
2793            "R6: Recovered key must match original"
2794        );
2795    }
2796
2797    // ===== Phase 3.2: R6 Perms Entry Tests =====
2798
2799    #[test]
2800    fn test_r6_perms_entry_computation() {
2801        let handler = StandardSecurityHandler::aes_256_r6();
2802        let permissions = Permissions::all();
2803        let key = EncryptionKey::new(vec![0x42; 32]);
2804
2805        let perms = handler
2806            .compute_r6_perms_entry(permissions, &key, true)
2807            .unwrap();
2808
2809        assert_eq!(perms.len(), 16, "Perms entry must be 16 bytes");
2810    }
2811
2812    #[test]
2813    fn test_r6_perms_validation() {
2814        let handler = StandardSecurityHandler::aes_256_r6();
2815        let permissions = Permissions::new();
2816        let key = EncryptionKey::new(vec![0x55; 32]);
2817
2818        let perms = handler
2819            .compute_r6_perms_entry(permissions, &key, false)
2820            .unwrap();
2821
2822        let is_valid = handler
2823            .validate_r6_perms(&perms, &key, permissions)
2824            .unwrap();
2825        assert!(is_valid, "Perms validation must succeed with correct key");
2826    }
2827
2828    #[test]
2829    fn test_r6_perms_wrong_key_fails() {
2830        let handler = StandardSecurityHandler::aes_256_r6();
2831        let permissions = Permissions::all();
2832        let correct_key = EncryptionKey::new(vec![0xAA; 32]);
2833        let wrong_key = EncryptionKey::new(vec![0xBB; 32]);
2834
2835        let perms = handler
2836            .compute_r6_perms_entry(permissions, &correct_key, true)
2837            .unwrap();
2838
2839        // Validation with wrong key should fail (structure won't match)
2840        let result = handler.validate_r6_perms(&perms, &wrong_key, permissions);
2841        assert!(result.is_ok()); // No error
2842        assert!(!result.unwrap()); // But validation fails
2843    }
2844
2845    #[test]
2846    fn test_r6_perms_encrypt_metadata_flag() {
2847        let handler = StandardSecurityHandler::aes_256_r6();
2848        let permissions = Permissions::new();
2849        let key = EncryptionKey::new(vec![0x33; 32]);
2850
2851        let perms_true = handler
2852            .compute_r6_perms_entry(permissions, &key, true)
2853            .unwrap();
2854        let perms_false = handler
2855            .compute_r6_perms_entry(permissions, &key, false)
2856            .unwrap();
2857
2858        // Different encrypt_metadata flag should produce different Perms
2859        assert_ne!(
2860            perms_true, perms_false,
2861            "Different EncryptMetadata must produce different Perms"
2862        );
2863
2864        // Extract and verify flags
2865        let flag_true = handler
2866            .extract_r6_encrypt_metadata(&perms_true, &key)
2867            .unwrap();
2868        assert_eq!(flag_true, Some(true));
2869
2870        let flag_false = handler
2871            .extract_r6_encrypt_metadata(&perms_false, &key)
2872            .unwrap();
2873        assert_eq!(flag_false, Some(false));
2874    }
2875
2876    #[test]
2877    fn test_r6_perms_invalid_length() {
2878        let handler = StandardSecurityHandler::aes_256_r6();
2879        let key = EncryptionKey::new(vec![0x44; 32]);
2880        let permissions = Permissions::new();
2881
2882        let invalid_perms = vec![0u8; 12]; // Too short
2883        let result = handler.validate_r6_perms(&invalid_perms, &key, permissions);
2884        assert!(result.is_err(), "Short Perms entry must fail");
2885    }
2886
2887    #[test]
2888    fn test_r6_full_workflow_with_perms() {
2889        // Complete R6 integration test: U + UE + Perms
2890        let handler = StandardSecurityHandler::aes_256_r6();
2891        let password = UserPassword("r6_full_workflow".to_string());
2892        let permissions = Permissions::all();
2893        let encryption_key = EncryptionKey::new((0..32).map(|i| (i * 3) as u8).collect());
2894
2895        // Step 1: Compute U entry (password verification)
2896        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2897        assert_eq!(u_entry.len(), 48);
2898
2899        // Step 2: Validate password
2900        assert!(handler
2901            .validate_r6_user_password(&password, &u_entry)
2902            .unwrap());
2903
2904        // Step 3: Compute UE entry (encrypted key)
2905        let ue_entry = handler
2906            .compute_r6_ue_entry(&password, &u_entry, &encryption_key)
2907            .unwrap();
2908        assert_eq!(ue_entry.len(), 32);
2909
2910        // Step 4: Compute Perms entry (encrypted permissions)
2911        let perms = handler
2912            .compute_r6_perms_entry(permissions, &encryption_key, true)
2913            .unwrap();
2914        assert_eq!(perms.len(), 16);
2915
2916        // Step 5: Recover encryption key from UE
2917        let recovered_key = handler
2918            .recover_r6_encryption_key(&password, &u_entry, &ue_entry)
2919            .unwrap();
2920        assert_eq!(
2921            recovered_key.as_bytes(),
2922            encryption_key.as_bytes(),
2923            "Recovered key must match original"
2924        );
2925
2926        // Step 6: Validate Perms with recovered key
2927        let perms_valid = handler
2928            .validate_r6_perms(&perms, &recovered_key, permissions)
2929            .unwrap();
2930        assert!(perms_valid, "Perms must validate with recovered key");
2931
2932        // Step 7: Extract EncryptMetadata flag
2933        let encrypt_meta = handler
2934            .extract_r6_encrypt_metadata(&perms, &recovered_key)
2935            .unwrap();
2936        assert_eq!(encrypt_meta, Some(true), "EncryptMetadata must be true");
2937    }
2938}