Looks like either I, or someone else, has never thought about encrypted mode enforcement in mfpreadsector.
Now during readouts data is decrypted on the fly.
Checked on real tag.
Signed-off-by: team-orangeBlue <63470411+team-orangeBlue@users.noreply.github.com>
Currently there is no bounds checking on the to send buffer which
results in larger requests overflowing the buffer and corrupting the
CRC. This fixes that by adding bounds checking. It also increases
DYNAMIC_MODULATION_BUFFER2_SIZE to support frames up to 256 bytes
Issue origin:
Commit 6b7665ed5 "Added live fc/cn update to hf iclass tagsim" added a data_available() poll inside the per-byte DMA loop of GetIso15693CommandFromReader so the ARM could drop out of RF-listen and process live emulator updates.
Before that commit, that tight loop had no USB poll at all — only gotFrame / BUTTON_PRESS / WDT_HIT. Verified via git show 6b7665ed5^:armsrc/iso15693.c.
Why it shows up on sim -t 3/6/7: those are the FULL sim modes that share do_iclass_simulation. Between reader commands the decoder sits in STATE_READER_UNSYNCD, so the gated poll at iso15693.c:1570-1575 fires every byte (reading UDP peripheral registers). With DMA filling at ~1 byte / ~19 µs, the added USB register reads plus jitter occasionally push the CPU past the 90% lag threshold → behindBy 461 with DMA_BUFFER_SIZE=512.
Commit fb8f94fa2 narrowed the gate to UNSYNCD to stop mid-frame exits, but the per-byte poll itself is still what's new on that path.
Fix:
New mode constant in include/iclass_cmd.h:
#define ICLASS_SIM_MODE_FULL_LIVE 8 // FULL + allow USB interrupt for live emul updates
Treat it identically to ICLASS_SIM_MODE_FULL everywhere except for the poll gate.
Add a flag param to GetIso15693CommandFromReader — e.g. bool allow_usb_interrupt in iso15693.c:1495 and iso15693.h:42. Wrap the poll:
if (allow_usb_interrupt &&
(dr->state == STATE_READER_UNSYNCD ||
dr->state == STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF) &&
data_available()) { ... }
Pass true only for live mode in do_iclass_simulation iclass.c:502:
bool live = (simulationMode == ICLASS_SIM_MODE_FULL_LIVE);
len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time, live);
The len == -2 drain block stays but becomes dead code for non-live modes (never returns -2).
Client side: cmdhficlass.c:1687 (CmdHFiClassTagSim) sends ICLASS_SIM_MODE_FULL_LIVE. CmdHFiClassSim -t 3/6/7 keeps sending ICLASS_SIM_MODE_FULL / _GLITCH / _GLITCH_KEY.
Other callers (iso15693.c:2270, iclass.c:1121 = reader-attack sim) pass false.
Result:
hf iclass sim -t 3/6/7 → byte-inner loop is back to its pre-tagsim shape → no blow-buffer abort.
hf iclass tagsim → keeps live update ability; still has the overhead, but that's the trade-off the feature needs.
Imported updates from legbrute hashcat modules to speed up hf iclass legbrute
1. Bitslicing — biggest win (~32×)
Kernel stores each cipher register (l, r, b, t) as 32 parallel 1-bit lanes in u32s (m64000_a3-pure.cl:147-201, bs_iclass_tick) and computes 32 MACs per tick. The CPU doMAC_brute does 1 at a time. A 64-bit bitslice port would give ~64× per core; AVX2 gets 256×. This is the single largest speedup lever.
2. Early-reject after 8 output ticks
In m64000_sxx (m64000_a3-pure.cl:534-535) the kernel breaks out as soon as the first MAC byte can't match. doMAC_brute always produces the full 32 output bits before memcmp. Comparing byte-by-byte as bits are produced saves ~3× on the output phase since 255/256 keys fail after byte 0.
3. Pre-expanded y_ccnr bit array
Kernel expands the 96 input bits into a flat array once (m64000_a3-pure.cl:239-247) and reuses it for every candidate. suc_bytes in cipher.c:181 re-does b >>= 1 shifts for every key. Pre-expanding lets the inner loop be branch-free and vectorizable.
4. Widen lanes to 256/512 via AVX2/AVX-512. The bitslice code is written against a single uint64_t lane type — swapping for __m256i/__m512i (or an abstracted bs_word_t) gives 4×/8× throughput on hosts that support it, with scalar u64 fallback on ARM/older x86. NEON gives 2× for ARM.