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::RngCore;
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    pub fn validate_owner_password(
1480        &self,
1481        owner_password: &OwnerPassword,
1482        owner_hash: &[u8],
1483        _user_password: &UserPassword, // Will be recovered from owner_hash
1484        _permissions: Permissions,
1485        _file_id: Option<&[u8]>,
1486    ) -> Result<bool> {
1487        match self.revision {
1488            SecurityHandlerRevision::R2
1489            | SecurityHandlerRevision::R3
1490            | SecurityHandlerRevision::R4 => {
1491                // Step 1: Pad owner password
1492                let owner_pad = Self::pad_password(&owner_password.0);
1493
1494                // Step 2: Create MD5 hash of owner password
1495                let mut hash = md5::compute(&owner_pad).to_vec();
1496
1497                // Step 3: For revision 3+, do 50 additional iterations
1498                if self.revision >= SecurityHandlerRevision::R3 {
1499                    for _ in 0..50 {
1500                        hash = md5::compute(&hash).to_vec();
1501                    }
1502                }
1503
1504                // Step 4: Create RC4 key from hash (truncated to key length)
1505                let rc4_key = Rc4Key::from_slice(&hash[..self.key_length]);
1506
1507                // Step 5: Decrypt owner hash to get user password
1508                let mut decrypted = owner_hash[..32].to_vec();
1509
1510                // For R3+, do 19 iterations in reverse
1511                if self.revision >= SecurityHandlerRevision::R3 {
1512                    for i in (0..20).rev() {
1513                        let mut key_bytes = hash[..self.key_length].to_vec();
1514                        for byte in &mut key_bytes {
1515                            *byte ^= i as u8;
1516                        }
1517                        let iter_key = Rc4Key::from_slice(&key_bytes);
1518                        decrypted = rc4_encrypt(&iter_key, &decrypted);
1519                    }
1520                } else {
1521                    // For R2, single decryption
1522                    decrypted = rc4_encrypt(&rc4_key, &decrypted);
1523                }
1524
1525                // Step 6: The decrypted data should be the padded user password
1526                // Try to validate by computing what the owner hash SHOULD be
1527                // with this owner password, and compare
1528
1529                // Extract potential user password (remove padding)
1530                let user_pwd_bytes = decrypted
1531                    .iter()
1532                    .take_while(|&&b| b != 0x28 || decrypted.starts_with(&PADDING))
1533                    .copied()
1534                    .collect::<Vec<u8>>();
1535
1536                let recovered_user =
1537                    UserPassword(String::from_utf8_lossy(&user_pwd_bytes).to_string());
1538
1539                // Compute what owner hash should be with this owner password
1540                let computed_owner = self.compute_owner_hash(owner_password, &recovered_user);
1541
1542                // Compare with stored owner hash
1543                Ok(computed_owner[..32] == owner_hash[..32])
1544            }
1545            SecurityHandlerRevision::R5 | SecurityHandlerRevision::R6 => {
1546                // R5/R6 owner password validation requires O/OE entry processing
1547                // (Algorithms 12/13 in ISO 32000-2) - not yet implemented
1548                Err(crate::error::PdfError::EncryptionError(
1549                    "R5/R6 owner password validation not yet implemented (Phase 3)".to_string(),
1550                ))
1551            }
1552        }
1553    }
1554}
1555
1556/// Helper function for RC4 encryption
1557fn rc4_encrypt(key: &Rc4Key, data: &[u8]) -> Vec<u8> {
1558    let mut cipher = Rc4::new(key);
1559    cipher.process(data)
1560}
1561
1562// Use the md5 crate for actual MD5 hashing (required for PDF encryption)
1563
1564/// SHA-256 implementation using RustCrypto (production-grade)
1565///
1566/// Returns a 32-byte hash of the input data according to FIPS 180-4.
1567/// Used for R5 password validation and key derivation.
1568fn sha256(data: &[u8]) -> Vec<u8> {
1569    Sha256::digest(data).to_vec()
1570}
1571
1572/// SHA-384 implementation using RustCrypto (production-grade)
1573///
1574/// Returns a 48-byte hash of the input data according to FIPS 180-4.
1575/// Used for R6 Algorithm 2.B hash rotation.
1576fn sha384(data: &[u8]) -> Vec<u8> {
1577    Sha384::digest(data).to_vec()
1578}
1579
1580/// SHA-512 implementation using RustCrypto (production-grade)
1581///
1582/// Returns a 64-byte hash of the input data according to FIPS 180-4.
1583/// Used for R6 password validation and key derivation.
1584fn sha512(data: &[u8]) -> Vec<u8> {
1585    Sha512::digest(data).to_vec()
1586}
1587
1588// ============================================================================
1589// Algorithm 2.B - R6 Key Derivation (ISO 32000-2:2020 §7.6.4.3.4)
1590// ============================================================================
1591
1592/// Minimum number of rounds for Algorithm 2.B
1593const ALGORITHM_2B_MIN_ROUNDS: usize = 64;
1594
1595/// Maximum rounds (DoS protection, not in spec but common implementation)
1596const ALGORITHM_2B_MAX_ROUNDS: usize = 2048;
1597
1598/// Maximum password length (ISO 32000-2 §7.6.3.3.2 recommends 127 bytes)
1599/// This prevents DoS via massive allocation: 1MB password × 64 repetitions = 64MB/round
1600const ALGORITHM_2B_MAX_PASSWORD_LEN: usize = 127;
1601
1602/// Number of bytes used for hash function selection (spec: first 16 bytes as BigInteger mod 3)
1603const HASH_SELECTOR_BYTES: usize = 16;
1604
1605/// Compute R6 password hash using Algorithm 2.B (ISO 32000-2:2020 §7.6.4.3.4)
1606///
1607/// This is the correct R6 key derivation algorithm used by qpdf, Adobe Acrobat,
1608/// and other compliant PDF processors. It uses AES-128-CBC encryption within
1609/// the iteration loop and dynamically selects SHA-256/384/512 based on output.
1610///
1611/// # Algorithm Overview
1612/// 1. Initial hash: K = SHA-256(password + salt + U\[0..48\])
1613/// 2. Loop (minimum 64 rounds):
1614///    a. Construct k1 = (password + K + U\[0..48\]), repeat 64 times
1615///    b. E = AES-128-CBC-encrypt(k1, key=K\[0..16\], iv=K\[16..32\])
1616///    c. Select hash: SHA-256/384/512 based on sum(E\[0..16\]) mod 3
1617///    d. K = hash(E)
1618///    e. Check termination: round >= 64 AND E\[last\] <= (round - 32)
1619/// 3. Return K\[0..32\]
1620///
1621/// # Parameters
1622/// - `password`: User password bytes (UTF-8 encoded)
1623/// - `salt`: 8-byte salt (validation_salt or key_salt from U entry)
1624/// - `u_entry`: Full 48-byte U entry (or empty slice for initial computation)
1625///
1626/// # Returns
1627/// 32-byte derived key
1628///
1629/// # Security Notes
1630/// - Maximum 2048 rounds to prevent DoS attacks
1631/// - Variable iteration count makes brute-force harder
1632/// - AES encryption + hash rotation provides strong KDF
1633///
1634/// # References
1635/// - ISO 32000-2:2020 §7.6.4.3.4 "Algorithm 2.B: Computing a hash (R6)"
1636pub fn compute_hash_r6_algorithm_2b(
1637    password: &[u8],
1638    salt: &[u8],
1639    u_entry: &[u8],
1640) -> Result<Vec<u8>> {
1641    // Security: Validate password length to prevent DoS via massive allocations
1642    if password.len() > ALGORITHM_2B_MAX_PASSWORD_LEN {
1643        return Err(crate::error::PdfError::EncryptionError(format!(
1644            "Password too long ({} bytes, max {})",
1645            password.len(),
1646            ALGORITHM_2B_MAX_PASSWORD_LEN
1647        )));
1648    }
1649
1650    // Step 1: Initial hash K = SHA-256(password + salt + U[0..48])
1651    let mut input = Vec::with_capacity(password.len() + salt.len() + u_entry.len().min(48));
1652    input.extend_from_slice(password);
1653    input.extend_from_slice(salt);
1654    if !u_entry.is_empty() {
1655        input.extend_from_slice(&u_entry[..u_entry.len().min(48)]);
1656    }
1657
1658    let mut k = sha256(&input);
1659
1660    // Step 2: Iteration loop
1661    let mut round: usize = 0;
1662    loop {
1663        // 2a. Construct input sequence: password + K + U[0..48], repeated
1664        // The spec says to create a sequence that will be encrypted
1665        let mut k1_unit = Vec::new();
1666        k1_unit.extend_from_slice(password);
1667        k1_unit.extend_from_slice(&k);
1668        if !u_entry.is_empty() {
1669            k1_unit.extend_from_slice(&u_entry[..u_entry.len().min(48)]);
1670        }
1671
1672        // Repeat 64 times to create input for AES
1673        let mut k1 = Vec::with_capacity(k1_unit.len() * 64);
1674        for _ in 0..64 {
1675            k1.extend_from_slice(&k1_unit);
1676        }
1677
1678        // Zero-pad to AES block size (16 bytes) per ISO 32000-2 §7.6.4.3.4
1679        // NOTE: This is zero-padding, NOT PKCS#7 - the spec requires raw AES without padding removal
1680        while k1.len() % 16 != 0 {
1681            k1.push(0);
1682        }
1683
1684        // 2b. AES-128-CBC encryption
1685        // Key: first 16 bytes of K, IV: next 16 bytes of K
1686        if k.len() < 32 {
1687            // Extend K if needed (shouldn't happen with proper hashes)
1688            while k.len() < 32 {
1689                k.push(0);
1690            }
1691        }
1692
1693        let aes_key = AesKey::new_128(k[..16].to_vec()).map_err(|e| {
1694            crate::error::PdfError::EncryptionError(format!(
1695                "Algorithm 2.B: Failed to create AES key: {}",
1696                e
1697            ))
1698        })?;
1699        let aes = Aes::new(aes_key);
1700        let iv = &k[16..32];
1701
1702        let e = aes.encrypt_cbc_raw(&k1, iv).map_err(|e| {
1703            crate::error::PdfError::EncryptionError(format!(
1704                "Algorithm 2.B: AES encryption failed: {}",
1705                e
1706            ))
1707        })?;
1708
1709        // 2c. Select hash function based on first 16 bytes of E as BigInteger mod 3
1710        // Per iText/Adobe implementation: interpret E[0..HASH_SELECTOR_BYTES] as big-endian integer
1711        // Mathematical equivalence: sum(bytes) mod 3 == BigInteger(bytes) mod 3
1712        // because 256 mod 3 = 1, therefore 256^k mod 3 = 1 for all k
1713        let hash_selector = {
1714            let sum: u64 = e[..HASH_SELECTOR_BYTES.min(e.len())]
1715                .iter()
1716                .map(|&b| b as u64)
1717                .sum();
1718            (sum % 3) as u8
1719        };
1720
1721        k = match hash_selector {
1722            0 => sha256(&e),
1723            1 => sha384(&e),
1724            2 => sha512(&e),
1725            _ => unreachable!("Modulo 3 can only be 0, 1, or 2"),
1726        };
1727
1728        // 2d. Check termination condition
1729        // Terminate when: round >= 64 AND E[last] <= (round - 32)
1730        let last_byte = *e.last().unwrap_or(&0);
1731        round += 1;
1732
1733        if round >= ALGORITHM_2B_MIN_ROUNDS {
1734            // The termination condition from ISO spec:
1735            // "the last byte value of the last iteration is less than or equal to
1736            // the number of iterations minus 32"
1737            if (last_byte as usize) <= round.saturating_sub(32) {
1738                break;
1739            }
1740        }
1741
1742        // Safety: Prevent infinite loop (DoS protection)
1743        if round >= ALGORITHM_2B_MAX_ROUNDS {
1744            break;
1745        }
1746    }
1747
1748    // Step 3: Return first 32 bytes of final K
1749    // K might be > 32 bytes if last hash was SHA-384 or SHA-512
1750    Ok(k[..32.min(k.len())].to_vec())
1751}
1752
1753/// R5 salt length in bytes (PDF spec §7.6.4.3.4)
1754const R5_SALT_LENGTH: usize = 8;
1755
1756/// R5 SHA-256 iteration count (ISO 32000-2:2020 Algorithm 8/11)
1757/// NOTE: R5 does NOT use iterations - hash is simply SHA-256(password + salt)
1758/// The 64 iterations are only for R6 which uses Algorithm 2.B
1759const R5_HASH_ITERATIONS: usize = 0;
1760
1761/// R6 salt length in bytes (PDF spec ISO 32000-2)
1762const R6_SALT_LENGTH: usize = 8;
1763
1764// ============================================================================
1765// R5/R6 U Entry Structure Constants (48 bytes total)
1766// ============================================================================
1767
1768/// Length of the hash portion in U entry (SHA-256/SHA-512 truncated to 32 bytes)
1769const U_HASH_LENGTH: usize = 32;
1770
1771/// Start offset of validation salt in U entry
1772const U_VALIDATION_SALT_START: usize = 32;
1773
1774/// End offset of validation salt in U entry
1775const U_VALIDATION_SALT_END: usize = 40;
1776
1777/// Start offset of key salt in U entry
1778const U_KEY_SALT_START: usize = 40;
1779
1780/// End offset of key salt in U entry
1781const U_KEY_SALT_END: usize = 48;
1782
1783/// Total length of U entry for R5/R6
1784const U_ENTRY_LENGTH: usize = 48;
1785
1786/// Length of UE entry (encrypted encryption key)
1787const UE_ENTRY_LENGTH: usize = 32;
1788
1789// ============================================================================
1790// R6 Perms Entry Structure Constants (16 bytes total)
1791// ============================================================================
1792
1793/// Length of Perms entry
1794const PERMS_ENTRY_LENGTH: usize = 16;
1795
1796/// Start offset of permissions value in decrypted Perms (little-endian u32)
1797const PERMS_P_START: usize = 0;
1798
1799/// End offset of permissions value in decrypted Perms
1800const PERMS_P_END: usize = 4;
1801
1802/// Start offset of fixed marker (0xFFFFFFFF) in decrypted Perms
1803const PERMS_MARKER_START: usize = 4;
1804
1805/// End offset of fixed marker in decrypted Perms
1806const PERMS_MARKER_END: usize = 8;
1807
1808/// Start offset of "adb" literal in decrypted Perms
1809const PERMS_LITERAL_START: usize = 8;
1810
1811/// End offset of "adb" literal in decrypted Perms
1812const PERMS_LITERAL_END: usize = 11;
1813
1814/// Offset of EncryptMetadata flag byte ('T' or 'F') in decrypted Perms
1815const PERMS_ENCRYPT_META_BYTE: usize = 11;
1816
1817/// Fixed marker value in Perms entry
1818const PERMS_MARKER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
1819
1820/// Literal verification string in Perms entry
1821const PERMS_LITERAL: &[u8; 3] = b"adb";
1822
1823/// Generate cryptographically secure random salt using OS CSPRNG
1824///
1825/// Uses `rand::rng()` which provides a thread-local CSPRNG (ChaCha12) seeded
1826/// from the OS random number generator. This is suitable for PDF encryption salts.
1827///
1828/// # Security
1829/// - Uses ChaCha12 PRNG seeded from OS entropy (rand 0.9 implementation)
1830/// - Provides cryptographic-quality randomness for salt generation
1831/// - Each call produces independent random bytes
1832fn generate_salt(len: usize) -> Vec<u8> {
1833    let mut salt = vec![0u8; len];
1834    rand::rng().fill_bytes(&mut salt);
1835    salt
1836}
1837
1838#[cfg(test)]
1839mod tests {
1840    use super::*;
1841
1842    #[test]
1843    fn test_pad_password() {
1844        let padded = StandardSecurityHandler::pad_password("test");
1845        assert_eq!(padded.len(), 32);
1846        assert_eq!(&padded[..4], b"test");
1847        assert_eq!(&padded[4..8], &PADDING[..4]);
1848    }
1849
1850    #[test]
1851    fn test_pad_password_long() {
1852        let long_password = "a".repeat(40);
1853        let padded = StandardSecurityHandler::pad_password(&long_password);
1854        assert_eq!(padded.len(), 32);
1855        assert_eq!(&padded[..32], &long_password.as_bytes()[..32]);
1856    }
1857
1858    #[test]
1859    fn test_rc4_40bit_handler() {
1860        let handler = StandardSecurityHandler::rc4_40bit();
1861        assert_eq!(handler.revision, SecurityHandlerRevision::R2);
1862        assert_eq!(handler.key_length, 5);
1863    }
1864
1865    #[test]
1866    fn test_rc4_128bit_handler() {
1867        let handler = StandardSecurityHandler::rc4_128bit();
1868        assert_eq!(handler.revision, SecurityHandlerRevision::R3);
1869        assert_eq!(handler.key_length, 16);
1870    }
1871
1872    #[test]
1873    fn test_owner_hash_computation() {
1874        let handler = StandardSecurityHandler::rc4_40bit();
1875        let owner_pwd = OwnerPassword("owner".to_string());
1876        let user_pwd = UserPassword("user".to_string());
1877
1878        let hash = handler.compute_owner_hash(&owner_pwd, &user_pwd);
1879        assert_eq!(hash.len(), 32);
1880    }
1881
1882    #[test]
1883    fn test_encryption_key_computation() {
1884        let handler = StandardSecurityHandler::rc4_40bit();
1885        let user_pwd = UserPassword("user".to_string());
1886        let owner_hash = vec![0u8; 32];
1887        let permissions = Permissions::new();
1888
1889        let key = handler
1890            .compute_encryption_key(&user_pwd, &owner_hash, permissions, None)
1891            .unwrap();
1892
1893        assert_eq!(key.len(), 5);
1894    }
1895
1896    #[test]
1897    fn test_aes_256_r5_handler() {
1898        let handler = StandardSecurityHandler::aes_256_r5();
1899        assert_eq!(handler.revision, SecurityHandlerRevision::R5);
1900        assert_eq!(handler.key_length, 32);
1901    }
1902
1903    #[test]
1904    fn test_aes_256_r6_handler() {
1905        let handler = StandardSecurityHandler::aes_256_r6();
1906        assert_eq!(handler.revision, SecurityHandlerRevision::R6);
1907        assert_eq!(handler.key_length, 32);
1908    }
1909
1910    #[test]
1911    fn test_aes_encryption_key_computation() {
1912        let handler = StandardSecurityHandler::aes_256_r5();
1913        let user_pwd = UserPassword("testuser".to_string());
1914        let owner_hash = vec![0u8; 32];
1915        let permissions = Permissions::new();
1916
1917        let key = handler
1918            .compute_aes_encryption_key(&user_pwd, &owner_hash, permissions, None)
1919            .unwrap();
1920
1921        assert_eq!(key.len(), 32);
1922    }
1923
1924    #[test]
1925    fn test_aes_encrypt_decrypt() {
1926        let handler = StandardSecurityHandler::aes_256_r5();
1927        let key = EncryptionKey::new(vec![0u8; 32]);
1928        let obj_id = ObjectId::new(1, 0);
1929        let data = b"Hello AES encryption!";
1930
1931        let encrypted = handler.encrypt_aes(data, &key, &obj_id).unwrap();
1932        assert_ne!(encrypted.as_slice(), data);
1933        assert!(encrypted.len() > data.len()); // Should include IV
1934
1935        // Note: This simplified AES implementation is for demonstration only
1936        let _decrypted = handler.decrypt_aes(&encrypted, &key, &obj_id);
1937        // For now, just test that the operations complete without panicking
1938    }
1939
1940    #[test]
1941    fn test_aes_with_rc4_handler_fails() {
1942        let handler = StandardSecurityHandler::rc4_128bit();
1943        let key = EncryptionKey::new(vec![0u8; 16]);
1944        let obj_id = ObjectId::new(1, 0);
1945        let data = b"test data";
1946
1947        // Should fail because handler is not Rev 5+
1948        assert!(handler.encrypt_aes(data, &key, &obj_id).is_err());
1949        assert!(handler.decrypt_aes(data, &key, &obj_id).is_err());
1950    }
1951
1952    #[test]
1953    fn test_aes_decrypt_invalid_data() {
1954        let handler = StandardSecurityHandler::aes_256_r5();
1955        let key = EncryptionKey::new(vec![0u8; 32]);
1956        let obj_id = ObjectId::new(1, 0);
1957
1958        // Data too short (no IV)
1959        let short_data = vec![0u8; 10];
1960        assert!(handler.decrypt_aes(&short_data, &key, &obj_id).is_err());
1961    }
1962
1963    #[test]
1964    fn test_sha256_deterministic() {
1965        let data1 = b"test data";
1966        let data2 = b"test data";
1967        let data3 = b"different data";
1968
1969        let hash1 = sha256(data1);
1970        let hash2 = sha256(data2);
1971        let hash3 = sha256(data3);
1972
1973        assert_eq!(hash1.len(), 32);
1974        assert_eq!(hash2.len(), 32);
1975        assert_eq!(hash3.len(), 32);
1976
1977        assert_eq!(hash1, hash2); // Same input should give same output
1978        assert_ne!(hash1, hash3); // Different input should give different output
1979    }
1980
1981    #[test]
1982    fn test_security_handler_revision_ordering() {
1983        assert!(SecurityHandlerRevision::R2 < SecurityHandlerRevision::R3);
1984        assert!(SecurityHandlerRevision::R3 < SecurityHandlerRevision::R4);
1985        assert!(SecurityHandlerRevision::R4 < SecurityHandlerRevision::R5);
1986        assert!(SecurityHandlerRevision::R5 < SecurityHandlerRevision::R6);
1987    }
1988
1989    #[test]
1990    fn test_aes_password_validation() {
1991        let handler = StandardSecurityHandler::aes_256_r5();
1992        let password = UserPassword("testpassword".to_string());
1993        let user_hash = vec![0u8; 32]; // Simplified hash
1994        let permissions = Permissions::new();
1995
1996        // This is a basic test - in practice, the validation would be more complex
1997        let result = handler.validate_aes_user_password(&password, &user_hash, permissions, None);
1998        assert!(result.is_ok());
1999    }
2000
2001    // ===== Additional Comprehensive Tests =====
2002
2003    #[test]
2004    fn test_user_password_debug() {
2005        let pwd = UserPassword("debug_test".to_string());
2006        let debug_str = format!("{pwd:?}");
2007        assert!(debug_str.contains("UserPassword"));
2008        assert!(debug_str.contains("debug_test"));
2009    }
2010
2011    #[test]
2012    fn test_owner_password_debug() {
2013        let pwd = OwnerPassword("owner_debug".to_string());
2014        let debug_str = format!("{pwd:?}");
2015        assert!(debug_str.contains("OwnerPassword"));
2016        assert!(debug_str.contains("owner_debug"));
2017    }
2018
2019    #[test]
2020    fn test_encryption_key_debug() {
2021        let key = EncryptionKey::new(vec![0x01, 0x02, 0x03]);
2022        let debug_str = format!("{key:?}");
2023        assert!(debug_str.contains("EncryptionKey"));
2024    }
2025
2026    #[test]
2027    fn test_security_handler_revision_equality() {
2028        assert_eq!(SecurityHandlerRevision::R2, SecurityHandlerRevision::R2);
2029        assert_ne!(SecurityHandlerRevision::R2, SecurityHandlerRevision::R3);
2030    }
2031
2032    #[test]
2033    fn test_security_handler_revision_values() {
2034        assert_eq!(SecurityHandlerRevision::R2 as u8, 2);
2035        assert_eq!(SecurityHandlerRevision::R3 as u8, 3);
2036        assert_eq!(SecurityHandlerRevision::R4 as u8, 4);
2037        assert_eq!(SecurityHandlerRevision::R5 as u8, 5);
2038        assert_eq!(SecurityHandlerRevision::R6 as u8, 6);
2039    }
2040
2041    #[test]
2042    fn test_pad_password_various_lengths() {
2043        for len in 0..=40 {
2044            let password = "x".repeat(len);
2045            let padded = StandardSecurityHandler::pad_password(&password);
2046            assert_eq!(padded.len(), 32);
2047
2048            if len <= 32 {
2049                assert_eq!(&padded[..len], password.as_bytes());
2050            } else {
2051                assert_eq!(&padded[..], &password.as_bytes()[..32]);
2052            }
2053        }
2054    }
2055
2056    #[test]
2057    fn test_pad_password_unicode() {
2058        let padded = StandardSecurityHandler::pad_password("café");
2059        assert_eq!(padded.len(), 32);
2060        // UTF-8 encoding of "café" is 5 bytes
2061        assert_eq!(&padded[..5], "café".as_bytes());
2062    }
2063
2064    #[test]
2065    fn test_compute_owner_hash_different_users() {
2066        let handler = StandardSecurityHandler::rc4_128bit();
2067        let owner = OwnerPassword("owner".to_string());
2068        let user1 = UserPassword("user1".to_string());
2069        let user2 = UserPassword("user2".to_string());
2070
2071        let hash1 = handler.compute_owner_hash(&owner, &user1);
2072        let hash2 = handler.compute_owner_hash(&owner, &user2);
2073
2074        assert_ne!(hash1, hash2); // Different user passwords should produce different hashes
2075    }
2076
2077    #[test]
2078    fn test_compute_user_hash_r4() {
2079        let handler = StandardSecurityHandler {
2080            revision: SecurityHandlerRevision::R4,
2081            key_length: 16,
2082        };
2083        let user = UserPassword("r4test".to_string());
2084        let owner_hash = vec![0xAA; 32];
2085        let permissions = Permissions::new();
2086
2087        let hash = handler
2088            .compute_user_hash(&user, &owner_hash, permissions, None)
2089            .unwrap();
2090        assert_eq!(hash.len(), 32);
2091    }
2092
2093    #[test]
2094    fn test_compute_user_hash_r6() {
2095        let handler = StandardSecurityHandler::aes_256_r6();
2096        let user = UserPassword("r6test".to_string());
2097        let owner_hash = vec![0xBB; 32];
2098        let permissions = Permissions::all();
2099
2100        let hash = handler
2101            .compute_user_hash(&user, &owner_hash, permissions, None)
2102            .unwrap();
2103        assert_eq!(hash.len(), 32);
2104    }
2105
2106    #[test]
2107    fn test_encryption_key_with_file_id_affects_result() {
2108        let handler = StandardSecurityHandler::rc4_128bit();
2109        let user = UserPassword("test".to_string());
2110        let owner_hash = vec![0xFF; 32];
2111        let permissions = Permissions::new();
2112        let file_id = b"unique_file_id_12345";
2113
2114        let key_with_id = handler
2115            .compute_encryption_key(&user, &owner_hash, permissions, Some(file_id))
2116            .unwrap();
2117        let key_without_id = handler
2118            .compute_encryption_key(&user, &owner_hash, permissions, None)
2119            .unwrap();
2120
2121        assert_ne!(key_with_id.key, key_without_id.key);
2122    }
2123
2124    #[test]
2125    fn test_encrypt_string_empty() {
2126        let handler = StandardSecurityHandler::rc4_40bit();
2127        let key = EncryptionKey::new(vec![0x01, 0x02, 0x03, 0x04, 0x05]);
2128        let obj_id = ObjectId::new(1, 0);
2129
2130        let encrypted = handler.encrypt_string(b"", &key, &obj_id);
2131        assert_eq!(encrypted.len(), 0);
2132    }
2133
2134    #[test]
2135    fn test_encrypt_decrypt_large_data() {
2136        let handler = StandardSecurityHandler::rc4_128bit();
2137        let key = EncryptionKey::new(vec![0xAA; 16]);
2138        let obj_id = ObjectId::new(42, 0);
2139        let large_data = vec![0x55; 10000]; // 10KB
2140
2141        let encrypted = handler.encrypt_string(&large_data, &key, &obj_id);
2142        assert_eq!(encrypted.len(), large_data.len());
2143        assert_ne!(encrypted, large_data);
2144
2145        let decrypted = handler.decrypt_string(&encrypted, &key, &obj_id);
2146        assert_eq!(decrypted, large_data);
2147    }
2148
2149    #[test]
2150    fn test_stream_encryption_different_from_string() {
2151        // For current implementation they're the same, but test separately
2152        let handler = StandardSecurityHandler::rc4_128bit();
2153        let key = EncryptionKey::new(vec![0x11; 16]);
2154        let obj_id = ObjectId::new(5, 1);
2155        let data = b"Stream content test";
2156
2157        let encrypted_string = handler.encrypt_string(data, &key, &obj_id);
2158        let encrypted_stream = handler.encrypt_stream(data, &key, &obj_id);
2159
2160        assert_eq!(encrypted_string, encrypted_stream); // Currently same implementation
2161    }
2162
2163    #[test]
2164    fn test_aes_encryption_with_different_object_ids() {
2165        let handler = StandardSecurityHandler::aes_256_r5();
2166        let key = EncryptionKey::new(vec![0x77; 32]);
2167        let obj_id1 = ObjectId::new(10, 0);
2168        let obj_id2 = ObjectId::new(11, 0);
2169        let data = b"AES test data";
2170
2171        let encrypted1 = handler.encrypt_aes(data, &key, &obj_id1).unwrap();
2172        let encrypted2 = handler.encrypt_aes(data, &key, &obj_id2).unwrap();
2173
2174        // Different object IDs should produce different ciphertexts
2175        assert_ne!(encrypted1, encrypted2);
2176    }
2177
2178    #[test]
2179    fn test_aes_decrypt_invalid_iv_length() {
2180        let handler = StandardSecurityHandler::aes_256_r5();
2181        let key = EncryptionKey::new(vec![0x88; 32]);
2182        let obj_id = ObjectId::new(1, 0);
2183
2184        // Data too short to contain IV
2185        let short_data = vec![0u8; 10];
2186        assert!(handler.decrypt_aes(&short_data, &key, &obj_id).is_err());
2187
2188        // Exactly 16 bytes (only IV, no encrypted data)
2189        let iv_only = vec![0u8; 16];
2190        let result = handler.decrypt_aes(&iv_only, &key, &obj_id);
2191        // This might succeed with empty decrypted data or fail depending on implementation
2192        if let Ok(decrypted) = result {
2193            assert_eq!(decrypted.len(), 0);
2194        }
2195    }
2196
2197    #[test]
2198    fn test_aes_validate_password_wrong_hash_length() {
2199        let handler = StandardSecurityHandler::aes_256_r5();
2200        let password = UserPassword("test".to_string());
2201        let short_hash = vec![0u8; 16]; // Too short
2202        let permissions = Permissions::new();
2203
2204        let result = handler
2205            .validate_aes_user_password(&password, &short_hash, permissions, None)
2206            .unwrap();
2207        assert!(!result); // Should return false for invalid hash
2208    }
2209
2210    #[test]
2211    fn test_permissions_affect_encryption_key() {
2212        let handler = StandardSecurityHandler::rc4_128bit();
2213        let user = UserPassword("same_user".to_string());
2214        let owner_hash = vec![0xCC; 32];
2215
2216        let perms1 = Permissions::new();
2217        let perms2 = Permissions::all();
2218
2219        let key1 = handler
2220            .compute_encryption_key(&user, &owner_hash, perms1, None)
2221            .unwrap();
2222        let key2 = handler
2223            .compute_encryption_key(&user, &owner_hash, perms2, None)
2224            .unwrap();
2225
2226        assert_ne!(key1.key, key2.key); // Different permissions should affect the key
2227    }
2228
2229    #[test]
2230    fn test_different_handlers_produce_different_keys() {
2231        let user = UserPassword("test".to_string());
2232        let owner_hash = vec![0xDD; 32];
2233        let permissions = Permissions::new();
2234
2235        let handler_r2 = StandardSecurityHandler::rc4_40bit();
2236        let handler_r3 = StandardSecurityHandler::rc4_128bit();
2237
2238        let key_r2 = handler_r2
2239            .compute_encryption_key(&user, &owner_hash, permissions, None)
2240            .unwrap();
2241        let key_r3 = handler_r3
2242            .compute_encryption_key(&user, &owner_hash, permissions, None)
2243            .unwrap();
2244
2245        assert_ne!(key_r2.len(), key_r3.len()); // Different key lengths
2246        assert_eq!(key_r2.len(), 5);
2247        assert_eq!(key_r3.len(), 16);
2248    }
2249
2250    #[test]
2251    fn test_full_workflow_aes_r6() {
2252        let handler = StandardSecurityHandler::aes_256_r6();
2253        let user_pwd = UserPassword("user_r6".to_string());
2254        let permissions = Permissions::new();
2255        let file_id = b"test_file_r6";
2256
2257        // For AES R5/R6, owner hash computation is different - use a dummy hash
2258        let owner_hash = vec![0x42; 32]; // AES uses 32-byte hashes
2259
2260        // Compute user hash
2261        let user_hash = handler
2262            .compute_user_hash(&user_pwd, &owner_hash, permissions, Some(file_id))
2263            .unwrap();
2264        assert_eq!(user_hash.len(), 32);
2265
2266        // Compute encryption key
2267        let key = handler
2268            .compute_aes_encryption_key(&user_pwd, &owner_hash, permissions, Some(file_id))
2269            .unwrap();
2270        assert_eq!(key.len(), 32);
2271
2272        // Test string encryption (uses AES for R6)
2273        let obj_id = ObjectId::new(100, 5);
2274        let content = b"R6 AES encryption test";
2275        let encrypted = handler.encrypt_string(content, &key, &obj_id);
2276
2277        // With AES, encrypted should be empty on error or have data
2278        if !encrypted.is_empty() {
2279            assert_ne!(encrypted.as_slice(), content);
2280        }
2281    }
2282
2283    #[test]
2284    fn test_md5_compute_consistency() {
2285        let data = b"consistent data for md5";
2286        let hash1 = md5::compute(data);
2287        let hash2 = md5::compute(data);
2288
2289        assert_eq!(hash1, hash2);
2290        assert_eq!(hash1.len(), 16);
2291    }
2292
2293    #[test]
2294    fn test_sha256_consistency() {
2295        let data = b"consistent data for sha256";
2296        let hash1 = sha256(data);
2297        let hash2 = sha256(data);
2298
2299        assert_eq!(hash1, hash2);
2300        assert_eq!(hash1.len(), 32);
2301    }
2302
2303    #[test]
2304    fn test_rc4_encrypt_helper() {
2305        let key = Rc4Key::from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05]);
2306        let data = b"test rc4 helper";
2307
2308        let encrypted = rc4_encrypt(&key, data);
2309        assert_ne!(encrypted.as_slice(), data);
2310
2311        // RC4 is symmetric
2312        let decrypted = rc4_encrypt(&key, &encrypted);
2313        assert_eq!(decrypted.as_slice(), data);
2314    }
2315
2316    #[test]
2317    fn test_edge_case_max_object_generation() {
2318        let handler = StandardSecurityHandler::rc4_128bit();
2319        let key = EncryptionKey::new(vec![0xEE; 16]);
2320        let obj_id = ObjectId::new(0xFFFFFF, 0xFFFF); // Max values
2321        let data = b"edge case";
2322
2323        let encrypted = handler.encrypt_string(data, &key, &obj_id);
2324        let decrypted = handler.decrypt_string(&encrypted, &key, &obj_id);
2325        assert_eq!(decrypted.as_slice(), data);
2326    }
2327
2328    // ===== SHA-256/512 NIST Vector Tests (Phase 1.3 - RustCrypto Integration) =====
2329
2330    #[test]
2331    fn test_sha256_nist_empty_string() {
2332        // NIST FIPS 180-4 test vector: SHA-256("")
2333        let hash = sha256(b"");
2334        let expected: [u8; 32] = [
2335            0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
2336            0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
2337            0x78, 0x52, 0xb8, 0x55,
2338        ];
2339        assert_eq!(
2340            hash.as_slice(),
2341            expected.as_slice(),
2342            "SHA-256('') must match NIST test vector"
2343        );
2344    }
2345
2346    #[test]
2347    fn test_sha256_nist_abc() {
2348        // NIST FIPS 180-4 test vector: SHA-256("abc")
2349        let hash = sha256(b"abc");
2350        let expected: [u8; 32] = [
2351            0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
2352            0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
2353            0xf2, 0x00, 0x15, 0xad,
2354        ];
2355        assert_eq!(
2356            hash.as_slice(),
2357            expected.as_slice(),
2358            "SHA-256('abc') must match NIST test vector"
2359        );
2360    }
2361
2362    #[test]
2363    fn test_sha512_nist_abc() {
2364        // NIST FIPS 180-4 test vector: SHA-512("abc")
2365        let hash = sha512(b"abc");
2366        let expected: [u8; 64] = [
2367            0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20,
2368            0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6,
2369            0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba,
2370            0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
2371            0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f,
2372        ];
2373        assert_eq!(
2374            hash.as_slice(),
2375            expected.as_slice(),
2376            "SHA-512('abc') must match NIST test vector"
2377        );
2378    }
2379
2380    #[test]
2381    fn test_sha512_length() {
2382        let hash = sha512(b"test data");
2383        assert_eq!(hash.len(), 64, "SHA-512 must produce 64 bytes");
2384    }
2385
2386    #[test]
2387    fn test_sha512_deterministic() {
2388        let data1 = b"sha512 test data";
2389        let data2 = b"sha512 test data";
2390        let data3 = b"different data";
2391
2392        let hash1 = sha512(data1);
2393        let hash2 = sha512(data2);
2394        let hash3 = sha512(data3);
2395
2396        assert_eq!(hash1, hash2, "Same input must produce same SHA-512 hash");
2397        assert_ne!(hash1, hash3, "Different input must produce different hash");
2398    }
2399
2400    // ===== Phase 2.1: R5 User Password Tests (Algorithm 8 & 11) =====
2401
2402    #[test]
2403    fn test_r5_user_hash_computation() {
2404        let handler = StandardSecurityHandler::aes_256_r5();
2405        let password = UserPassword("test_password".to_string());
2406
2407        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2408
2409        // U entry must be exactly 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
2410        assert_eq!(u_entry.len(), 48, "R5 U entry must be 48 bytes");
2411    }
2412
2413    #[test]
2414    fn test_r5_user_password_validation_correct() {
2415        let handler = StandardSecurityHandler::aes_256_r5();
2416        let password = UserPassword("correct_password".to_string());
2417
2418        // Compute U entry with the password
2419        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2420
2421        // Validate with same password should succeed
2422        let is_valid = handler
2423            .validate_r5_user_password(&password, &u_entry)
2424            .unwrap();
2425        assert!(is_valid, "Correct password must validate");
2426    }
2427
2428    #[test]
2429    fn test_r5_user_password_validation_incorrect() {
2430        let handler = StandardSecurityHandler::aes_256_r5();
2431        let correct_password = UserPassword("correct_password".to_string());
2432        let wrong_password = UserPassword("wrong_password".to_string());
2433
2434        // Compute U entry with correct password
2435        let u_entry = handler.compute_r5_user_hash(&correct_password).unwrap();
2436
2437        // Validate with wrong password should fail
2438        let is_valid = handler
2439            .validate_r5_user_password(&wrong_password, &u_entry)
2440            .unwrap();
2441        assert!(!is_valid, "Wrong password must not validate");
2442    }
2443
2444    #[test]
2445    fn test_r5_user_hash_random_salts() {
2446        let handler = StandardSecurityHandler::aes_256_r5();
2447        let password = UserPassword("same_password".to_string());
2448
2449        // Compute U entry twice - salts should be different
2450        let u_entry1 = handler.compute_r5_user_hash(&password).unwrap();
2451        let u_entry2 = handler.compute_r5_user_hash(&password).unwrap();
2452
2453        // Hash portion should be different (due to random salts)
2454        assert_ne!(
2455            &u_entry1[..32],
2456            &u_entry2[..32],
2457            "Different random salts should produce different hashes"
2458        );
2459
2460        // Validation salt should be different
2461        assert_ne!(
2462            &u_entry1[32..40],
2463            &u_entry2[32..40],
2464            "Validation salts must be random"
2465        );
2466
2467        // But both should validate with the same password
2468        assert!(handler
2469            .validate_r5_user_password(&password, &u_entry1)
2470            .unwrap());
2471        assert!(handler
2472            .validate_r5_user_password(&password, &u_entry2)
2473            .unwrap());
2474    }
2475
2476    #[test]
2477    fn test_r5_user_hash_invalid_entry_length() {
2478        let handler = StandardSecurityHandler::aes_256_r5();
2479        let password = UserPassword("test".to_string());
2480
2481        // Try to validate with wrong length U entry
2482        let short_entry = vec![0u8; 32]; // Too short
2483        let result = handler.validate_r5_user_password(&password, &short_entry);
2484        assert!(result.is_err(), "Short U entry must fail");
2485
2486        let long_entry = vec![0u8; 64]; // Too long
2487        let result = handler.validate_r5_user_password(&password, &long_entry);
2488        assert!(result.is_err(), "Long U entry must fail");
2489    }
2490
2491    #[test]
2492    fn test_r5_empty_password() {
2493        let handler = StandardSecurityHandler::aes_256_r5();
2494        let empty_password = UserPassword("".to_string());
2495
2496        // Empty password should work (common for user-only encryption)
2497        let u_entry = handler.compute_r5_user_hash(&empty_password).unwrap();
2498        assert_eq!(u_entry.len(), 48);
2499
2500        let is_valid = handler
2501            .validate_r5_user_password(&empty_password, &u_entry)
2502            .unwrap();
2503        assert!(is_valid, "Empty password must validate correctly");
2504
2505        // Non-empty password should fail
2506        let non_empty = UserPassword("not_empty".to_string());
2507        let is_valid = handler
2508            .validate_r5_user_password(&non_empty, &u_entry)
2509            .unwrap();
2510        assert!(!is_valid, "Non-empty password must not validate");
2511    }
2512
2513    // ===== Phase 2.2: R5 UE Entry Tests (Encryption Key Storage) =====
2514
2515    #[test]
2516    fn test_r5_ue_entry_computation() {
2517        let handler = StandardSecurityHandler::aes_256_r5();
2518        let password = UserPassword("ue_test_password".to_string());
2519        let encryption_key = EncryptionKey::new(vec![0xAB; 32]);
2520
2521        // Compute U entry first
2522        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2523
2524        // Compute UE entry
2525        let ue_entry = handler
2526            .compute_r5_ue_entry(&password, &u_entry, &encryption_key)
2527            .unwrap();
2528
2529        // UE entry must be exactly 32 bytes
2530        assert_eq!(ue_entry.len(), 32, "R5 UE entry must be 32 bytes");
2531
2532        // UE should be different from the original key (it's encrypted)
2533        assert_ne!(
2534            ue_entry.as_slice(),
2535            encryption_key.as_bytes(),
2536            "UE must be encrypted"
2537        );
2538    }
2539
2540    #[test]
2541    fn test_r5_encryption_key_recovery() {
2542        let handler = StandardSecurityHandler::aes_256_r5();
2543        let password = UserPassword("recovery_test".to_string());
2544        let original_key = EncryptionKey::new(vec![0x42; 32]);
2545
2546        // Compute U entry
2547        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2548
2549        // Compute UE entry
2550        let ue_entry = handler
2551            .compute_r5_ue_entry(&password, &u_entry, &original_key)
2552            .unwrap();
2553
2554        // Recover the key
2555        let recovered_key = handler
2556            .recover_r5_encryption_key(&password, &u_entry, &ue_entry)
2557            .unwrap();
2558
2559        // Recovered key must match original
2560        assert_eq!(
2561            recovered_key.as_bytes(),
2562            original_key.as_bytes(),
2563            "Recovered key must match original"
2564        );
2565    }
2566
2567    #[test]
2568    fn test_r5_ue_wrong_password_fails() {
2569        let handler = StandardSecurityHandler::aes_256_r5();
2570        let correct_password = UserPassword("correct".to_string());
2571        let wrong_password = UserPassword("wrong".to_string());
2572        let original_key = EncryptionKey::new(vec![0x99; 32]);
2573
2574        // Compute U and UE with correct password
2575        let u_entry = handler.compute_r5_user_hash(&correct_password).unwrap();
2576        let ue_entry = handler
2577            .compute_r5_ue_entry(&correct_password, &u_entry, &original_key)
2578            .unwrap();
2579
2580        // Try to recover with wrong password
2581        let recovered_key = handler
2582            .recover_r5_encryption_key(&wrong_password, &u_entry, &ue_entry)
2583            .unwrap();
2584
2585        // Key should be different (wrong decryption)
2586        assert_ne!(
2587            recovered_key.as_bytes(),
2588            original_key.as_bytes(),
2589            "Wrong password must produce wrong key"
2590        );
2591    }
2592
2593    #[test]
2594    fn test_r5_ue_invalid_length() {
2595        let handler = StandardSecurityHandler::aes_256_r5();
2596        let password = UserPassword("test".to_string());
2597        let u_entry = vec![0u8; 48]; // Valid U entry length
2598
2599        // Try to recover with wrong length UE entry
2600        let short_ue = vec![0u8; 16]; // Too short
2601        let result = handler.recover_r5_encryption_key(&password, &u_entry, &short_ue);
2602        assert!(result.is_err(), "Short UE entry must fail");
2603
2604        let long_ue = vec![0u8; 64]; // Too long
2605        let result = handler.recover_r5_encryption_key(&password, &u_entry, &long_ue);
2606        assert!(result.is_err(), "Long UE entry must fail");
2607    }
2608
2609    #[test]
2610    fn test_r5_ue_invalid_u_length() {
2611        let handler = StandardSecurityHandler::aes_256_r5();
2612        let password = UserPassword("test".to_string());
2613        let encryption_key = EncryptionKey::new(vec![0x11; 32]);
2614
2615        // Try to compute UE with wrong length U entry
2616        let short_u = vec![0u8; 32]; // Too short
2617        let result = handler.compute_r5_ue_entry(&password, &short_u, &encryption_key);
2618        assert!(
2619            result.is_err(),
2620            "Short U entry must fail for UE computation"
2621        );
2622    }
2623
2624    #[test]
2625    fn test_r5_full_workflow_u_ue() {
2626        let handler = StandardSecurityHandler::aes_256_r5();
2627        let password = UserPassword("full_workflow_test".to_string());
2628        let encryption_key = EncryptionKey::new((0..32).collect::<Vec<u8>>());
2629
2630        // Step 1: Compute U entry (password verification data)
2631        let u_entry = handler.compute_r5_user_hash(&password).unwrap();
2632        assert_eq!(u_entry.len(), 48);
2633
2634        // Step 2: Verify password validates
2635        assert!(handler
2636            .validate_r5_user_password(&password, &u_entry)
2637            .unwrap());
2638
2639        // Step 3: Compute UE entry (encrypted key storage)
2640        let ue_entry = handler
2641            .compute_r5_ue_entry(&password, &u_entry, &encryption_key)
2642            .unwrap();
2643        assert_eq!(ue_entry.len(), 32);
2644
2645        // Step 4: Recover key from UE
2646        let recovered = handler
2647            .recover_r5_encryption_key(&password, &u_entry, &ue_entry)
2648            .unwrap();
2649
2650        // Step 5: Verify recovered key matches original
2651        assert_eq!(
2652            recovered.as_bytes(),
2653            encryption_key.as_bytes(),
2654            "Full R5 workflow: recovered key must match original"
2655        );
2656    }
2657
2658    // ===== Phase 3.1: R6 User Password Tests (SHA-512 based) =====
2659
2660    #[test]
2661    fn test_r6_user_hash_computation() {
2662        let handler = StandardSecurityHandler::aes_256_r6();
2663        let password = UserPassword("r6_test_password".to_string());
2664
2665        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2666
2667        // U entry must be exactly 48 bytes: hash(32) + validation_salt(8) + key_salt(8)
2668        assert_eq!(u_entry.len(), 48, "R6 U entry must be 48 bytes");
2669    }
2670
2671    #[test]
2672    fn test_r6_user_password_validation_correct() {
2673        let handler = StandardSecurityHandler::aes_256_r6();
2674        let password = UserPassword("r6_correct_password".to_string());
2675
2676        // Compute U entry with the password
2677        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2678
2679        // Validate with same password should succeed
2680        let is_valid = handler
2681            .validate_r6_user_password(&password, &u_entry)
2682            .unwrap();
2683        assert!(is_valid, "Correct R6 password must validate");
2684    }
2685
2686    #[test]
2687    fn test_r6_user_password_validation_incorrect() {
2688        let handler = StandardSecurityHandler::aes_256_r6();
2689        let correct_password = UserPassword("r6_correct".to_string());
2690        let wrong_password = UserPassword("r6_wrong".to_string());
2691
2692        // Compute U entry with correct password
2693        let u_entry = handler.compute_r6_user_hash(&correct_password).unwrap();
2694
2695        // Validate with wrong password should fail
2696        let is_valid = handler
2697            .validate_r6_user_password(&wrong_password, &u_entry)
2698            .unwrap();
2699        assert!(!is_valid, "Wrong R6 password must not validate");
2700    }
2701
2702    #[test]
2703    fn test_r6_uses_sha512_not_sha256() {
2704        // Verify R6 produces different hash than R5 for same password
2705        let handler_r5 = StandardSecurityHandler::aes_256_r5();
2706        let handler_r6 = StandardSecurityHandler::aes_256_r6();
2707        let password = UserPassword("same_password_both_revisions".to_string());
2708
2709        let u_r5 = handler_r5.compute_r5_user_hash(&password).unwrap();
2710        let u_r6 = handler_r6.compute_r6_user_hash(&password).unwrap();
2711
2712        // Hash portions (first 32 bytes) should be different
2713        // Note: Salts are random, but even with same salt the hash algorithm differs
2714        assert_ne!(
2715            &u_r5[..32],
2716            &u_r6[..32],
2717            "R5 (SHA-256) and R6 (SHA-512) must produce different hashes"
2718        );
2719    }
2720
2721    #[test]
2722    fn test_r6_unicode_password() {
2723        let handler = StandardSecurityHandler::aes_256_r6();
2724        let unicode_password = UserPassword("café🔒日本語".to_string());
2725
2726        let u_entry = handler.compute_r6_user_hash(&unicode_password).unwrap();
2727        assert_eq!(u_entry.len(), 48);
2728
2729        // Validate with same Unicode password
2730        let is_valid = handler
2731            .validate_r6_user_password(&unicode_password, &u_entry)
2732            .unwrap();
2733        assert!(is_valid, "Unicode password must validate");
2734
2735        // Different Unicode password should fail
2736        let different_unicode = UserPassword("café🔓日本語".to_string()); // Different emoji
2737        let is_valid = handler
2738            .validate_r6_user_password(&different_unicode, &u_entry)
2739            .unwrap();
2740        assert!(!is_valid, "Different Unicode password must not validate");
2741    }
2742
2743    // ===== Phase 3.1: R6 UE Entry Tests =====
2744
2745    #[test]
2746    fn test_r6_ue_entry_computation() {
2747        let handler = StandardSecurityHandler::aes_256_r6();
2748        let password = UserPassword("r6_ue_test".to_string());
2749        let encryption_key = EncryptionKey::new(vec![0xCD; 32]);
2750
2751        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2752        let ue_entry = handler
2753            .compute_r6_ue_entry(&password, &u_entry, &encryption_key)
2754            .unwrap();
2755
2756        assert_eq!(ue_entry.len(), 32, "R6 UE entry must be 32 bytes");
2757    }
2758
2759    #[test]
2760    fn test_r6_encryption_key_recovery() {
2761        let handler = StandardSecurityHandler::aes_256_r6();
2762        let password = UserPassword("r6_recovery_test".to_string());
2763        let original_key = EncryptionKey::new(vec![0xEF; 32]);
2764
2765        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2766        let ue_entry = handler
2767            .compute_r6_ue_entry(&password, &u_entry, &original_key)
2768            .unwrap();
2769
2770        let recovered_key = handler
2771            .recover_r6_encryption_key(&password, &u_entry, &ue_entry)
2772            .unwrap();
2773
2774        assert_eq!(
2775            recovered_key.as_bytes(),
2776            original_key.as_bytes(),
2777            "R6: Recovered key must match original"
2778        );
2779    }
2780
2781    // ===== Phase 3.2: R6 Perms Entry Tests =====
2782
2783    #[test]
2784    fn test_r6_perms_entry_computation() {
2785        let handler = StandardSecurityHandler::aes_256_r6();
2786        let permissions = Permissions::all();
2787        let key = EncryptionKey::new(vec![0x42; 32]);
2788
2789        let perms = handler
2790            .compute_r6_perms_entry(permissions, &key, true)
2791            .unwrap();
2792
2793        assert_eq!(perms.len(), 16, "Perms entry must be 16 bytes");
2794    }
2795
2796    #[test]
2797    fn test_r6_perms_validation() {
2798        let handler = StandardSecurityHandler::aes_256_r6();
2799        let permissions = Permissions::new();
2800        let key = EncryptionKey::new(vec![0x55; 32]);
2801
2802        let perms = handler
2803            .compute_r6_perms_entry(permissions, &key, false)
2804            .unwrap();
2805
2806        let is_valid = handler
2807            .validate_r6_perms(&perms, &key, permissions)
2808            .unwrap();
2809        assert!(is_valid, "Perms validation must succeed with correct key");
2810    }
2811
2812    #[test]
2813    fn test_r6_perms_wrong_key_fails() {
2814        let handler = StandardSecurityHandler::aes_256_r6();
2815        let permissions = Permissions::all();
2816        let correct_key = EncryptionKey::new(vec![0xAA; 32]);
2817        let wrong_key = EncryptionKey::new(vec![0xBB; 32]);
2818
2819        let perms = handler
2820            .compute_r6_perms_entry(permissions, &correct_key, true)
2821            .unwrap();
2822
2823        // Validation with wrong key should fail (structure won't match)
2824        let result = handler.validate_r6_perms(&perms, &wrong_key, permissions);
2825        assert!(result.is_ok()); // No error
2826        assert!(!result.unwrap()); // But validation fails
2827    }
2828
2829    #[test]
2830    fn test_r6_perms_encrypt_metadata_flag() {
2831        let handler = StandardSecurityHandler::aes_256_r6();
2832        let permissions = Permissions::new();
2833        let key = EncryptionKey::new(vec![0x33; 32]);
2834
2835        let perms_true = handler
2836            .compute_r6_perms_entry(permissions, &key, true)
2837            .unwrap();
2838        let perms_false = handler
2839            .compute_r6_perms_entry(permissions, &key, false)
2840            .unwrap();
2841
2842        // Different encrypt_metadata flag should produce different Perms
2843        assert_ne!(
2844            perms_true, perms_false,
2845            "Different EncryptMetadata must produce different Perms"
2846        );
2847
2848        // Extract and verify flags
2849        let flag_true = handler
2850            .extract_r6_encrypt_metadata(&perms_true, &key)
2851            .unwrap();
2852        assert_eq!(flag_true, Some(true));
2853
2854        let flag_false = handler
2855            .extract_r6_encrypt_metadata(&perms_false, &key)
2856            .unwrap();
2857        assert_eq!(flag_false, Some(false));
2858    }
2859
2860    #[test]
2861    fn test_r6_perms_invalid_length() {
2862        let handler = StandardSecurityHandler::aes_256_r6();
2863        let key = EncryptionKey::new(vec![0x44; 32]);
2864        let permissions = Permissions::new();
2865
2866        let invalid_perms = vec![0u8; 12]; // Too short
2867        let result = handler.validate_r6_perms(&invalid_perms, &key, permissions);
2868        assert!(result.is_err(), "Short Perms entry must fail");
2869    }
2870
2871    #[test]
2872    fn test_r6_full_workflow_with_perms() {
2873        // Complete R6 integration test: U + UE + Perms
2874        let handler = StandardSecurityHandler::aes_256_r6();
2875        let password = UserPassword("r6_full_workflow".to_string());
2876        let permissions = Permissions::all();
2877        let encryption_key = EncryptionKey::new((0..32).map(|i| (i * 3) as u8).collect());
2878
2879        // Step 1: Compute U entry (password verification)
2880        let u_entry = handler.compute_r6_user_hash(&password).unwrap();
2881        assert_eq!(u_entry.len(), 48);
2882
2883        // Step 2: Validate password
2884        assert!(handler
2885            .validate_r6_user_password(&password, &u_entry)
2886            .unwrap());
2887
2888        // Step 3: Compute UE entry (encrypted key)
2889        let ue_entry = handler
2890            .compute_r6_ue_entry(&password, &u_entry, &encryption_key)
2891            .unwrap();
2892        assert_eq!(ue_entry.len(), 32);
2893
2894        // Step 4: Compute Perms entry (encrypted permissions)
2895        let perms = handler
2896            .compute_r6_perms_entry(permissions, &encryption_key, true)
2897            .unwrap();
2898        assert_eq!(perms.len(), 16);
2899
2900        // Step 5: Recover encryption key from UE
2901        let recovered_key = handler
2902            .recover_r6_encryption_key(&password, &u_entry, &ue_entry)
2903            .unwrap();
2904        assert_eq!(
2905            recovered_key.as_bytes(),
2906            encryption_key.as_bytes(),
2907            "Recovered key must match original"
2908        );
2909
2910        // Step 6: Validate Perms with recovered key
2911        let perms_valid = handler
2912            .validate_r6_perms(&perms, &recovered_key, permissions)
2913            .unwrap();
2914        assert!(perms_valid, "Perms must validate with recovered key");
2915
2916        // Step 7: Extract EncryptMetadata flag
2917        let encrypt_meta = handler
2918            .extract_r6_encrypt_metadata(&perms, &recovered_key)
2919            .unwrap();
2920        assert_eq!(encrypt_meta, Some(true), "EncryptMetadata must be true");
2921    }
2922}