Commit Graph
23362 Commits
Author SHA1 Message Date
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
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
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
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
Mistial DeveloperandClaude Fable 5.1 e588085c10 hf mfdes sim: host driven test hook with injectable randomness
The DESFire simulation could only be reached over the air. A conformance
suite that has recorded a genuine card's session needs to replay it byte
for byte, which takes two things the simulation did not have: a way in
over USB, and control of the card's random draws.

CMD_HF_DESFIRE_SIM_TEST carries one operation per packet into the same
state machine the RF loop drives: BEGIN, SCAN, APDU, RANDOM, FIELDOFF,
STATE, END. SCAN runs the RF-reset path (init, reset, random id, FSD) and
APDU goes through desfire_sim_apdu(), so native and ISO 7816 wrapped
commands answer exactly as they do on air. No FPGA involvement.

Randomness goes through a small host-fed byte queue: RndB and the random
id draw from it first and fall back to the existing fixed value or tick
counter when it is short, raising a sticky underflow flag. With nothing
queued the RF simulation is byte-identical to before; SimulateDesfireTag()
clears the queue so a host session cannot leak into a reader session.

Co-Authored-By: Claude Fable 5.1 (claude-fable-5-1) <noreply@anthropic.com>
2026-09-16 22:04:01 +02:00
CinderSocketandgpt-daybreak-blue 71b558d6be usb: consume zero-length OUT packets and already buffered commands
A transfer whose size is an exact multiple of the endpoint size ends with
a zero-length packet. Nothing acknowledged it, so that receive bank stayed
selected and data queued in the other bank stalled. A command already
buffered by usb_read_ng was also not recognised until another packet came
in. Both AT91 and AT32 reuse their receive cleanup to acknowledge the empty
packet and rearm reception; frame parsing is unchanged.

Seen as a small packet lost now and then right behind a burst of
CMD_HF_MIFARE_EML_MEMSET chunks from `hf mfdes eload`.

(cherry picked from cindersocket/proxmark3 495bc201d, upstream PR #3628)

Co-Authored-By: gpt-daybreak-blue <noreply@openai.com>
2026-09-16 22:04:01 +02:00
Philippe Teuwen 1d887fa869 make miscchecks 2026-09-16 19:06:43 +02:00
Philippe Teuwen 634edd11fd make style 2026-09-16 19:00:50 +02:00
iceman1001 f1e71c5b69 ulaes config fix 2026-09-16 18:58:42 +02:00
iceman1001 34c68fd347 ulaes print conf correct 2026-09-16 17:36:46 +02:00
iceman1001 f76ae2b3f2 fix more stabilty issues with NULL checks and leaving values after REALLOC 2026-09-16 13:58:20 +02:00
iceman1001 5318069ccf fix potential unstability with proper NULL checks 2026-09-16 13:56:02 +02:00
iceman1001andClaude Opus 5 57b30c44e1 hf mfdes chk: check every key the app declares, and stop miscounting dictionaries
Three things behind a scan that ran against one application, printed its check
line twice, and then said nothing at all.

The dictionary loader was truncating rather than rejecting. 'loadFileDICTIONARYEx'
null terminated each line at the requested key length and only skipped lines that
came out too short, so any line holding more hex than asked for was silently cut
down and taken as a key. Reading 'mfdes_default_keys' for DES keys turned all 47
of its 32-hex AES lines and all 4 of its 48-hex 3K3DES lines into 8-byte keys that
are on no card, reporting 58 DES keys where the file holds 7. It now skips a line
whose hex run is longer than the key being asked for, which is what its sibling
'loadFileDICTIONARY_safe_ex' has always done. A trailing comment or whitespace
after the key is still fine, so the bundled dictionaries keep working. Counts for
that file go from 58/51/4 to 7/47/4, and mfc, iclass, mfp and t55xx are unchanged.

The key numbers to check came only from file access rights. An application with
three keys whose files name just key 1 had key 2 left out of the sweep entirely,
even though the card had already said how many keys it holds. Key settings carry
that count in the low nibble, so chk reads it and checks every key number the
application declares, the same sweep 'hf mfdes detect' already does. On a test
card this immediately turned up an AES key 2 still at the factory default, which
no file pointed at and which the old code could never have found. The access
rights walk stays as the fallback for when key settings are not readable, which
also means the common path no longer spends a file list round trip.

And the last round of a chunked dictionary read comes back empty. That empty list
was still handed to AuthCheckDesfire, which selected the application, read its key
settings, probed for LRP and listed its files in order to then check no keys at
all, printing a second identical check line on the way. Skipped now.

Finally, a scan that found nothing printed nothing. In non verbose mode all that
was left was a blank line, itself a leftover from the progress markers removed in
d842c7e5. It says so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:12:11 +02:00
iceman1001andClaude Opus 5 00aabd7443 hf mfu chk: one dictionary check that detects UL-C or UL-AES
hf mfu cchk and hf mfu aeschk were the same command twice. Ninety lines of
dictionary loading and chunked device calls were duplicated, and the only
real difference was which key slot they targeted: aeschk took --idx, cchk
hardcoded the Ultralight C slot. Both are replaced by hf mfu chk, which
reads the tag type off the card with GetHF14AMfU_Type() and picks the slot
itself. Ultralight AES still honours --idx, 0 DataProtKey, 1 UIDRetrKey,
2 OriginalityKey. Ultralight C holds a single key, so --idx is rejected
there rather than silently ignored. Any other tag is refused with a pointer
to hf mfu info.

Without -f the dictionary is mfulc_default_keys.dic for both tag types. A
segment check keeps needing an explicit -f, because the segment dictionaries
hold four byte keys and the default one does not. aeschk used to advertise
mfulaes_default_keys.dic in its help, which has never been shipped.

Collapsing the two bodies also fixes --retries. firstChunk and lastChunk
were declared outside the retry loop and never reset, so only the first pass
was correct. From the second pass on, every chunk went out with firstchunk
clear and lastchunk set, which on the device side means no select and a
field teardown after each chunk, against a field the previous pass had
already dropped. They are now scoped to the pass.

client/pyscripts/mfulaes_mask_recovery.py called aeschk and now calls chk.
doc/commands.md and doc/commands.json are regenerated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 12:40:47 +02:00
iceman1001 60eca59fee text 2026-09-16 11:43:36 +02:00
iceman1001 60e71e1d3d hf 14b dump: run the MyKey parser on a card read, not just a file 2026-09-16 11:33:42 +02:00
iceman1001 99020b0297 fix cppcheck warning 2026-09-16 11:26:16 +02:00
iceman1001 9aca3be176 silence cppwarning dead code 2026-09-16 11:00:31 +02:00
iceman1001andClaude Opus 5 e648438306 hf 14b view: decode MyKey / COGES keys on SRIX4K
The SRIX4K block scrambler in cmdhf14b.c was a three entry lookup table with
its callers commented out, so `hf 14b valid` printed hard coded values and
nothing ever decoded. The scrambler is a 4x4 transpose of the block read as
sixteen crumbs. A transpose is its own inverse and it reproduces all three
entries of the old table, so the stub is replaced by a working parser.

client/src/parsers/parsemykey.c reads the application off a dump: key id,
production date, operations counter, vendor code, lock id, current and
previous credit, and the eight slot transaction ring. Every block carries a
checksum in its top byte and the parser reports how many hold up, which
catches a wrong UID or a torn write. The credit blocks are XORed with a
session key derived from the UID, the vendor code and the count down counter
in block 6, so the file name has to carry the UID.

`hf 14b valid` is removed. Checking that the maths holds is now
`hf 14b view --selftest`, following `hf mf view --selftest`, and it runs
against traces/hf-14b-D0021F673CB26556-dump.json, a dump of a real reset key.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 10:58:57 +02:00
iceman1001 199c3f107c fix image too large for 256kb devices by adding guards 2026-09-16 10:32:48 +02:00
iceman1001 6e25742606 fix build, removing unused var 2026-09-16 08:49:32 +02:00
Iceman ffb62a22e7 Merge pull request #3635 from Antiklesys/master
Update frame_data2.c
2026-09-16 13:46:58 +07:00
Antiklesys 1dc2ec25e9 Update frame_data2.c 2026-09-16 12:04:13 +08:00
iceman1001 f66632e288 text 2026-09-16 02:44:53 +02:00