Skip to content

[NFC] Fix MIFARE Plus 2K SL1 transit parsers (#1037)#1038

Merged
mishamyte merged 2 commits into
devfrom
bug/1037-plus-2k-sl1-parsers
Jul 15, 2026
Merged

[NFC] Fix MIFARE Plus 2K SL1 transit parsers (#1037)#1038
mishamyte merged 2 commits into
devfrom
bug/1037-plus-2k-sl1-parsers

Conversation

@mishamyte

Copy link
Copy Markdown
Member

Summary

Fixes #1037. After #1016 introduced MfClassicType2k and promoted genuine MIFARE Plus S/X 2K cards in SL1 (SAK 0x08 + Plus ATS) from MfClassicType1k, the supported-card parsers for those cards broke.

Root cause

  1. Type gate*_get_card_config() / type-branched extraction accepted only 1K/4K, so parse() rejected 2K (plantain, troika).
  2. Full-read completionmf_classic_is_card_read() needs 32 sectors/64 keys for 2K (was 16/32). A targeted read() keying only its own sectors returns MfClassicErrorPartialReadis_read=false → the app diverts to the dict-attack scene and never reaches parse() (sevppk, szppk_so, two_cities).

Fix

Treat MfClassicType2k as the Classic 1K these cards present (same lower-sector keys/data sector) and accept a partial read:

  • plantain — 2K case in get_card_config + extract_purse_data; accept PartialRead
  • troika — 2K case in get_card_config; accept PartialRead
  • sevppk_tk, szppk_so, two_cities — accept PartialRead (parse is type-independent)

social_moscow/kazan (plain Classic) and sk_tk (4K) aren't promoted to 2K → unchanged.

Testing

fbt fap_{plantain,troika,szppk_so,two_cities,sev_tk}_parser builds clean. On-hardware validation with real cards still pending.

Closes #1037

🤖 Generated with Claude Code

After #1016 promoted genuine MIFARE Plus S/X 2K cards in SL1 (SAK 0x08 +
Plus ATS) from MfClassicType1k to the new MfClassicType2k, the supported-
card parsers for those cards stopped working:

- Type gates (get_card_config / extract_purse_data) knew only 1K/4K, so
  parse() rejected 2K -- plantain, troika.
- mf_classic_is_card_read() now needs all 32 sectors / 64 keys for a 2K
  card, so a targeted read() that keys only its own sectors returns
  MfClassicErrorPartialRead -> is_read = false -> the app diverts to the
  dict-attack scene and never reaches parse() -- sevppk, szppk_so,
  two_cities (and the above).

Handle MfClassicType2k explicitly as the Classic 1K these cards present
(same lower-sector keys / data sector), and accept a partial read in the
plugins' read() so parse() runs and validates the key.

social_moscow / kazan (plain Classic) and sk_tk (4K) are not promoted to
2K and are left unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mishamyte
mishamyte requested a review from xMasterX as a code owner July 15, 2026 18:59
@github-actions github-actions Bot added the area/nfc Related to the nfc subsystem label Jul 15, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🤖 Build & analyze — bug-1037-plus-2k-sl1-parsers @ bfaa4950

Firmware built — artifact unleashed-fw-bug-1037-plus-2k-sl1-parsers-bfaa4950 (run)

💾 Flash & RAM — f7 (ble_light)

Metric Size
Firmware (flash) 855.17 KiB
DFU image 855.47 KiB
Reserved — radio stack + FUS 164.00 KiB
Free flash (usable) 4.83 KiB ⚠️
RAM (.data + .bss) 7.94 KiB

1 MiB flash = firmware + usable free + radio/FUS. The BLE coprocessor stack sits at the top of flash (load addr 0x080D7000); the linker's .free_flash (168.83 KiB) counts that region as free, so usable free = .free_flash − reserved (164.00 KiB).

📋 Public API changes

✅ No public API changes in this PR.

@mishamyte
mishamyte merged commit 3dcdb35 into dev Jul 15, 2026
2 checks passed
@mishamyte
mishamyte deleted the bug/1037-plus-2k-sl1-parsers branch July 15, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/nfc Related to the nfc subsystem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NFC] MIFARE Plus 2K SL1 transit parsers broken after MfClassicType2k (#1016)

1 participant