RFID
rfid launches an on-device RFID application and opens an interactive rfid> sub-prompt for reading, writing, sniffing, and emulating LF and HF tags. The same commands and dump-file formats are used on every device that has an RFID frontend (the Proxmark3, the Flipper Zero and Kiisu, and the Chameleon Ultra), so a card read on one device can be written or emulated from another.
Devices and frontends
Each platform implements its own driver in platforms/*/rfid.c. The drivers meet at the HAL in hal/hal_rfid.h, where HF is a framed transceive and LF is a raw acquire plus modulate. The protocol layer above the HAL - anticollision, EM4100 decode, CRC, Crypto1 - lives in the RFID app and is shared across platforms. Each platform reports which operations it supports through capability bits, and the CLI adapts at runtime.
| Device | RFID frontend |
|---|---|
| Proxmark3 | Xilinx Spartan-II XC2S30 FPGA driven by the AT91SAM7S512 |
| Flipper Zero / Kiisu | ST25R3916 in transparent mode |
| Chameleon Ultra | nRF52840 NFCT + MFRC522 |
Each frontend covers both LF and HF. On the Proxmark3, the FPGA bitstreams are stored compressed under /fpga; they are streamed from the host the first time a band is used.
Running the app
rfid is a command in the Fantasi host CLI. It requires the protobuf transport, so start the client with --usb or --ble. Over plain --serial it reports:
fantasi> rfid
rfid: needs the protobuf transport - start the CLI with --usb or --ble
With a protobuf transport, rfid launches the on-device app and opens the rfid> sub-prompt, which has its own command history and TAB completion. Use exit to leave the app and return to the main CLI.
fantasi> rfid
rfid> read mfc
rfid> read t5577
rfid> exit
To run a single RFID command without entering the sub-prompt, pass it to the host CLI's -c flag. This launches the app, runs the one command, and exits:
fantasi --usb -c "rfid read mfc"
fantasi --usb -c "rfid emulate lf-t55xx-1A2B3C4D-dump.json"
Only one app runs on the device at a time. If a previous rfid session did not exit cleanly, later commands report rfid: an app is already running; run kill from the main CLI to stop it.
Commands
help lists the available verbs:
rfid> help
commands:
search [protocol] scan for tags (bare = every band)
sniff <protocol> passively watch a reader<->card exchange
raw <protocol> [-c][-k][-s] <hex> send a raw frame to a protocol
write <protocol> -b <block> -d <hex> write a block to a tag
read <protocol> [-b <block>] read a block, or all blocks, from a tag
collect <protocol> <card|reader|sniff> [-u UID][-k key] gather key material (nonces, sniffed keys)
emulate <dump.json> emulate a card from a saved dump (MIFARE Classic)
list [band|sub] list supported protocols (band > sub-cat > protocol)
trace [clear] show (or clear) the accumulated raw trace
field on|off|status turn the reader carrier on/off, or report it
help show this help
exit leave the rfid app
read, write, list, collect, and emulate are handled on the host; search, sniff, raw, trace, and field dispatch to the device.
list
list prints the supported protocols as a band > tech > protocol tree, with the operations available for each protocol. Pass a band or sub-category name to filter (for example list lf). The three bands are LF, HF, and UHF.
rfid> list
LF
125-500 kHz
lf generic read available
t5577 T5577 read raw write available
HF · 13.56 MHz
NFC A · ISO14443-A
nfca generic read sniff raw available
mfc MIFARE Classic read sniff raw available
mfp MIFARE Plus sniff raw available
ul Ultralight read sniff raw available
ulc Ultralight C read sniff raw available
ulaes Ultralight AES sniff raw available
mfdes DESFire sniff raw available
NFC B · ISO14443-B
(none yet)
NFC F · FeliCa
(none yet)
NFC V · ISO15693
(none yet)
UHF
860-960 MHz
(none yet)
search
search [protocol] scans for a tag in the field and reports what it finds. With no argument it scans every band; pass a protocol to limit the scan.
read
read <protocol> [-b <block>] reads a tag. A bare read <protocol> reads all blocks; -b <n> reads a single block.
read t5577reads an LF T5577 in full. It decodes the config block first to determine how many data blocks the tag holds, then reads them and prints an all-block dump.read mfcreads a MIFARE Classic card end to end: it collects nonces, recovers the sector keys against a dictionary, then authenticates and dumps every block. The bundled key dictionary is inresources/nfc/mfc_dict.dic.
Add -s to save the result as a dump file (see Dump files).
write
write <protocol> -b <block> -d <hex> writes one block. For example, to write block 4 of a T5577:
rfid> write t5577 -b 4 -d 1A2B3C4D
raw
raw <protocol> [-c][-k][-s] <hex> sends a raw frame and prints the response - the way to reach a protocol that has no dedicated read/write support (see the raw column in list).
| Flag | Effect |
|---|---|
-c | Append the protocol CRC to the frame |
-k | Keep the field on after the frame (for a multi-step exchange) |
-s | Select the card before sending the frame |
field
field on|off|status drives the reader carrier directly: turn the field on or off, or report its current state.
trace
trace prints the accumulated raw frame trace from the current session; trace clear empties it.
Sniffing
sniff <protocol> passively watches a live reader-to-card exchange with the device's own field off. Traffic prints as it happens; press any key or ^C (Control-C) to stop.
rfid> sniff mfc
The host annotates each captured frame against the protocol you named, labelling commands inline - for example SELECT, ANTICOLL, READ blk 4, AUTH-A blk 7, WRITE page 6. Frames with bad CRCs or parity errors are flagged in place. For MIFARE Classic, mfkey64 runs against the trace as it is captured, so a captured authentication yields the sector key without a separate cracking step.
Where the frontend can measure field strength, a capture opens with a coupling reading that grades the sniff quality as strong, fair, or weak (shown green, yellow, or red). On the Flipper this reading comes from the ST25R3916's External Field Detector and also drives an adaptive first-stage gain, which keeps a reader in range as its distance changes. A device that cannot measure field strength reports the coupling as unknown.
Emulation
emulate <dump.json> plays a saved card back to a reader. The supported card type is MIFARE Classic 1K, which is load-modulated through a full reader authentication and block reads. Emulation runs until you press a key or ^C.
rfid> emulate hf-mf-A1B2C3D4-dump.json
The dump is a JSON card image such as those written by read -s. Frame delay time (FDT) is close to that of a physical card, which is generally required for readers that reject slower emulators. For background on the timing, see the Chameleon Ultra technical whitepaper.
collect
collect <protocol> <card|reader|sniff> [-u UID][-k key] gathers key material - nonces from a card or reader, or keys recovered from a sniffed exchange - and writes it to a log the host can consume (for example when recovering MIFARE Classic keys).
Dump files
read -s writes a dump file when it reads a card. The format is close to the Proxmark3's own dump format, so files interchange for common card types. Emulation and re-writing read these dumps back.
How the app is structured
The RFID app itself contains little protocol code. Each feature - the HF reader, the LF reader, the sniffer, raw transceive, T5577 read/write, and the MIFARE Classic collect, read, and emulate stages - is a separate ELF module. When a command needs one, the module is fetched from the host over the protobuf link, run, and then deleted, so only one module is resident at a time. This keeps the subsystem within the flash and heap limits of the smallest target, the Proxmark3.