Commit Graph
1448 Commits
Author SHA1 Message Date
iceman1001andClaude Opus 5 (1M context) ee2d55fafb hf mfdes: put a DESFire card image in emulator memory
Adds the on-device card image a DESFire simulation will read, the client
side that packs a dump into it, and eload / esave / eview.

The layout is in include/desfire_em.h. Tables grow up from the header,
file data grows down from the end, and an allocation only has to leave
the two frontiers apart -- so a three-file card spends a few hundred
bytes rather than a worst case, and the space between them is what the
card has left. The PICC is application 000000 and uses the same struct
as any other application, so key settings and keys are always stated
against an AID. Delete sets a tombstone rather than compacting, which is
not a shortcut: a real card does not reclaim on delete either, measured
as 2080 bytes free with zero applications before an experiment and 2560
after FormatPICC.

Two size limits, and a reader only ever sees the first. cardsize is what
the emulated card claims to hold, so GetFreeMem answers from that and
CreateFile will refuse with OUT_OF_EEPROM when it runs out. Without it a
card impersonating a 2K part would report 7434 bytes free, which no 2K
part does. The image size is what emulator memory physically holds, is
the harder limit, and is never visible.

cardsize is anchored to the free memory the real card reported when the
dump was taken -- observed free plus what we reserve for the same content
-- so the emulation answers what its original answered. That is also a
check on the reservation rule rather than only a convenience: for the
bench card it computed 576 bytes spent, and 1984 + 576 is 2560, exactly
what that card reports when formatted.

Reservation follows what CommitTransaction covers. Backup data, value and
record files each get a shadow region because writes to them are staged
until commit; a standard data file writes through and does not. Sizes
round to a 32 byte granule, which is the granule a real card allocates in.
It deliberately does not reproduce NXP's allocator -- that is
undocumented and does not fit a simple model, a declared 1024 byte record
file costs 1088 on silicon -- so what matters is that the figure is
self-consistent and shrinks as the reader writes.

No new device command. Emulator memory is one shared region, so
CMD_HF_MIFARE_EML_MEMSET and BIG_BUF_EML already reach it, and both
inherit the bounds checking those paths gained earlier.

Verified with the client only, no simulation yet: packing a dump taken
from a DESFire EV2 and walking it back reproduces every field including
file contents byte for byte, the same round trip through the device via
eload and esave is identical, and an image too large is refused by name
rather than truncated -- 'Out of emulator memory laying out AID 112233
file 00: needs 4066 more bytes'.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-14 19:48:45 +02:00
iceman1001 c0792409b0 update samples 2026-09-14 19:36:28 +02:00
iceman1001andClaude Opus 5 (1M context) 8fd9bcbebc hf mfdes: dump a whole card to json, and view it back
'hf mfdes dump' walked one application and printed it. It now walks
every application on the PICC, keeps what it reads, and saves a
'hf-mfdes-<UID>-dump.json' card image. '--aid' / '--isoid' / '--dfname'
still narrow it to one application, '--ns' skips the save.

The format is 'mfdes v1', written and read in fileutils.c and documented
in doc/mfdes_dump_format.md. Two decisions worth stating:

 - The PICC level is application 000000, so every key in the file says
   which AID it opens. Key version and key value are separate: a version
   with no key is the normal shape for a key that was found but never
   recovered, and a missing key never means the key is zero.

 - Every file carries a 'Read' flag. A file whose contents could not be
   fetched is recorded as unread with no data at all, rather than as a
   run of zeros. A simulator built on this must not confuse '8 bytes of
   00' with 'we could not read 8 bytes'.

'hf mfdes view -f <fn>' prints such a file with no device attached.

With no '--keys', the dump looks for 'hf-mfdes-<UID>-keys.json' by
itself, so a 'hf mfdes chk -j' run is picked up on the next dump without
naming the file again.

Two fixes fell out of testing against a DESFire EV2:

 - DesfireSetKey() calls DesfireClearContext(), which wipes command set,
   comm mode, KDF and UID, not just the key. Swapping in a per-application
   key that way left the context at 'Communication mode: n/a' and
   DesfireFillFileList() then returned junk file ids. Use
   DesfireSetKeyNoClear().

 - GetVersion and the originality signature are answered unauthenticated.
   Asking for them from inside the authenticated session produced a
   'Wrong communication mode' warning and a run of MAC mismatches.

hex_to_buffer() treats hex_max_len as a byte count while every sprint_hex*
caller passes sizeof(buf) - 1, a character count, so it writes two or
three times the buffer size. Measured, sprint_hex_inrow overflowed at
4098 input bytes. Doubling UTIL_BUFFER_SIZE_SPRINT to 16384 moves that to
8192; the mixed semantics still need auditing across ~30 call sites.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-14 09:11:38 +02:00
iceman1001 66dbf6ac5c update 2026-09-14 09:03:57 +02:00
iceman1001 48d779261a the new dump format for desfire cards 2026-09-14 08:37:00 +02:00
iceman1001 8e3c439358 text 2026-09-12 21:50:19 +02:00
iceman1001andClaude Opus 5 (1M context) 255576fa43 make hf 14a antifuzz actually reach a reader
Every answer was modulated after the reader's frame arrived, landing
~1812 carrier periods late against the 1172 the FDT allows, so readers
timed out before any of it mattered. All answers are now precomputed the
way hf 14a sim does it, and a phone answers at 1172 exactly.

Cascade mode sent a cascade tag at every level, which a conforming reader
rejects in the last level its ATQA announced - it dropped the card before
ever sending a SELECT. The cascade tag now appears only below that level;
it is the SAK that lies about the UID being incomplete, and that is what
walks a reader up to cascade level 7.

A bit oriented ANTICOLLISION was answered with the whole UID instead of
the bits the reader still lacked, handing it a frame of the wrong length.
One encoder now builds any tail, with or without collisions in it.

--coll leaves the first UID byte clean and collides every bit after it, so
a reader resolves 24 bits one round trip at a time, is then given a BCC
that checks out, and is cascaded into the same again - 183 answers per
poll against the 3 a real card needs. Colliding byte 0 as well only
produced a UID of all ones, which readers drop before asking for the BCC.

Reader frames that go unanswered are traced instead of silently dropped,
LED B marks an attempt in progress and LED C flips on each step deeper,
and the closing line reports rounds run and how far a reader got.

trace list -t 14a decodes SEL 0x99..0x9F, shows how many UID bits a bit
oriented ANTICOLL claims, and no longer flags those CRC-less frames as
bad CRC.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-12 21:18:26 +02:00
iceman1001 cb75a05553 text 2026-09-12 15:14:13 +02:00
iceman1001andClaude Opus 5 (1M context) a967560335 hf thinfilm sim - shorter frame gap
The inter frame delay was 3600us for a 128 bit payload and 2400us for 256 bit,
sized so that either one holds a constant 4.8ms repeat period.  That is the wrong
target.  A Kovio tag is never transacted with - the reader captures it during a
poll slot and hands the bytes up as an activation, see
nfa_dm_disc_handle_kovio_activation() in libnfc-nci, which reads the barcode
straight out of rf_tech_param.param.pk.uid - so the only thing that matters is how often a frame is on the air.

Measured repeat period before today was 8.66ms, ie 14% duty cycle.  A fixed 500us
gap takes a 128 bit payload to roughly 2.2ms.  The gap cannot go to zero, a reader
needs unmodulated carrier to find the frame start and our own demod wants three
quiet bytes, but 500us is an order of magnitude clear of that.

Also drop the 'not correct' caveat from 'hf thinfilm list', the sim side traces
properly now.

Tested on RDV4 against an Android reader.  Builds clean for PM3RDV4 and PM5.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-12 14:17:13 +02:00
Niel Nielsen 443b2d8fc8 Document 'hw bwm name' command for BLE name management
Added documentation for the 'hw bwm name' command, detailing how to get and set the BLE advertising name, including usage examples and notes on behavior during name changes.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-12 13:45:14 +02:00
iceman1001andClaude Opus 5 (1M context) 67c121f554 hf mfdes detect: sweep all key numbers, and count errors per key type
errcount was declared before the key type loop and only reset by a
non -11 result, so eleven scattered card errors during the DES pass left
the AES pass to break on its first error without trying a key.  Count
per key type instead.

With no -n, detect only ever looked at key 0.  Sweep the key numbers the
application declares (low nibble of the key settings) instead, falling
back to 0x00..0x0D when the settings are unreadable.  All keys in an
application share an algo, so the first key number that succeeds narrows
keytypes[] for the rest.  --save now stores the first key found rather
than whatever dctx was left holding, and a lost card aborts the sweep.

-n <num> behaves exactly as before.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-11 15:15:36 +02:00
iceman1001andClaude Opus 5 (1M context) cec0e800ab hf mfdes chk: detect the secure channel per application
secureChannel was the constant DACEV1, and there was no way to override
it, so a card in LRP mode could never be authenticated - chk reported no
keys on a card 'hf mfdes detect' handles fine.  When the key settings
were unreadable it gave up instead of probing.

Work the channel out per AID: the key settings give the algo, and for an
AES app one AuthenticateLRPFirst probe separates EV1/EV2 from LRP, which
the settings byte cannot.  When the settings are unreadable, fall back to
DesfireCheckAuthCommands() the way detect does.  --schann d40|ev1|ev2|lrp
pins it and skips detection.  Only AES is tried on an LRP channel.

Also clear the session after a found key, so the next key number starts a
first auth rather than an EV2/LRP non-first one.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-11 11:08:45 +02:00
iceman1001 2610d0cfc2 text 2026-09-11 10:42:33 +02:00
Innocent Bystander 1457a5d827 Add verbage to make flashing the BWM clearer 2026-09-10 01:17:06 -04:00
Innocent Bystander b3123d153f Adding BWM Flashing instructions to PM5 Documentation 2026-09-09 21:14:26 -04:00
Iceman 9f641c3ced Merge pull request #3427 from Sanduuz/feature/st25ta_ndef_sim
Added support for emulating ST25TA tag (IKEA Rothult) with custom NDEF response
2026-09-07 15:38:46 +07:00
Iceman e807ef0df7 Merge pull request #3497 from 0x6r1an0y/20260823-uscuiddoc
Update USCUID section in magic_cards_notes
2026-09-07 15:31:12 +07:00
xilni 342cc37cca docs(bwm): fix stale hw bwm command references 2026-09-07 00:07:07 -04:00
Iceman 45c1d79282 Merge branch 'master' into 20260823-mfuformat
Signed-off-by: Iceman <iceman@iuse.se>
2026-09-06 21:00:13 +07:00
Niel Nielsen 9dfc7aacf4 Refactor command syntax in PM5-BWM-USAGE.md
Updated command syntax and formatting for clarity.

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
2026-09-05 10:10:48 +02:00
歐歪 7bfd6b6189 docs: content clean up 2026-09-05 05:18:51 +08:00
Philippe Teuwen 47d0a8fa00 typo 2026-09-04 19:59:40 +02:00
iceman1001 1a34aac8df texts 2026-09-04 13:32:54 +02:00
Msprg d3bf03f3e3 Docs: Add PM5 BWM BLE connection instructions 2026-09-03 01:41:54 +02:00
Innocent Bystander 22fcbf60c9 Fold more PM5 exclusive resources into the PM5_Start_Here folder to speed up finding information. 2026-09-01 20:28:59 -04:00
Innocent Bystander 85b225b2c4 Changing the DFU Util section to better reflect the shortest path to recovery. 2026-09-01 20:11:02 -04:00
Philippe Teuwen 38e0c068d9 A few less hardcoded 40000 samples 2026-09-01 19:54:05 +02:00
Philippe Teuwen 18aed4eaa4 spurious hidden char 2026-09-01 14:09:49 +02:00
Philippe Teuwen 3ed5792b23 fix doc link 2026-09-01 14:07:12 +02:00
DJ Eric James bc7f0716a1 fixes 2026-08-31 23:42:38 -04:00
DJ Eric James aa189ca70c move files a bit. 2026-08-31 23:40:48 -04:00
DJ Eric James 1b4ac29a1e move files a bit. 2026-08-31 23:40:24 -04:00
DJ Eric James bfb7307216 fixes 2026-08-31 23:37:13 -04:00
DJ Eric James 7510e4faa5 fixes 2026-08-31 23:35:52 -04:00
DJ Eric James c5a67dad5f fixes 2026-08-31 23:32:59 -04:00
DJ Eric James c7915c5b83 fixes 2026-08-31 23:30:54 -04:00
DJ Eric James ab4ec63efd fixes 2026-08-31 23:29:08 -04:00
DJ Eric James 27dcb6a63c fixes 2026-08-31 23:25:55 -04:00
DJ Eric James cdf4a097bc fixes 2026-08-31 23:25:03 -04:00
DJ Eric James 4c454f387b fixes 2026-08-31 23:24:06 -04:00
DJ Eric James 50ee709954 fixes 2026-08-31 23:22:52 -04:00
DJ Eric James 7899b560a1 fixes 2026-08-31 23:19:59 -04:00
DJ Eric James b1de4b52c1 fixes 2026-08-31 23:19:03 -04:00
DJ Eric James bf230b4db4 fixes 2026-08-31 23:18:00 -04:00
DJ Eric James 6b12579546 fixes 2026-08-31 23:15:39 -04:00
DJ Eric James 52686ab6d2 fixes 2026-08-31 23:14:39 -04:00
DJ Eric James 5649bb268d fixes 2026-08-31 23:13:57 -04:00
DJ Eric James 399afc31a2 fixes 2026-08-31 20:40:58 -04:00
DJ Eric James b80be3cbf8 restructure document 2026-08-31 20:14:52 -04:00
DJ Eric James 243f1a0861 docu2 2026-08-31 19:09:36 -04:00