CoreExtendedNFC
Swift package for NFC protocol-layer logic on iOS. CoreNFC handles RF transport; CoreExtendedNFC identifies cards, builds commands, models memory, reads passports, and exports dumps.
Capabilities
- Card identification from ATQA, SAK, ATS, FeliCa system code, ISO 15693 metadata, and ISO 7816 application hints, refined by safe probes (Ultralight C, NTAG210/212, DESFire EV1-EV3, FeliCa Lite / Lite-S).
- Memory operations for Ultralight, NTAG, DESFire (read-only), FeliCa Type 3, ISO 15693, and Type 4 NDEF tags, plus NTAG 424 DNA file settings (including SDM) and plain WriteData.
- Passport and eMRTD reading with PACE (ECDH Generic Mapping on NIST P-256/384/521 and Brainpool P-224 to P-512 curves) or BAC, Secure Messaging, data-group parsing, Passive Authentication against caller-supplied CSCA certificates, and Active Authentication.
- Transit-card readers for Japan IC, Hong Kong Octopus, Singapore CEPAS, China T-Union, and Korea KS X 6924 paths.
- Japan My Number card token reads, protected individual-number reads, and PIN-attempt lookup.
- Dump export to hex, JSON, Flipper NFC, Proxmark3 MFU, libnfc MFD, and raw binary, and import from Flipper NFC and Proxmark3 MFU.
Install
dependencies: [
.package(url: "https://github.com/Lakr233/CoreExtendedNFC.git", from: "2.1.0"),
],
targets: [
.target(name: "App", dependencies: [
.product(name: "CoreExtendedNFC", package: "CoreExtendedNFC"),
]),
]
Upgrading from 1.x? See Migrating to 2.0 and the changelog.
Quick Start
import CoreExtendedNFC
let (card, transport, session) = try await CoreExtendedNFC.scan()
print(card.type.description, card.uid.hexString)
session.invalidate()
let (info, dump) = try await CoreExtendedNFC.scanAndDump()
print(dump.exportHex())
let passport = try await CoreExtendedNFC.readPassport(
mrzKey: "L898902C<369080619406236",
dataGroups: [.com, .dg1, .dg2, .sod]
)
The package depends on openssl-spm for passport cryptography; SwiftPM resolves it automatically. Failures are thrown as NFCError; see Errors.
Supported Cards
| Family | Identify | Read | Write | Dump |
|---|---|---|---|---|
| MIFARE Ultralight / EV1 / C | yes | yes | yes | yes |
| NTAG 210 / 212 / 213 / 215 / 216 | yes | yes | yes | yes |
| MIFARE DESFire EV1-EV3 | yes | yes | no | free-access files |
| NTAG 424 DNA | as DESFire / Type 4 | file settings, NDEF | plain files | no |
| FeliCa Type 3 NDEF | yes | yes | yes | partial |
| ISO 15693 / Type 5 | yes | yes | yes | extended blocks when supported |
| Type 4 NDEF / ISO 7816 | yes | yes | yes | partial |
| eMRTD / ePassport | yes | yes | no | workflow-specific |
| My Number card | yes | yes | no | token data |
| MIFARE Classic 1K / 4K | yes | no | no | no |
MIFARE Classic is identification-only because iOS does not expose Crypto1 authentication (iOS cannot send the encrypted parity bits it needs). DESFire has no write API; NTAG 424 DNA has a plain (CommMode.Plain) WriteData only. ISO 15693 tags with more than 256 blocks are read with extended commands; tags that reject them are dumped up to block 255 and marked partially readable.
Next Steps
- GuideTask-oriented scanning, dump, NDEF, passport, transit, My Number, and Info.plist setup notes.
- API ReferencePublic Swift surface grouped by top-level API, card commands, models, and protocol helpers.
- Migrating to 2.0Upgrade checklist from 1.1.2 with before/after code, renamed functions, and the subclassing contract.
- Research NotesReal-card validation, iOS polling identifiers, transit-card findings, My Number data layout, and reference documents.