lf t55xx dump: when lf t55xx detect has already recovered and confirmed
the password, T55xxReadBlockEx now trusts that session config instead of
re-probing the config block unauthenticated. A password-gated tag does
not answer that probe, so 'dump -p' failed its safety check on every
block and demanded --override; it now reads directly.
lf t55xx p1detect / lf search: the page-1 trace fingerprint hardcoded
Atmel's manufacturer byte (0x15/0x39) into a 16-bit preamble, so a valid
T5577 clone with another manufacturer (e.g. Tendyron 0x65) was rejected.
The duplicated atmel/silicon checks are collapsed into
t55xx_trace_preamble_match(), which also matches the bare 8-bit ACL 0xE0
- the same anchor lf t55xx trace decodes against.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When no sector key was known, autopwn probed for a static encrypted
nonce using the default key FFFFFFFFFFFF. On a FM11RF08S with
non-default keys that auth fails, the probe returns NONCE_FAIL, and
autopwn fell through to darkside/nested instead of the sen recovery.
The later re-detections are gated on known_key, so nothing recovered it.
Probe the known Fudan backdoor keys first, as 'hf mf info' and
'hf mf sen' already do, and run the detection with MF_KEY_BD. The
default key stays as the fallback for cards without a backdoor.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`hf mfu dump -k` appends the authentication key to the dump file, but
`view` never showed it. The key was there in the hex listing all along,
split across four pages and byte-swapped, which is not something you read
off the screen.
With `-v`, view now prints it. UL-C takes pages 0x2C..0x2F, UL-AES pages
0x30..0x33, and both are unswapped back into the form `-k` expects, so the
printed line can be pasted straight into the next command. The existing
ulc_print_3deskey() does the UL-C side; ulaes_print_key() is its UL-AES
sibling.
Tag type comes from the dump header rather than a card: the three UL-AES
version signatures that ul_select_card() matches on a live tag, and for
UL-C, which answers no GET_VERSION, all-zero version bytes plus a page
count of 0x2F. Key pages that are all zero say so and point at `dump -k`,
since a dump taken without a key legitimately has none.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`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>
`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>
`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>
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>
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>
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>
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>
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>
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>
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.
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