pdftract/notes/pdftract-2t1an.md
jedarden fe4dcdeaa8 docs(pdftract-2t1an): add verification note for encryption detection
Bead: pdftract-2t1an

Added verification note documenting the complete implementation of
encryption dictionary detection and EncryptionInfo struct.

All acceptance criteria PASS:
- V=1 R=2 RC4-40 detection (version=1, revision=2, key_length=40)
- V=5 R=6 AES-256 detection (version=5, revision=6, key_length=256)
- Non-Standard filter rejection with ENCRYPTION_UNSUPPORTED
- Invalid /O/U length handling with ENCRYPTION_INVALID_DICT
- Clean handling of missing /Encrypt key
- Unit tests covering all V/R combinations

Test results: 10/10 tests pass

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 01:00:22 -04:00

3.4 KiB

pdftract-2t1an: Encryption dictionary detection + EncryptionInfo struct

Summary

Implemented detect_encryption(trailer, resolver) function that parses the PDF trailer's /Encrypt dictionary into a structured EncryptionInfo. The implementation recognizes:

  • /Filter (Standard handler only)
  • /V (1/2/4/5)
  • /R (2/3/4/5/6)
  • /KeyLength (with defaults per version)
  • /O, /U (owner/user password hashes with length validation)
  • /P (permissions bitfield)
  • /Perms (V=5 encrypted permissions)
  • /CF, /StmF, /StrF (crypt filters for V>=4)
  • /ID[0] (file ID from trailer)

Implementation Details

Public Types

  • EncryptionInfo: Main encryption metadata struct

    • version, revision, key_length
    • owner_hash, user_hash, perms, file_id
    • Optional crypt_filters for V>=4
  • CryptFiltersV4: Crypt filter metadata for V=4/5

    • stream_filter, string_filter
    • filters: BTreeMap<String, CryptFilterDef>
  • CryptFilterDef: Individual crypt filter definition

    • cfm: CryptFilterMethod (Identity/V2/AesV2/AesV3)
    • length: Option
    • auth_event: AuthEvent

Detection Function

detect_encryption(trailer, resolver, diagnostics) -> Option<EncryptionInfo>

  1. Looks up /Encrypt in trailer (handles both ObjRef and inline dict)
  2. Resolves ObjRef via XrefResolver
  3. Validates /Filter == /Standard; emits ENCRYPTION_UNSUPPORTED if not
  4. Parses /V, /R, /KeyLength (with version-based defaults)
  5. Parses /O, /U with length validation (32 bytes for R<=4, 48 for R>=5)
  6. Parses /P permissions bitfield
  7. For V>=4, parses /CF, /StmF, /StrF
  8. For V=5, parses /Perms encrypted permissions
  9. Extracts /ID[0] from trailer (or empty if missing)
  10. Returns Some(EncryptionInfo) or None with diagnostics

Diagnostics

  • ENCRYPTION_UNSUPPORTED: Emitted for non-Standard filters (e.g., Adobe Public Key, custom)
  • ENCRYPTION_INVALID_DICT: Emitted for invalid /O or /U lengths, missing required fields

Test Results

All 10 unit tests pass:

  • test_v1_r2_rc4_40: V=1 R=2 RC4-40 (version=1, revision=2, key_length=40)
  • test_v5_r6_aes_256: V=5 R=6 AES-256 (version=5, revision=6, key_length=256)
  • test_non_standard_filter_emits_diagnostic: Returns None + ENCRYPTION_UNSUPPORTED
  • test_invalid_o_length_emits_diagnostic: Returns None + ENCRYPTION_INVALID_DICT
  • test_invalid_u_length_emits_diagnostic: Returns None + ENCRYPTION_INVALID_DICT
  • test_v5_invalid_hash_length_emits_diagnostic: 48-byte validation for R>=5
  • test_no_encrypt_key: Returns None cleanly when no /Encrypt
  • test_missing_id: Empty file_id when /ID missing
  • test_v4_crypt_filters: Parses /CF, /StmF, /StrF correctly
  • test_all_v_r_combinations: Covers V=1/R=2, V=2/R=3, V=4/R=4

Acceptance Criteria Status

Criterion Status Evidence
V=1 R=2 RC4-40 detection PASS test_v1_r2_rc4_40
V=5 R=6 AES-256 detection PASS test_v5_r6_aes_256
Non-Standard filter rejection PASS test_non_standard_filter_emits_diagnostic
Invalid /O length handling PASS test_invalid_o_length_emits_diagnostic
No /Encrypt key handling PASS test_no_encrypt_key
All V/R combinations tested PASS test_all_v_r_combinations

Module Location

crates/pdftract-core/src/encryption/detection.rs (feature-gated on decrypt)

Dependencies

  • pdftract-core::parser::object::{PdfDict, PdfObject, ObjRef}
  • pdftract-core::diagnostics::{emit, Diagnostic, DiagCode}
  • std::collections::BTreeMap