Commit Graph
23382 Commits
Author SHA1 Message Date
iceman1001 de2aaa48d8 text 2026-09-22 14:48:54 +02:00
iceman1001andClaude Opus 5 e3be641809 hf mf: honour --ns in the FM11RF08S nonce recovery
`hf mf autopwn --ns` asks for no files, but on an FM11RF08S it wrote
them anyway. no_save is read once and only gates the two save blocks
at the end of autopwn; the static encrypted nonce is detected earlier
and returns into HFMFSENRecover from five places, none of which saw
the flag. The recovery path wrote the key file and the dump
unconditionally, and now that the dump carries JSON as well, that was
three files against a flag asking for none.

no_save travels with the call now, and fm11_save_recovery_outputs
returns before it names anything, printing the same "Called with no
save option" line that `hf mf dump` and autopwn already print. The key
table is still shown, so --ns reads the card and leaves nothing on
disk.

`hf mf sen` gains the same `--ns` option, so the flag does not depend
on which command reached the recovery.

--ns does not suppress `--keep-nonces`. That option exists only to
write its evidence file, and a blanket no-save would leave no way to
ask for the evidence without a dump.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 14:24:34 +02:00
iceman1001andClaude Opus 5 42b8fb8367 hf mf: carry --suffix into the FM11RF08S nonce recovery
`hf mf autopwn --suffix <txt>` names its output files
`hf-mf-<uid>-<dump|key>-<suffix>`, but on an FM11RF08S the suffix was
dropped. autopwn detects the static encrypted nonce and returns into
HFMFSENRecover from five separate places, all of them before its own
file naming runs, and the recovery path built `hf-mf-<uid>-key` and
`hf-mf-<uid>-dump` from the card UID alone. Two runs against the same
card overwrote each other, which is the collision the suffix exists to
prevent.

The suffix now travels with the call, so a card autopwn hands over is
named the same way as one autopwn finishes itself.

`hf mf sen` gains the same `--suffix` option, so the naming no longer
depends on which command reached the recovery. It covers the
`--keep-nonces` evidence file too, which collided the same way.

The three names are built by fm11_build_filename() instead of by three
snprintf calls that have to agree on the template.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 14:22:18 +02:00
iceman1001 38e733e37d fix #3655 2026-09-22 13:56:07 +02:00
iceman1001andClaude Opus 5 950ba026bf hf mfdes: check the PICC master key, keep --key, and read 0x1A on its own
`hf mfdes chk` reported "No keys found" on a card whose PICC master key was
still the factory default, and missed a key handed to it on the command line.

The AID list comes from GetApplicationIDs, which never returns 000000, so the
PICC level was never swept - only an explicit `--aid 000000` reached it. That
list is itself gated by PICC key settings bit 1, and a card refusing it aborted
the whole run rather than falling back to the one key number still reachable.
000000 now seeds the sweep, and a refused list leaves the PICC level to check.

A key given with `--key` was written into the key list at parse time and then
overwritten: every round resets the length and refills the same buffer from
index 0. It was counted in "Loaded N keys" and never tried. It is now
re-inserted at the head of its list after each fill, so it is attempt one.

When key settings are unreadable the fallback walked the file access rights to
name the key numbers in use. GetFileIDs, GetISOFileIDs and GetFileSettings are
gated by the same settings bit that just refused GetKeySettings, so that
fallback could never run. GetKeyVersion is not gated at all and names the key numbers
directly, absent ones answering 0x40 NO_SUCH_KEY.

AuthenticateISO (0x1A) was read only when Authenticate (0x0A) had answered
first, but 0x1A covers DES, 2TDEA and 3TDEA where 0x0A covers only the first
two. An application holding 3TDEA keys answers 0x1A alone, so it named no key
type and was skipped outright. chk and detect both read it on its own now.
Because 0x1A cannot separate 2TDEA from 3TDEA, detect also drops a key type on
the first wrong-length challenge instead of waiting for its error counter.

Measured on a DESFire EV2 2K: PICC master key and an application AES key are
both recovered in one run, and the unauthenticated GetKeyVersion sweep keeps
answering across a run of NO_SUCH_KEY errors with no re-select.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 13:55:06 +02:00
iceman1001 ee20f50965 fix duplicates 2026-09-22 12:49:50 +02:00
iceman1001andClaude Opus 5 a3d32ac220 hf mfdes view: name known AIDs
The dump viewer printed bare AID numbers while the live card paths
already resolved them through AIDDFGetCommentStr(). Use the same lookup
here, falling back to the old separator line when the AID is unknown.

    --- AID 578000 --- NORTIC (Card Issuer App) [NPRA]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 12:46:06 +02:00
iceman1001 5a964c8b5a fix our uniqueness check to als include JSON files 2026-09-22 12:39:26 +02:00
iceman1001 577f6ef45c added entries from Metrodroid project 2026-09-22 12:38:15 +02:00
iceman1001 4d1414a0e9 fix duplicate entries in aid file 2026-09-22 12:36:56 +02:00
Iceman 2539efc901 Merge pull request #3651 from youngh82/pm3-iclass-sio-unknown-tags
hf iclass view: surface unhandled SIO TLV tags in Insights
2026-09-22 16:22:52 +07:00
Iceman f7dd78ebc5 Merge branch 'master' into pm3-iclass-sio-unknown-tags
Signed-off-by: Iceman <iceman@iuse.se>
2026-09-22 16:22:25 +07:00
iceman1001 0aa6c96c22 hook in parser 2026-09-22 11:20:15 +02:00
iceman1001andClaude Opus 5 54e004e252 hf mfdes: add NORTIC travel card parser
NORTIC (Norwegian Ticketing Interoperable Concept) is the Norwegian
national public transport card, on DESFire since 2008 and specified by
Statens vegvesen, now Jernbanedirektoratet, in Handbok V821.

Decodes the card issuer header, file 0C of AID 578000. That file is
free to read, so the parser produces output on any Norwegian card
without key material: country code, format, choice bitmap, card serial
number, validity end date, application owner company, retailer
organisation and card key version.

The transport application, AID 578001, is listed by file with its role
and the key it needs, and any file that was read is dumped as hex. Its
field layouts are in Handbok V821 Del 18, which has no download link,
and every file needs read key 7, which is not public. Nothing there is
guessed at.

NORTIC is EN 1545 and packs fields most significant bit first, which is
the opposite of the RKF Type CL-1 layout in parserkf.c where RKF-0022
7.4.1 numbers bits from the least significant end. Reading a NORTIC
header the RKF way gives country code 144 instead of 578, so the self
test asserts that as a negative control.

Verified field by field against the published card issuer header, every
field matching its documented value, including the validity date 6938
decoding to 2015-12-31. 'hf mfdes view --selftest' runs the checks,
including a round trip through an encoder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 11:19:24 +02:00
iceman1001andClaude Opus 5 28d49510e2 hf mf: add RKF travel card parser
The RKF travel card (Resekortsföreningen i Norden) is the Nordic public
transport card, specified 2001-2002 on MIFARE Classic and deployed by
Västtrafik, SL Stockholm, Länstrafiken and the Danish Rejsekort.

Decodes the card issuer and support layers (CMI, TCCI, TCAS, TCDI) and
every application object the specification pins down: TCPU purse, TCEL
event log, TCDB, TCCP, TCST, and TCTI/TCCO through an identifier chain
walker covering all 18 data element groups. AID owners are named from
RKF-0019.

Three things the specification does not state, determined from 21 cards:

  - RKF-0022 7.7.1 calls the block checksum 'standard CRC-8' without
    naming the parameters. It is CRC-8/MIFARE-MAD, poly 0x1D init 0xC7,
    which the tree already ships as CRC8Mad().

  - The MAC trio is the final 24 bits of a MACed object. The RKF-0023
    tables list Free (bits) as a trailing summary row, which reads as if
    the authenticator follows a gap after the key identifier; it does
    not. Measured on the fact that MACAlgorithmIdentifier must be 0:
    TCST 42/42 against 15/42, TCCP 20/20 against 13/20.

  - TCPU version 4 drops EndDate and moves Value to bit 16.

Cards reporting a version other than 2 are flagged, and a MAC algorithm
the specification does not define is reported as a layout failure rather
than printed as data.

MAC values are not verified. The master key is in RKF-0018, which was
never published. des_mac() is added to libpcrypto for when that changes,
with the FIPS 113 worked example as its test.

Verified against a Danish Rejsekort whose provenance notes give the
purchase timestamp, card number and balance; the parser reproduces all
three. 48 self test checks on 'hf mf view --selftest', no false
positives across 460 local dumps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 11:14:44 +02:00
iceman1001andClaude Opus 5 82597a32c5 fix: don't treat a RATS NAK as a successful ISO14443-4 activation
iso14443a_select_cardEx() only rejected silence after RATS. A card that
answered with a 4 bit NAK came back as Demod.len == 1, was stored as a
one byte ATS and reported to the client as select status 1, meaning L4
activated. The client then sent GetVersion (90 60 00 00 00) as an I-block
to a card that never left ISO14443-3, and every caller ended with
'timeout while waiting for reply' / 'No tag detected or other tag
communication error (-4)'.

The bogus TL of 0x04 also made iso14a_set_ATS_times() look for a T0 and
read past the single received byte.

Check that the answer to RATS is a well formed ATS, TL plus the bytes TL
counts plus the two CRC bytes, before accepting it. Anything else returns
2, selected but ISO14443-3 only, so the card stays usable over the Classic
path instead of failing detection.

The client side 'try to request ATS even if the tag claims not to support
it' retry had the same hole and stored whatever came back in card.ats, so
guard all four copies of it the same way.

Reported on a clone with ATQA 0004 / SAK 28 that advertises ISO14443-4 it
does not implement. hf mf autopwn on it needed hf 14a config --rats skip
to get past detection; with this it takes the Classic path on its own.

Fixes #3659

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 11:05:07 +02:00
Iceman 983b466ca1 Merge pull request #3656 from 0x6r1an0y/20260922-15693magic-docs
Fill in the ISO15693 magic notes
2026-09-22 07:00:20 +07:00
Iceman be8a0d524e Merge pull request #3657 from 0x6r1an0y/20260922-makefile-fix
fix: preserve UTF-8 in generated command docs
2026-09-22 06:59:35 +07:00
Iceman 12899dc2e8 Merge pull request #3658 from Axi-ohm/fix/bigbuf-align-mask-32bit
BigBuf: widen BIGBUF_ALIGN_MASK to 32-bit for PM5
2026-09-22 06:57:56 +07:00
Axi-ohmandClaude Opus 4.8 3f8edc5563 BigBuf: widen BIGBUF_ALIGN_MASK to 32-bit for PM5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 18:34:23 -05:00
歐歪andOpenAI Codex 940f26ce37 build: centralize Python executable definition
Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-09-22 07:24:43 +08:00
歐歪 5360980b48 doc: 15693 wipe command would brick the v3 tag for now 2026-09-22 07:14:31 +08:00
iceman1001andClaude Opus 5 4cca8df3a0 hf mfu: support UL-AES in restore, fix info config output
restore refused UL-AES outright.  The generic page plan assumes the last
four pages are cfg0/cfg1/PWD/PACK, which on UL-AES are the AES keys, so
the data loop walked over the lock page, both config pages and the key
lock bits at 0x2D.  Give UL-AES its own plan: user memory 0x04..0x27,
and lock/cfg0/cfg1 behind -s.  Key pages 0x30..0x37 are left alone, the
dump only ever carries AESKey0 and 0x34..0x37 read back as zeros.

info never printed the UL-AES config.  ulaes_print_configuration() is
called with 0x29 but its first branch tested for 0x2C, so cfg0 and cfg1
fell through to the bare return and only the CMAC page showed up.

info also read page 0x34 as if it were an EV1 config page.  That is the
UIDRetrKey.  Genuine silicon NAKs the read, but a magic or simulated
card would have had its key printed as cfg0/cfg1/PWD/PACK.

Tested on a UL-AES with AUTH0=4, PROT set and secure messaging on.
Restore of an unmodified dump comes back byte identical; a dump carrying
DEADBEEF at 0x27 and CAFEBABE at 0x2B writes 0x27 and leaves 0x2B alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 00:23:02 +02:00
歐歪andOpenAI Codex 6775a78a10 fix: preserve UTF-8 in generated command docs
Transcode the MinGW client's CP850 output before writing command documentation and force Python to read the converted stream as UTF-8. Normalize the remaining escaped Greek mu strings to the project's micro sign convention.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-09-22 05:37:09 +08:00
歐歪 4ea8207400 doc: 15693 magic card 2026-09-22 04:32:14 +08:00
Philippe Teuwen 6150d8fc57 "Starting today in version 2.1.277, if there is no CLAUDE.md in a folder, Claude will check for and use AGENTS.md." 2026-09-19 21:02:32 +02:00
Jooyoung bdaaf9fd85 hf iclass view: surface unhandled SIO TLV tags in Insights
print_iclass_sio_decoded() silently dropped any TLV tag it did not
explicitly handle. Real credentials (e.g. SR) carry context tags such as
[5]/[9] that were therefore invisible in the Insights output, even though
the raw block dump and the --verbose ASN1 view showed them.

Print unhandled tags as 'Unknown tag 0xNN : <hex>' so the human-readable
Insights view is lossless. No semantic guessing is done; --verbose still
provides the full ASN1 TLV.
2026-09-19 02:22:01 -04:00
dxl 2c955d7deb Fixed bug on the PM5 platform where changing PM3_CMD_DATA_SIZE to a larger value broke compatibility for certain commands. 2026-09-18 21:56:29 +02:00
dxl d5ef826587 Before sending data via the SSC, it is best to ensure that the transmitter is ready (TX ready). 2026-09-18 21:56:29 +02:00
dxl 38e06eec5a Fixed a bug on the PM5 platform where an CSPAS error caused a SPI_SSC hang, resulting in random device freezes. 2026-09-18 21:56:29 +02:00
Philippe Teuwen 431f553bfa Fix ProxSpace CI for tagged commits
MSYS2 git fails with
C:\ProxSpace\msys2\usr\bin\git.exe rev-parse refs/tags/v4.23346^{commit}
  Error: fatal: ambiguous argument 'refs/tags/v4.23346^commit': unknown revision or path not in the working tr

GitHub's windows-latest hosted runner images ship with Git, so let's use it
2026-09-18 11:26:49 +02:00
Shawn Hoffman 3c1af8e077 ntag424: implement GetTTStatus and SetConfiguration
fix bug in changekey's keyversion param handling
2026-09-18 00:59:15 +02:00
Philippe Teuwen bed32b1458 standalone modes alphabetical order 2026-09-18 00:52:30 +02:00
Philippe Teuwen 731814f67d changelog 2026-09-18 00:23:52 +02:00
Philippe Teuwen e2acee8a85 Revert "Release v4.23346 - Frosty Lemon"
This reverts commit dc0110c29d.
2026-09-18 00:22:18 +02:00
Philippe Teuwen dc0110c29d Release v4.23346 - Frosty Lemon v4.23346 2026-09-18 00:22:18 +02:00
Philippe Teuwen 67f66ab3d9 prepare release 2026-09-18 00:21:27 +02:00
Philippe Teuwen 7822cbd8b1 silent gcc warnings on ARMHF architecture
The warnings are false-positive: resp.data is a union of uint8_t asBytes[] and uint32_t asDwords[], so the buffer is actually 4-byte aligned — but casting uint8_t* directly to a stricter-aligned struct pointer trips -Wcast-align. Fix by routing through (const void *)
2026-09-17 22:53:58 +02:00
Philippe Teuwen b3beffd59b docker tests 2026-09-17 22:48:34 +02:00
Philippe Teuwen afb55e196a Allow skipping setcap, to ease dockerized release tests 2026-09-17 16:59:19 +02:00
Philippe Teuwen 90c41c6de5 use arraylen 2026-09-17 00:23:18 +02:00
Mistial DeveloperandGPT-Daybreak Blue 8ed285af90 feat(desfire): add DFC credential interoperability
Add bidirectional conversion between DFC v4 credentials and mfdes v1 JSON, with documentation and round-trip coverage. Include H10301 FC69 CN420 factory and field fixtures and an external HID reader test target.

Co-Authored-By: GPT-Daybreak Blue <noreply@openai.com>
2026-09-17 00:08:06 +02:00
Mistial DeveloperandGPT-Daybreak Blue 957896a926 build(desfire): make emulator test hook optional
Exclude the USB test dispatcher and queued-random support from normal firmware builds. Enable them with ENABLE_HFMFDESETEST=1 when running emulator vectors.

Co-Authored-By: GPT-Daybreak Blue <noreply@openai.com>
2026-09-17 00:08:06 +02:00
Mistial DeveloperandGPT-Daybreak Blue 50f6b76469 feat(desfire): handle ISO 7816 selection in simulator
Recognize interindustry SELECT APDUs by DF name or file identifier and return card-compatible status words.

Co-Authored-By: GPT-Daybreak Blue <noreply@openai.com>
2026-09-17 00:08:06 +02:00
Mistial DeveloperandGPT-Daybreak Blue a8e347ddb9 fix(desfire): stabilize simulator RF exchanges
Constrain activation to supported bit rates, ignore invalid polling and frames, and follow independent ISO-DEP block sequences during recovery.

Co-Authored-By: GPT-Daybreak Blue <noreply@openai.com>
2026-09-17 00:08:06 +02:00
Mistial DeveloperandClaude Fable 5.1 2b35f40c95 hf mfdes sim: legacy secure messaging after a 0x0A authentication
A session opened with 0x0A kept the EV1 secure messaging: an 8 byte CMAC
on every answer, CRC32 in enciphered transfers and ChangeKey, one CBC
chain across commands. The legacy session is different in every one of
those: nothing on a plain answer, a 4 byte DES MAC over the data alone on
MACed transfers, CRC16 over the data in enciphered transfers and in the
ChangeKey cryptogram, the reader's cryptograms undone by enciphering, and
every cryptogram from a zero IV.

The session remembers which authentication opened it and the four places
that secure or check a transfer take the legacy path when it was 0x0A:
the write gatherer's expected length, the command unwrap, the answer
wrapping, and ChangeKey. Chained answers carry the transfer's mode so a
MACed read puts its MAC on the last frame only.

Measured against a genuine DESFire EV1 4K with the pm3 as reader, all
zero and non-zero DES keys, writes and reads in all three modes and a
ChangeKey of another key: the simulation answers every frame with the
card's bytes.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:14:07 +02:00
Mistial DeveloperandClaude Fable 5.1 49a19be247 hf mfdes sim: run the 0x0A legacy authentication the way a card does
The second frame of a 0x0A handshake was handled like 0x1A: the reader
token was deciphered in CBC with the IV chained from E(RndB), and RndA'
was enciphered with the IV chained from the token. A card starts each
legacy cryptogram from a zero IV and only ever enciphers, so it recovers
the token by enciphering each block and xoring the previous ciphertext
block.

The wrong IV only touches the token's first block, so RndB' still
verified and the simulation reported success with RndA off by E(RndB).
Session key and final frame were wrong from there, which is where the
D40 secure messaging captures started to disagree.

Measured against a genuine DESFire EV1 4K: the card's final frame is the
same across sessions with different RndB, which only a zero IV gives,
and the simulation's old answer matched the chained-IV arithmetic byte
for byte. Both handshake captures now replay through the simulation.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00
Mistial DeveloperandClaude Fable 5.1 fee9648b53 hf mfdes etest: place the command doc entry at top level, state the draw order
The regenerated `hf mfdes etest` object had been spliced inside the
`hf mfdes esave` object in doc/commands.json, so catalog consumers did
not see it. Moved by hand to its place among the commands, matching what
`make commands` produces for that entry.

Help and how-to said a recorded session replays byte for byte. It does
only when the queue is filled in draw order: the random UID takes 3 bytes
at --scan on a random-id image, then each authentication takes its RndB.
Say so.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00
Mistial DeveloperandClaude Fable 5.1 deab288804 hf mfdes etest: changelog and how-to
Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00
Mistial DeveloperandClaude Fable 5.1 2ff6b0fecd hf mfdes etest: drive the DESFire simulation from the host
One command with one action per call: --begin, --scan, --apdu <hex>,
--random <hex>, --fieldoff, --state, --end. Text output by default,
-j gives one line of JSON per call for a script to read back.

Distinct failures are reported as such: no image in emulator memory,
not activated (--scan first), random queue full, and a firmware that
does not answer.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00