A reproducible, read-only research toolkit for recovering MIFARE Classic 1K sector keys with a Raspberry Pi and an inexpensive MFRC522 / RC522 reader.
The project unifies two recovery paths behind one Typer and Rich CLI:
- Weak nonce cards: classic Nested recovery based on Håkon Hystad's
MFRC522_nested_attackimplementation. - Hardened nonce cards: an RC522 raw-frame acquisition path developed for this project, followed by the RRG/Iceman Proxmark3 Hardnested solver in offline mode.
Every candidate is authenticated against the physical card before it is accepted. Every verified key is immediately tested across remaining sectors, so reused keys and readable Key B values are discovered before another expensive nonce collection begins.
Important
Use this project only with cards you own or have explicit permission to test. The bundled workflow is read-only and contains no card-writing, cloning, or emulation command.
The MFRC522 can transmit raw ISO 14443-A frames and expose encrypted parity when automatic parity handling is disabled. That is enough to collect the encrypted nonce material required by Hardnested. The CPU-intensive Crypto1 search is delegated to the mature Proxmark3 client in offline mode.
This project is not a complete Proxmark3 replacement. It is a focused MIFARE Classic acquisition frontend for one inexpensive reader.
| Capability | Status |
|---|---|
| Raspberry Pi 5, Raspberry Pi OS Trixie arm64 | Hardware tested |
| Raspberry Pi 4 | Expected to work, community validation welcome |
MFRC522 VersionReg 0x92 |
Hardware tested |
MFRC522 VersionReg 0x91 |
Expected to work |
| MIFARE Classic 1K, 4-byte UID | Supported |
| Common-key and reused-key discovery | Supported |
| Readable Key B extraction from sector trailers | Supported and re-authenticated before acceptance |
| Weak PRNG Nested | Implemented from the upstream RC522 attack path |
| Hardened PRNG Hardnested | Hardware validated on Raspberry Pi 5 and MFRC522 0x92 |
| Direct recovered-key verification | Supported |
| Resumable private state | Supported |
JSON, CSV, MCT .keys, and 1 KiB binary dump export |
Supported |
| Static nonce and static encrypted nonce cards | Detected, not implemented |
| MIFARE Classic 4K, Plus, DESFire, Ultralight, NTAG | Not supported |
| Writing, cloning, emulation | Intentionally out of scope |
See docs/TEST_MATRIX.md for the exact validated environment.
Power the RC522 from 3.3 V only.
| RC522 | Raspberry Pi physical pin | Signal |
|---|---|---|
3.3V |
1 | 3.3 V |
GND |
6 | Ground |
SDA / SS |
24 | SPI0 CE0, GPIO8 |
SCK |
23 | SPI0 SCLK, GPIO11 |
MOSI |
19 | SPI0 MOSI, GPIO10 |
MISO |
21 | SPI0 MISO, GPIO9 |
RST |
18 | GPIO24, WiringPi pin 5 |
IRQ |
Not connected | Unused |
Detailed hardware guidance is in docs/HARDWARE.md.
git clone https://github.com/AppSolves/rc522-mfc-recovery.git
cd rc522-mfc-recovery
./scripts/bootstrap.sh
source .venv/bin/activate
rc522-mfc doctor
rc522-mfc --versionThe installer:
- installs the required Debian packages,
- enables SPI through
raspi-configwhen available, - installs the stable WiringPi 3.18 Debian package,
- builds the native RC522 helper,
- fetches a pinned Proxmark3 commit and applies the narrow offline Hardnested patch,
- creates a Python virtual environment and installs the CLI.
The same process is available through:
rc522-mfc setupReader-facing commands perform a toolchain preflight. When a component is missing and the terminal is interactive, the CLI offers to run setup automatically.
rc522-mfc inspectThe command identifies the card and classifies its nonce generator as:
weakhardstatic
Nested recovery needs at least one known and verified sector key. Supply seeds in SECTOR:TYPE=KEY form:
rc522-mfc recover \
--known 4:A=FFFFFFFFFFFF \
--known 4:B=FFFFFFFFFFFF \
--sectors 0-15 \
--key-types ABThe automatic workflow performs these stages:
- verify every supplied key directly,
- test the bundled starter dictionary and optional user dictionaries, unless
--skip-dictionaryis set, - extract a readable Key B from a sector trailer when access conditions permit it,
- verify any extracted Key B through a fresh authentication,
- test every known key against all still-unknown sectors,
- classify the nonce generator,
- run weak Nested or RC522 Hardnested acquisition,
- solve Hardnested data offline when required,
- verify the recovered candidate directly,
- repeat global key-reuse checks and continue.
Long stages use Rich progress rows. Dictionary scans, nonce classification, and Hardnested trace collection report determinate counts. Hardnested collection also reports native attempts and consecutive failures. The offline Proxmark3 solver is shown as an indeterminate stage because it does not expose a stable candidate-count progress value.
Use an additional MCT-compatible dictionary when appropriate:
rc522-mfc recover \
--known 4:A=FFFFFFFFFFFF \
--dictionary ~/extended-std.keysThe option can be repeated. A dictionary file contains one 12-hex-character key per line.
If you already know dictionary scanning will not help and want to go straight to nonce classification and recovery, skip that stage explicitly:
rc522-mfc recover \
--known 4:A=FFFFFFFFFFFF \
--skip-dictionaryAn interrupted run is resumable. Verified keys and complete trace datasets are reused automatically. Trace metadata is checked against the UID, target block, key type, record count, and format before reuse.
Use tmux so an SSH disconnect does not end the workflow:
tmux new -s rc522-recovery
source .venv/bin/activate
rc522-mfc recover --known 4:A=FFFFFFFFFFFFDetach with Ctrl+B, then D. Reattach with:
tmux attach -t rc522-recoveryrc522-mfc status DEADBEEF
rc522-mfc verify DEADBEEFPrivate state is stored under the platform data directory, normally:
~/.local/share/rc522-mfc/cards/<UID>/
rc522-mfc export DEADBEEF --format json
rc522-mfc export DEADBEEF --format csv
rc522-mfc export DEADBEEF --format keys
rc522-mfc export DEADBEEF --format dumpExport formats:
json: full key map, metadata, discovery source, verification state.csv: sector-oriented table containing verified keys only.keys: one unique verified key per line, compatible with MIFARE Classic Tool key files.dump: 1,024-byte MIFARE Classic binary image. Verified recovered key bytes are inserted into sector trailer key fields because Key A is masked during normal card reads.
The dump reader tries verified Key A and Key B independently for each block, which supports sectors whose access conditions require different keys for different blocks. Keys marked unverified by rc522-mfc verify remain visible in JSON and status, but they are not treated as recovered for reuse, CSV, .keys, or dump export.
This repository deliberately uses no Git submodules.
- The small Håkon Hystad reader and weak-Nested core is vendored because this project contains substantial reviewed modifications to it.
- WiringPi is installed as a pinned platform package.
- Proxmark3 is fetched at a pinned tested commit into the user's cache, patched narrowly, and built as a client only.
This design keeps a normal ZIP download complete, avoids a very large Proxmark3 submodule, and avoids permanently dirty patched submodules.
More detail is in docs/ARCHITECTURE.md and docs/INSTALLATION.md.
.
├── .github/ GitHub Actions and contribution templates
├── docs/ Architecture, installation, formats, hardware, troubleshooting
├── native/
│ ├── src/ Unified RC522 native frontend
│ └── vendor/hakon/ Modified GPL-3.0 weak-Nested and reader core
├── patches/ Narrow Proxmark3 offline-solver patch
├── scripts/ Setup, build, cleanup, and release checks
├── src/rc522_mfc/ Typer and Rich orchestration package
├── tests/ Python unit tests
├── LICENSE
├── THIRD_PARTY.md
└── pyproject.toml
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
ruff check src tests
mypy src
pytest
cmake -S native -B build/mock -DRC522_HARDWARE=OFF
cmake --build build/mockRun the release safety check before publishing:
./scripts/release-check.shUIDs, keys, nonce traces, solver logs, and dumps are sensitive. They are ignored by Git, but .gitignore cannot remove data from an existing commit or archive.
Read SECURITY.md and docs/PUBLISHING.md before publishing forks, issues, logs, or releases.
The combined source distribution is licensed under GPL-3.0-only because it includes a modified GPL-3.0 implementation of MFRC522_nested_attack.
The Proxmark3 client and WiringPi are downloaded or installed separately. Full attribution is in THIRD_PARTY.md.
The implementation builds on:
- Håkon Hystad,
MFRC522_nested_attack - RRG/Iceman Proxmark3
- Carlo Meijer and Roel Verdult, Ciphertext-only Cryptanalysis on Hardened MIFARE Classic Cards
- NXP MFRC522 data sheet
See docs/REFERENCES.md.