I have a Flutter app with NTAG 424 SDM (SUN) support.
On the Flutter side I only call a MethodChannel (readTagUrl) and receive a tagData map back.
All the real SDM / crypto work is done on the native side (Android now, and I want the same on iOS).
Android (already working, native side):
On Android I do all logic in MainActivity (Kotlin):
Read NDEF URL
Extract picc_data and cmac from the URL
Decrypt picc_data with my AES key to get:
PICC UID
Read counter
Verify the CMAC with the same key
Compare decrypted UID with tag.id (raw NFC tag UID)
Send the result back to Flutter as a map
Core Android logic (simplified, key removed):
val tagIdHex1 = bytesToHex(tag.id) // raw NFC tag UID
val piccData = PiccData.decodeFromEncryptedBytes(
Utils.hexStringToByteArray(piccDataHex),
oneAESKey,
false
)
val uidHex = bytesToHex(piccData.uid) // decrypted PICC UID
val counter = piccData.readCounter
val tagIdHex = bytesToHex(tag.id)
val isUidValid = uidHex.equals(tagIdHex, ignoreCase = true)
piccData.setMacFileKey(oneAESKey)
val isValid = piccData.performShortCMAC(null)
.contentEquals(Utils.hexStringToByteArray(cmacHex))
From Android I send back to Flutter:
tag_id (raw tag UID)
picc_encrypted
cmac
uid (decrypted UID)
counter
cmac_valid
full_url
iOS (current native side):
On iOS I have started implementing the native side in AppDelegate.swift:
Using NFCNDEFReaderSession to read the NDEF URI
I parse picc_data, cmac, and full_url from the URL
I send a map back to Flutter via MethodChannel("ntag424/sun") and readTagUrl
Right now, the map I send from iOS looks like:
[
"tag_id": "", // empty for now
"picc_encrypted": piccDataHex,
"cmac": cmacHex,
"uid": "", // not decrypted on iOS yet
"counter": 0,
"cmac_valid": false,
"full_url": url
]
So on iOS I only do URL parsing.
I do not yet:
get a raw tag UID comparable to Android’s tag.id
decrypt picc_encrypted into UID + counter
verify CMAC on-device
My requirements on iOS (to match Android behavior):
On the iOS native side (Swift, with NfcDnaKit imported) I want to:
Get a tag UID that I can compare with the decrypted UID (Android’s tag.id equivalent).
Decrypt picc_data (PICC_ENC) from the URL using my 16‑byte AES key to obtain:
PICC UID
read counter
Compute and verify CMAC against the cmac value from the URL.
Then, just like Android, send this full map back to Flutter via MethodChannel.
Questions (concrete):
With NfcDnaKit, what is the recommended way on iOS to get a NTAG 424 tag UID that I can compare to the decrypted UID?
Should I use NFCTagReaderSession + DnaCommunicator.getChipUid() for this?
Does NfcDnaKit provide any helper or example code to:
decrypt SDM picc_data (PICC_ENC) into UID + counter, and
compute/verify the SDM CMAC, given a known 16‑byte AES key?
If there is no built‑in helper, what is the correct pattern you recommend on iOS:
implement an iOS/Swift equivalent of the Android PiccData.decodeFromEncryptedBytes and performShortCMAC using your AES/CMAC utilities, or
rely on EV2 communication (DnaCommunicator / nxpEncryptedCommand) to read UID + counter directly from the tag and combine this with the NDEF URL data?
I have a Flutter app with NTAG 424 SDM (SUN) support.
On the Flutter side I only call a MethodChannel (readTagUrl) and receive a tagData map back.
All the real SDM / crypto work is done on the native side (Android now, and I want the same on iOS).
Android (already working, native side):
On Android I do all logic in MainActivity (Kotlin):
Read NDEF URL
Extract picc_data and cmac from the URL
Decrypt picc_data with my AES key to get:
PICC UID
Read counter
Verify the CMAC with the same key
Compare decrypted UID with tag.id (raw NFC tag UID)
Send the result back to Flutter as a map
Core Android logic (simplified, key removed):
val tagIdHex1 = bytesToHex(tag.id) // raw NFC tag UID
val piccData = PiccData.decodeFromEncryptedBytes(
Utils.hexStringToByteArray(piccDataHex),
oneAESKey,
false
)
val uidHex = bytesToHex(piccData.uid) // decrypted PICC UID
val counter = piccData.readCounter
val tagIdHex = bytesToHex(tag.id)
val isUidValid = uidHex.equals(tagIdHex, ignoreCase = true)
piccData.setMacFileKey(oneAESKey)
val isValid = piccData.performShortCMAC(null)
.contentEquals(Utils.hexStringToByteArray(cmacHex))
From Android I send back to Flutter:
tag_id (raw tag UID)
picc_encrypted
cmac
uid (decrypted UID)
counter
cmac_valid
full_url
iOS (current native side):
On iOS I have started implementing the native side in AppDelegate.swift:
Using NFCNDEFReaderSession to read the NDEF URI
I parse picc_data, cmac, and full_url from the URL
I send a map back to Flutter via MethodChannel("ntag424/sun") and readTagUrl
Right now, the map I send from iOS looks like:
[
"tag_id": "", // empty for now
"picc_encrypted": piccDataHex,
"cmac": cmacHex,
"uid": "", // not decrypted on iOS yet
"counter": 0,
"cmac_valid": false,
"full_url": url
]
So on iOS I only do URL parsing.
I do not yet:
get a raw tag UID comparable to Android’s tag.id
decrypt picc_encrypted into UID + counter
verify CMAC on-device
My requirements on iOS (to match Android behavior):
On the iOS native side (Swift, with NfcDnaKit imported) I want to:
Get a tag UID that I can compare with the decrypted UID (Android’s tag.id equivalent).
Decrypt picc_data (PICC_ENC) from the URL using my 16‑byte AES key to obtain:
PICC UID
read counter
Compute and verify CMAC against the cmac value from the URL.
Then, just like Android, send this full map back to Flutter via MethodChannel.
Questions (concrete):
With NfcDnaKit, what is the recommended way on iOS to get a NTAG 424 tag UID that I can compare to the decrypted UID?
Should I use NFCTagReaderSession + DnaCommunicator.getChipUid() for this?
Does NfcDnaKit provide any helper or example code to:
decrypt SDM picc_data (PICC_ENC) into UID + counter, and
compute/verify the SDM CMAC, given a known 16‑byte AES key?
If there is no built‑in helper, what is the correct pattern you recommend on iOS:
implement an iOS/Swift equivalent of the Android PiccData.decodeFromEncryptedBytes and performShortCMAC using your AES/CMAC utilities, or
rely on EV2 communication (DnaCommunicator / nxpEncryptedCommand) to read UID + counter directly from the tag and combine this with the NDEF URL data?