Skip to content

feat: NTAG 424 DNA plain file operations - #18

Merged
Lakr233 merged 3 commits into
mainfrom
feat/ntag424-dna
Oct 17, 2026
Merged

Lakr233 merged 3 commits into
mainfrom
feat/ntag424-dna

Conversation

@Lakr233

@Lakr233 Lakr233 commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Closes #14

Summary

New Cards/NTAG424 module for NTAG 424 DNA native file operations in CommMode.Plain, over the ISO 7816 wrapped transport (90 CMD 00 00 Lc data 00) with the NDEF application selected.

  • NTAG424Commands.getFileSettings(fileID:) — GetFileSettings F5h, parsed strictly into NTAG424FileSettings:
    • FileType, FileOption (communication mode, SDM bit 6), Read / Write / ReadWrite / Change access-right nibbles (also as AccessCondition), 24-bit file size.
    • SDM extension when enabled: SDMOptions, SDMAccessRights (SDMMetaRead bits 15-12, SDMFileRead 11-8, RFU 7-4, SDMCtrRet 3-0) and the conditional UID / SDMReadCtr / PICCData / TTStatus (NTAG 424 DNA TT) / SDMMACInput / SDMENC offset + length / SDMMAC / SDMReadCtrLimit fields.
    • Truncated responses, trailing bytes (e.g. a response MAC), non-StandardData file types and a reserved SDMMetaRead value throw invalidResponse.
  • NTAG424Commands.writeDataPlain(fileID:offset:data:chunkSize:) — native WriteData 8Dh (not DESFire 3Dh), 3-byte little-endian offset and length, split into chunks (default 111 bytes so each command fits one tearing-protected 128-byte ISO 14443-4 frame; max 248, the datasheet limit). Arguments are validated before anything is sent; the first non-9100 status stops the write.
  • Facades CoreExtendedNFC.getNTAG424FileSettings(fileID:transport:) and CoreExtendedNFC.writeNTAG424DataPlain(fileID:offset:data:chunkSize:transport:).
  • NTAG424Commands follows the access policy (open class, @unchecked Sendable, immutable state, open class func payload hook).

Out of scope: ChangeFileSettings / SDM provisioning, CommMode.MAC / Full, EV2 command counters and response-MAC verification.

Tests

  • NTAG424Tests.swift: MockTransport APDU framing, 24-bit LE ranges, chunking, status mapping, argument validation, every truncation, trailing bytes, reserved values.

  • Vectors/NTAG424VectorTests.swift: NXP AN12196 published vectors — GetFileSettings responses from Tables 7 and 18, the illustrative Table 10 response (rejected as truncated against its own SDMAccessRights), and the plain CC WriteData C-APDU from Table 24.

  • Vectors/NTAG424VectorTests.swift also covers the NT4H2421Tx TTStatusOffset layout.

  • DESFireDumpTests.swift: an NTAG 424 DNA reported as DESFire (GetApplicationIDs → 91 1C, GetVersion hardware type 04h, AN12196 Table 12 transcript) is dumped as a Type 4 tag; other chips still report the error.

Verified on the iOS Simulator: package tests (1081 tests, 72 suites) pass, Example app builds.

Review

Three review rounds, each finding fixed only after a test reproduced it:

  1. Against the NT4H2421Gx / NT4H2421Tx datasheets and AN12196, cross-checked with ten open-source implementations (proxmark3, BoltCardTools, Amperstrand/ntag424, …): fixed the SDMAccessRights nibble order (proven by the AN12196 vectors).
  2. Independent adversarial review: single-frame default chunk size (datasheet §10.8.2 tearing protection), facade precondition wording, counterRetrievalCondition.
  3. Comparison with closed-source readers (NXP TagInfo / TagWriter with the embedded NXP SDK, NFC TagInfo, NFC Tools): parser and WriteData framing match the NXP SDK field for field; added the TagTamper TTStatusOffset and the NTAG 424 dump fallback.

Not validated on hardware yet; the module is experimental.

Docs

Also DESFireVersionInfo.ntagHardwareType.
CHANGELOG (Unreleased), README support table and tree, docs/api/card-commands.html, docs/api/core.html, docs/architecture.html, docs/index.html, docs/research/references.html.

🤖 Generated with Claude Code

Add Cards/NTAG424 with NTAG 424 DNA native commands in CommMode.Plain:

- NTAG424Commands.getFileSettings(fileID:) sends GetFileSettings (F5h) and
  parses the response strictly into NTAG424FileSettings: file type, file
  option / communication mode, access-right nibbles, 24-bit file size and,
  when SDM is enabled, SDMOptions, SDMAccessRights and every offset the
  options and access rights make present. Truncated responses, trailing
  bytes (such as a response MAC), non-StandardData files and a reserved
  SDMMetaRead value throw invalidResponse.
- NTAG424Commands.writeDataPlain(fileID:offset:data:chunkSize:) sends the
  native WriteData 8Dh (not the DESFire 3Dh) with 3-byte little-endian
  offset and length, split into short-APDU chunks.
- Facades CoreExtendedNFC.getNTAG424FileSettings(fileID:transport:) and
  writeNTAG424DataPlain(fileID:offset:data:chunkSize:transport:).

SDMAccessRights is decoded as SDMMetaRead bits 15-12, SDMFileRead 11-8,
RFU 7-4, SDMCtrRet 3-0, checked against the NXP AN12196 GetFileSettings
(Tables 7, 10/11, 18) and plain WriteData (Table 24) vectors in
Vectors/NTAG424VectorTests.swift.

ChangeFileSettings / SDM provisioning, CommMode.MAC / Full and EV2 command
counters are out of scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lakr233 and others added 2 commits October 17, 2026 13:46
Review findings checked against NT4H2421Gx / NT4H2421Tx Rev. 3.0:

- Default WriteData chunk is now 111 bytes so each command fits one
  128-byte ISO/IEC 14443-4 frame (ATS T0 77h, CID supported). The datasheet
  only guarantees tearing protection within one frame (§10.8.2, §8.5); the
  old 128-byte default produced 141-byte APDUs that the reader chains.
  The 248-byte maximum (Table 81) is unchanged.
- GetFileSettings parses TTStatusOffset, present on NTAG 424 DNA TT when
  SDMOptions bit 3 is set, between PICCDataOffset and SDMMACInputOffset
  (NT4H2421Tx Table 73). Such responses used to be rejected.
- SDMAccessRights gains counterRetrievalCondition; doc comments note that
  SDMReadCtrOffset FFFFFFh means no counter mirroring and that SDMFileRead
  Eh is RFU but still makes the MAC offsets present.
- The writeNTAG424DataPlain doc now states the real precondition: without
  authentication the Write or ReadWrite access condition must be Eh; the
  file's CommMode only applies inside an authenticated session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NTAG 424 DNA shares DESFire's ATQA 0344h / SAK 20h, so iOS can report it
as a DESFire tag. It has no GetApplicationIDs (NT4H2421Gx Table 22) and
answers 91 1C (Table 23), which made dumpCard fail. When that happens and
GetVersion reports hardware type 04h (NTAG, Table 54) the tag is now
dumped through the Type 4 path; any other chip still reports the error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Lakr233
Lakr233 merged commit 46e8020 into main Oct 17, 2026
1 of 4 checks passed
@Lakr233 Lakr233 mentioned this pull request Oct 17, 2026
@Lakr233
Lakr233 deleted the feat/ntag424-dna branch October 17, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: add an NTAG 424 DNA module for native file operations

1 participant