← Back to the tool Home 中文说明
TECHNICAL EXPLAINER

Browser-based PDF Password Removal — How Decryption Works

This tool removes PDF permission restrictions (the Owner password) entirely in your browser. Files are never uploaded to a server.

ⓘ
Based on the "PDF version → encryption method" mapping table, this document explains the decryption logic layer by layer, following the implementation in the tool's core module unlock_core.js.

1PDF Encryption at a Glance

PDF security is implemented by the Standard Security Handler. All encryption information lives in the file's Encryption Dictionary, referenced by /Encrypt <obj> 0 R in the trailer.

Encryption only affects two kinds of content:

Decryption must solve two problems:

  1. File Key: derived from the user password (empty in our case) plus the encryption dictionary;
  2. Object Key: each object (by object number + generation number) derives its own key from the file key, so that one key is never used directly for everything.

2PDF Version → Encryption Method Map

PDF version (compat.)CipherKey lengthEncryption dictionary
PDF 1.1 / 1.2 / 1.3RC440-bit/V 1 /R 2 /Length 40 (no /CF)
PDF 1.4 / 1.5RC4128-bit/V 2 /R 3 /Length 128; or /V 4 /CFM /V2 /Length 128
PDF 1.6 / 1.7AES (AES-CBC)128-bit/V 4 /CFM /AESV2 /Length 128
PDF 1.7+ (low security)AES256-bit/V 5 /R 5 /CFM /AESV3 /Length 256 (single SHA-256)
PDF 1.7+ (high security)AES (AES-256 + PBKDF2)256-bit/V 5 /R 6 /CFM /AESV3 /Length 256 (iterated hash)

3Key Fields of the Encryption Dictionary

FieldMeaningExample
/Filter /StandardStandard security handler/Filter /Standard
/VCipher version (1–5)/V 5
/RRevision (2–6)/R 6
/LengthKey length in bits (classic schemes)/Length 256
/OOwner-password data (32B when V<5; 48B when V=5)/O <e67f...>
/UUser-password data (32B when V<5; 48B when V=5)/U <542c...>
/OE / /UEV5: AES-encrypted Owner/User file key (32B)/UE <7d3a...>
/PPermission bits (32-bit mask, includes flags and three fixed bits)/P -3904
/CF /StdCF /CFMCrypt filter: /V2 (RC4), /AESV2 (AES-128), /AESV3 (AES-256)/CFM /AESV3
/StmF / /StrFFilter for streams / strings (default /Identity = no encryption)/StmF /StdCF
/EncryptMetadataWhether metadata is encrypted (affects key derivation for AES-128)/EncryptMetadata false

4The Decryption Pipeline

1
Read the PDF bytes → locate the encryption dictionary /Encrypt and parse /V /R /Length /O /U /P /CFM /StmF /StrF /UE
▼
2
Derive the file key → V1–V4: Algorithm 2 (MD5(pw+O+P+ID0), iterated 50× when R≥3); V5: Algorithm 2.B (R5 = one SHA-256, R6 = iterated AES-CBC hashing)
▼
3
Validate the empty password → V1–V4: Algorithm 6 compares /U; V5: Algorithm 11 checks /U and decrypts /UE to obtain the 32-byte file key
▼
4
Derive per-object keys → V=1 uses the extended key (spec note 1); V≥2 uses MD5(fileKey[:n]+salt)[:n+5] (AES-128 appends sAlT); V=5 uses the 32-byte file key directly
▼
5
Decrypt streams and strings → RC4 / AES-128 / AES-256-CBC; strings come as literal (...) or hex <...>
▼
6
Rebuild the output → drop /Encrypt, shift offsets by the new (decrypted) lengths and fix the xref → download an unrestricted PDF

4.1 Parsing the encryption dictionary

Find /Encrypt <N> 0 R in the trailer, read the dictionary at the object offset, and extract by regex:

/O, /U and /UE may be either hex strings (<...>) or literal strings ((...)); the latter require unescaping (\(, \), \\, octal \ddd, etc.).

4.2 File key derivation

V1–V4 (classic encryption, Algorithm 2)

key = MD5( password(empty) + O[0:32] + P(4-byte little-endian) + ID[0] )
if R >= 3: repeat 50 times: key = MD5(key + first 3 bytes)
take the first n bytes (n = Length/8; n capped at 16)

Note: for AES-128 (V4) with /EncryptMetadata false, append 4 extra bytes FF FF FF FF to the input. ID[0] comes from the trailer's /ID and participates in key derivation, so changing any byte of the file changes the key.

V5 (Algorithm 2.B)

hash = SHA-256( password + salt + udata )
count = 0
loop:
  count++
  k1 = password + hash + udata
  e  = AES-128-CBC encrypt( key=hash[0:16], IV=hash[16:32], data=k1 repeated 64 times, no padding )
  sel = (e[0]+...+e[15]) % 3            # picks the hash for this round
  hash = SHA-256 / SHA-384 / SHA-512 ( e )
  stop when count ≥ 64 and e[last] ≤ count-32
key = hash[0:32]

R6's stop condition and rotating hashes mean each derivation performs thousands of AES block encryptions and hashes. This is exactly why it is "high security" and brute-force resistant — and a major source of the tool's processing time.

4.3 Password validation (can we open it?)

This step also finalises the file key (cross-checked byte-for-byte against pypdf for R5/R6 in the implementation).

4.4 Per-object key derivation (Algorithms 1 / 3)

Each object builds a salt from object number (3 bytes LE) + generation number (2 bytes LE):

Cipher typeObject key
V=1 (RC4-40, no /CF)Extended key = fileKey + salt (spec note 1: with V=1, MD5 is replaced by RC4, and the extended key is used directly as the RC4 key); generator-compatible writers (e.g. pypdf) use the fallback MD5(fileKey+salt)[:n+5]
V≥2 RC4MD5( fileKey[:n] + salt )[: min(n+5, 16)]
V=4 AES-128Same, with 4 extra bytes sAlT appended to the salt
V=5 AES-256Use the 32-byte file key directly (no MD5, no object salt — Algorithm 3.1a)

RC4-40 key selection was a recent fix: a single wrong derivation breaks every stream. The implementation uses "content validation + primary/fallback adaptation": it decrypts with the spec key first, and if the content check fails (the result is not valid FlateDecode/image data) it retries with the MD5 fallback key, letting string decryption follow the same conclusion.

4.5 Stream decryption and content validation

4.6 String decryption

Strings are encrypted only under "classic encryption (V<4)" or when the dictionary explicitly sets /StrF to something other than /Identity (otherwise they are skipped — which is why some files keep intact bookmarks). Ciphertext comes in two forms:

The decrypted result must keep byte/text length consistency, and scanning continues after each replacement (adapting to shifted offsets).

4.7 Rebuilding the output

5Per-method Implementation Matrix

MethodV/RFile keyObject keyStream decryptionPassword check
RC4-401/2Alg. 2, 5 bytesExtended key (spec) / MD5 fallbackRC4 length-preserving + validationAlg. 6 (20 RC4 iterations)
RC4-1282/3 or 4/CFM V2Alg. 2, 16 bytes (50 iterations when R3)MD5+salt[:n+5]RC4 length-preserving + validationAlg. 6
AES-1284/AESV2Alg. 2 + EncryptMetadata fix-upMD5+salt+sAlTAES-CBC PKCS7 (Web Crypto)Alg. 6
AES-256 low5/R5Alg. 2.B: single SHA-256File key (32B)AES-256-CBC (Web Crypto)Alg. 11
AES-256 high5/R6Alg. 2.B: iterated hash (AES-CBC + rotating hashes)File key (32B)AES-256-CBC (Web Crypto)Alg. 11

Note: R6 iteration and /UE decryption require AES-CBC without padding, which Web Crypto does not provide. The core therefore ships a pure-JS AES block implementation (SBOX / key schedule / CBC chaining, verified against NIST test vectors) — the key to being a single self-contained file.

6Scope and Boundaries

SUPPORTED

NOT SUPPORTED / REJECTED

PRIVACY All logic runs in local browser JavaScript; files never leave your machine and are never uploaded.

7How It Was Verified