Recover forgotten passwords for old, locked files — right in your browser.
Everything runs client-side. Your file is opened locally by JavaScript and is never uploaded to any server. No backend, no accounts, no tracking, no build step.
▶ Live demo: palniraj.github.io/keyfinder
Repository: github.com/palniraj/keyfinder
screencast.webm
⚠️ Use responsibly. KeyFinder is for regaining access to files you own or are authorized to access. It targets weak passwords on obsolete or slow-by-design encryption. For modern Office AES it only helps with weak/common passwords — it does not defeat strong AES passwords.
| Format | Scheme | Status |
|---|---|---|
Word 97–2003 (.doc) |
RC4 40-bit (MD5) | ✅ Recover password and download an unlocked copy |
Excel 97–2003 (.xls) |
RC4 40-bit / RC4 CryptoAPI | ✅ Recover password (validated end-to-end) |
PowerPoint 97–2003 (.ppt) |
RC4 CryptoAPI | 🧪 Beta — recovers password; parser not yet verified on a sample |
Modern Office (.xlsx/.docx/.pptx, 2007+) |
AES (Standard SHA-1 / Agile SHA-512) | 🐢 Recover weak/common passwords only — slow, dictionary-first |
| PDF (older) | RC4 40/128-bit (Standard Security Handler, R2-R4) | ✅ Recover password (validated end-to-end) |
| ZIP | ZipCrypto (traditional PKWARE) | ✅ Recover password, CRC-verified (validated end-to-end) |
| ZIP | WinZip AES-128/256 (7-Zip, WinZip, macOS, GNOME) | 🐢 Recover weak/common passwords (weak PBKDF2 KDF), HMAC-verified |
| Modern PDF | AES-128 / AES-256 | ⛔ Detected but not brute-forceable |
KeyFinder detects the format and scheme of any file you drop in and tells you, in plain language, whether it can be recovered.
Crypto is validated against public John the Ripper oldoffice test vectors for
both the MD5 (types 0/1) and SHA-1 CryptoAPI (types 3/4) schemes, against FIPS 180-4
vectors for SHA-512 and FIPS-197 vectors for AES, and — for the modern Office Agile and
Standard verifiers — against independent vectors generated with Python hashlib +
cryptography. The PDF RC4 verifier is validated against real RC4-encrypted PDFs whose
/O and /U come from an independent Python implementation of the PDF spec's
Algorithms 2-5, and the ZIP verifier against real Info-ZIP ZipCrypto archives
(decrypt → inflate → CRC-32 confirmation, so a match is certain, not a 1-in-256 guess).
The WinZip-AES verifier is validated against PBKDF2-HMAC-SHA1 (RFC 6070) and independent
OpenSSL-generated verification/HMAC vectors. Excel recovery is additionally validated
end-to-end against a real password-protected .xls. The
PowerPoint header parser mirrors the reference office2john logic but has not yet been
verified against a real encrypted .ppt, hence its Beta label. For Excel/PowerPoint
the tool finds the password so you can open the file; a downloadable decrypted copy is
currently implemented only for Word .doc.
- Simple for non-technical users — drop a file, click one button.
- Runs entirely in the browser — nothing is uploaded.
- Honest format detection — clear status for every file type.
- Fast, high-yield search (multi-core Web Workers), tried in order:
- ~100,000 real-world common passwords (NCSC "most used", by frequency)
- a ~73,000-word English dictionary
- optional variations (
Word,word123,word!, …) - an optional custom wordlist
- optional brute force (short passwords)
oldoffice$0hash export for hashcat (mode9700) / John the Ripper.- Download an unlocked copy once the password is found (Word
.doc).
.doc files are OLE compound files. With version 1.1 "Office Binary Document RC4
Encryption" (MS-OFFCRYPTO §2.3.6), the key derives from the password via MD5 and only
40 bits are secret. The stored verifier lets us test guesses very fast:
keyHash = MD5(UTF16LE(password)) # first 5 bytes
buf = (keyHash[:5] + salt) * 16 # 336 bytes
mitm = MD5(buf) # first 5 bytes (the 40-bit key)
rc4Key = MD5(mitm[:5] + blockNumber) # 16-byte RC4 key
verify: dec = RC4(rc4Key, verifier || verifierHash)
ok = MD5(dec[:16]) == dec[16:32]
Same algorithm as John the Ripper's oldoffice (types 0/1) and msoffcrypto-tool.
Password-protected .xlsx/.docx/.pptx are OLE files holding an EncryptionInfo
descriptor plus an EncryptedPackage. Two schemes are supported:
- Standard Encryption (Office 2007): SHA-1, 50,000 iterations, AES-ECB.
- Agile Encryption (Office 2010+ and LibreOffice): SHA-512,
spinCount(typically 100,000) iterations, AES-CBC.
Both expose a verifier we can test without touching the package, so a guess is checked with a bounded amount of work — but that work includes the full iterated key derivation:
Standard: H = SHA1(salt || UTF16LE(pw)); repeat 50000×: H = SHA1(LE32(i) || H)
key = DeriveKey(SHA1(H || LE32(0))); ok = SHA1(AESdec(key,verifier)) == AESdec(key,verifierHash)
Agile: H = SHA512(salt || UTF16LE(pw)); repeat spinCount×: H = SHA512(LE32(i) || H)
key(blk) = SHA512(H || blockKey)[:keyBits/8]; verify via AES-CBC(IV=salt)
That deliberate iteration cost is why guessing is orders of magnitude slower than the
legacy formats (dozens of guesses/sec in-browser, not millions), and why only weak or
common passwords are realistically recoverable. The verifiers follow the same logic as
msoffcrypto-tool and hashcat (mode 9400 for 2007 Standard, 9500/9600 for Agile
2010/2013); our implementation is validated against independent vectors generated with
Python hashlib + cryptography (see the self-tests).
PDF (Standard Security Handler, RC4). Old PDFs derive the file key from the user
password with MD5 and encrypt with RC4, so a guess is checked against the stored /O,
/U, /P and /ID values (ISO 32000-1, Algorithms 2 and 4/5):
key = MD5( pad(pw) || O || P_le32 || ID0 [|| 0xffffffff if R>=4 && !EncryptMetadata] )
then, for R>=3, MD5 the first n bytes 50 more times; take n bytes
R2: ok = RC4(key, PAD) == /U (all 32 bytes)
R3+: x = RC4(key, MD5(PAD||ID0)); for i in 1..19: x = RC4(key ^ i, x)
ok = x == /U[:16]
AES-encrypted PDFs (V4 AESV2, V5/R6 AES-256) are detected and reported as not
feasible to brute-force.
ZIP (ZipCrypto / traditional PKWARE). Each entry has a 12-byte encryption header stream-encrypted with keys seeded from the password. A candidate is first screened by the header's check byte, then confirmed for certain by decrypting the whole entry, inflating it (RFC 1951), and matching its CRC-32 — no false positives.
ZIP (WinZip AES — the modern default). 7-Zip, WinZip, macOS and the GNOME/Windows
"compress with password" menus produce AES ZIPs (method 99). The content uses AES,
which we don't break — but the password key derivation is PBKDF2-HMAC-SHA1 with only
1000 iterations, so weak passwords fall to a dictionary run:
dk = PBKDF2-HMAC-SHA1(pw, salt, 1000, 2*keyLen + 2)
screen: dk[2*keyLen : +2] == the entry's 2-byte password-verification value
confirm: HMAC-SHA1(dk[keyLen : 2*keyLen], ciphertext)[:10] == the entry's auth code
The 2-byte screen is one PBKDF2 block (cheap); the HMAC confirmation makes a reported
password certain. Same scheme as hashcat mode 13600.
Serve over http(s) (ES modules + module Web Workers don't run from file://):
python3 dev_server.py 8000 # then open http://localhost:8000 (no-cache dev server)
# or: python3 -m http.server 8000npm test # node test/selftest.mjs — MD5 / RC4 / oldoffice vs public vectorsAn in-browser self-test lives under How it works → Developer diagnostics, and a
real Web Worker smoke test is at test/browser_e2e.html.
Static site, no build. Push the repo, then Settings → Pages → Source = "Deploy from a
branch", pick your branch and / (root). A .nojekyll file is included so src/,
data/ and the fonts are served verbatim. Live at
https://palniraj.github.io/keyfinder/.
index.html UI (two-column, single screen)
styles.css styling (self-hosted Outfit + Space Grotesk)
assets/fonts/ woff2 fonts + OFL licenses
data/
common-passwords.txt ~100k most-used passwords (SecLists / NCSC)
wordlist.txt ~73k English words (SCOWL)
NOTICE.md attribution for lists & fonts
src/
md5.js, rc4.js primitives
sha1.js, sha512.js hashes (SHA-1: CryptoAPI/Standard; SHA-512: Agile)
aes.js AES-128/192/256 ECB + CBC decryption (no padding)
inflate.js raw DEFLATE decompressor (for ZIP CRC verification)
oldoffice.js legacy RC4 key derivation, verify, decryption + verifier dispatch
agile.js modern Office Agile Encryption (SHA-512/AES-CBC) parse + verify
office2007.js modern Office Standard Encryption (SHA-1/AES-ECB) parse + verify
pdf.js PDF Standard Security Handler (RC4) parse + verify
zipcrypto.js ZIP ZipCrypto (PKWARE) parse + verify (CRC-confirmed)
zipaes.js ZIP WinZip-AES parse + PBKDF2-HMAC-SHA1 verify (HMAC-confirmed)
ole.js OLE/CFB reader + in-place stream writer
doc.js .doc analysis + decryption
formats.js multi-format detector + Excel/PowerPoint/modern-Office/PDF/ZIP parsing
search.js candidate generation + job execution
worker.js, engine.js Web Worker + coordinator
selftest.js, app.js in-browser self-test + UI controller
Password/word lists and fonts are third-party; see data/NOTICE.md.
MIT — see LICENSE.