Reading UIDs of NFC Cards in iOS 13

ios 13 nfc card emulation
ios 13 nfc write
best nfc tags for iphone
ios 13 nfc write example
iphone compatible nfc tags
ios 13 nfc ipad
ios 13 amiibo
can ipad read nfc tags

I would like to retrive the UID of MiFare cards. I'm using an iPhone X, Xcode 11 and iOS 13.

I'm aware this wasn't possible (specifically reading the UID) until iOS 13 according to this website: https://gototags.com/blog/apple-expands-nfc-on-iphone-in-ios-13/ and this guy: https://www.reddit.com/r/apple/comments/c0gzf0/clearing_up_misunderstandings_and/

The phones NFC reader is correctly detecting the card however the unique identifier is always returned as empty or nil. I can read the payload however and irrelvant to iOS but I can do this in Android (confirms the card isn't faulty or just odd)

Apple Sample Project: https://developer.apple.com/documentation/corenfc/building_an_nfc_tag-reader_app

    func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
            if case let NFCTag.miFare(tag) = tags.first! {
                session.connect(to: tags.first!) { (error: Error?) in
                    let apdu = NFCISO7816APDU(instructionClass: 0, instructionCode: 0xB0, p1Parameter: 0, p2Parameter: 0, data: Data(), expectedResponseLength: 16)
                    tag.queryNDEFStatus(completionHandler: {(status: NFCNDEFStatus, e: Int, error: Error?) in
                        debugPrint("\(status) \(e) \(error)")
                    })
                    tag.sendMiFareISO7816Command(apdu) { (data, sw1, sw2, error) in
                        debugPrint(data)
                        debugPrint(error)
                        debugPrint(tag.identifier)
                        debugPrint(String(data: tag.identifier, encoding: .utf8))
                    }
                }
            }
        }

I'm aware these sorts of hacks: CoreNFC not reading UID in iOS

But they are closed and only apply to iOS 11 for a short time in the past.


Ok I have an answer.

tag.identifier isn't empty -- per se -- if you examine from Xcodes debugger it appears empty (0x00 is the value!). It's type is Data and printing it will reveal the length of the Data but not how it's encoded. In this case it's a [UInt8] but stored as a bag of bits, I don't understand why Apple have done it this way -- it's clunky -- I'm sure they have good reasons. I would have stored it as a type String -- after all the whole point of a high level language like Swift is to abstract us away from such hadware implementation details.

The following code will retrive the UID from a MiFare card:

            if case let NFCTag.miFare(tag) = tags.first! {
                session.connect(to: tags.first!) { (error: Error?) in
                    let apdu = NFCISO7816APDU(instructionClass: 0, instructionCode: 0xB0, p1Parameter: 0, p2Parameter: 0, data: Data(), expectedResponseLength: 16)
                    tag.sendMiFareISO7816Command(apdu) { (apduData, sw1, sw2, error) in
                        let tagUIDData = tag.identifier
                        var byteData: [UInt8] = []
                        tagUIDData.withUnsafeBytes { byteData.append(contentsOf: $0) }
                        var uidString = ""
                        for byte in byteData {
                            let decimalNumber = String(byte, radix: 16)
                            if (Int(decimalNumber) ?? 0) < 10 { // add leading zero
                                uidString.append("0\(decimalNumber)")
                            } else {
                                uidString.append(decimalNumber)
                            }
                        }
                        debugPrint("\(byteData) converted to Tag UID: \(uidString)")
                    }
                }
            }

Apple Expands NFC on iPhone in iOS 13 - Blog, Only support for reading NDEF formatted data; No access to the NFC chip UID; An app was required to use NFC tags on iPhone models earlier  In addition, the U.K. government’s NFC passport reader app, ReadID, will now work on the iPhone as a result of the iOS 13 updates. “This announcement means that ReadID will also work on iPhones,


In iOS13 I was able read the Tag.identifier value for various MIFARE family's DESfire and UltraLight tags same as @scott-condron's answer, but for various MIFARE Classic ICs (the unknown family member?) my Console shows different error types.

Perhaps private framework APIs similar to the iOS11 work-around in the hack you mentioned would be helpful in these cases, e.g. to intercept and amend the discovery polling routine, but I wouldn't know which ones or how to use them.

Below you can find some test results for MIFARE Classic 4K (emulation) tags, as also reported in this github thread and this MIFARE support thread. Following Table 6 of Application Note #10833, the Select Acknowledge (SAK) value of 0x38 of the emulation tags below translates into 0 0 1 1 1 0 0 0 for bits 8..1, i.e. bits 6, 5, and 4 are 1, and therefore these SAK values classify as Smart MX with CLASSIC 4K as per Figure 3 of Application Note #10834.

  1. an Infineon Classic 4k Emulation successfully logs 1 tags found with the correct UID (31:9A:2F:88), ATQA (0x0200), SAK (detects 0x20, i.e. ISO 14443-4 protocol, and 0x18, i.e. MIFARE 4K, both part of the expected value: 0x38) and respective tag type (both Generic 4A and MiFare classified correctly), but then throws a Stack Error:

    error   14:48:08.675369 +0200   nfcd    00000001 04e04390 -
        [NFDriverWrapper connectTag:]:1436  Failed to connect to tag: 
        <NFTagInternal: 0x104e05cd0>-{length = 8, bytes = 0x7bad030077180efa} 
        { Tech=A Type=Generic 4A ID={length = 4, bytes = 0x319a2f88} 
        SAK={length = 1, bytes = 0x20} ATQA={length = 2, bytes = 0x0200} historicalBytes={length = 0, bytes = 0x}}
    :
    error   14:48:08.682881 +0200   nfcd    00000001 04e04390 -
        [NFDriverWrapper connectTag:]:1436  Failed to connect to tag: 
        <NFTagInternal: 0x104e1d600>-{length = 8, bytes = 0x81ad0300984374f3} 
        { Tech=A Type=MiFare ID={length = 4, bytes = 0x319a2f88} 
        SAK={length = 1, bytes = 0x18} ATQA={length = 2, bytes = 0x0200} historicalBytes={length = 0, bytes = 0x}}
    :
    default 14:48:08.683150 +0200   nfcd    00000001 04e07470 -
        [_NFReaderSession handleRemoteTagsDetected:]:445  1 tags found
    default 14:48:08.685792 +0200   nfcd    00000001 04e07470 -
        [_NFReaderSession connect:callback:]:507  NFC-Example
    :
    error   14:48:08.693429 +0200   nfcd    00000001 04e04390 -
        [NFDriverWrapper connectTag:]:1436  Failed to connect to tag: 
        <NFTagInternal: 0x104e05cd0>-{length = 8, bytes = 0x81ad0300984374f3} 
        { Tech=A Type=MiFare ID={length = 4, bytes = 0x319a2f88} 
        SAK=(null) ATQA=(null) historicalBytes={length = 0, bytes = 0x}}
    :
    error   14:48:08.694019 +0200   NFC-Example 00000002 802e2700 -
        [NFCTagReaderSession _connectTag:error:]:568  Error 
        Domain=NFCError Code=100 "Stack Error" UserInfo={NSLocalizedDescription=Stack Error, NSUnderlyingError=0x2822a86c0 
        {Error Domain=nfcd Code=15 "Stack Error" UserInfo={NSLocalizedDescription=Stack Error}}}
    
  2. an NXP SmartMX (Classic 4k emulation) with UID CF:3E:40:04 is discovered initially, but a reception error during ISO 14443-4A presence check (Proc Iso-Dep pres chk ntf: Receiption failed) continuously restarts the discovery polling until the session finally expires, possibly preventing the other SAK value 0x18 (for MIFARE 4K tag type) to be received:

    error   10:44:50.650673 +0200   nfcd    Proc Iso-Dep pres chk ntf: Receiption failed
    :
    error   10:44:50.677470 +0200   nfcd    00000001 04e04390 -
        [NFDriverWrapper disconnectTag:tagRemovalDetect:]:1448  Failed to disconnect tag: 
        <NFTagInternal: 0x104f09930>-{length = 8, bytes = 0x07320d00f3041861} 
        { Tech=A Type=Generic 4A ID={length = 4, bytes = 0xcf3e4004} 
        SAK={length = 1, bytes = 0x20} ATQA={length = 2, bytes = 0x0200} historicalBytes={length = 0, bytes = 0x}}
    default 10:44:50.677682 +0200   nfcd    00000001 04e04390 -
        [NFDriverWrapper restartDiscovery]:1953
    
  3. an actual NXP Classic 4k with UID 2D:FE:9B:87 remains undetected and throws no error. The discovery polling session for this tag simply times out after 60 seconds and logs the last 128 discovery messages transmitted (Tx) and received (Rx), among which the following pattern is repeated (which does include the expected UID: 2D FE 9B 87):

    error   11:42:19.511354 +0200   nfcd    1571305339.350902 Tx  '21 03 07 03 FF 01 00 01 01 01 6F 61'
    error   11:42:19.511484 +0200   nfcd    1571305339.353416 Rx  '41 03 01'
    error   11:42:19.511631 +0200   nfcd    1571305339.353486 Rx  '00 F6 89'
    error   11:42:19.511755 +0200   nfcd    1571305339.362455 Rx  '61 05 14'
    error   11:42:19.511905 +0200   nfcd    1571305339.362529 Rx  '01 80 80 00 FF 01 09 02 00 04 2D FE 9B 87 01 18 00 00 00 00 2D 11'
    
    error   11:42:19.512152 +0200   nfcd    1571305339.362734 Tx  '21 06 01 00 44 AB'
    error   11:42:19.512323 +0200   nfcd    1571305339.363959 Rx  '41 06 01'
    error   11:42:19.512489 +0200   nfcd    1571305339.364028 Rx  '00 1D 79'
    error   11:42:19.512726 +0200   nfcd    1571305339.364300 Rx  '61 06 02'
    error   11:42:19.512914 +0200   nfcd    1571305339.364347 Rx  '00 00 EB 78'
    

Has anyone managed code NFC UID read on iOS 13 / latest , Has anyone managed code NFC UID read on iOS 13 / latest CoreNFC. Hey all, has I was looking into picking up some more tags when I saw these things. As of iOS13, these phones can also write to NFC tags with an appropriate App. Reading NFC Tags with an iPhone 7, 8 or X. Even with the latest iOS13 operating system, the 7, 8 and X iPhones cannot read NFC Tags natively. This means that while these generations of iPhones can read NFC tags, they can't do it out of the box. An additional App is required.


I know you have said that it returns nil but for clarity for future readers:

Assuming it is not a Felica tag, it should be on the identifier field when it is detected:

func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {      
  if case let NFCTag.miFare(tag) = tags.first! {
    print(tag.identifier as NSData)
  }
}

But in your case, it's empty (see edit below). For most tags the APDU to get the UID of a tag is

  0xff // Class
  0xca // INS
  0x00 // P1
  0x00 // P2
  0x00 // Le

so you could try using tag.sendMiFareCommand to send that command manually.

Edit: Response from OP, it wasn't empty but was unclear because printing Data in Swift doesn't show in console

How To Read NFC Tags With An iPhone, As of iOS13, these phones can also write to NFC tags with an iOS13, the iPhone (7,8,X,Xs,Xr,11,11Pro) is able to also read the tags'a UID  Forum / MIFARE and NFC Reader IC`s / Is it possible to read the UID of a MiFare Card using iOS 13's Core-NFC? Tagged: Core-NFC , iOS 13 , iPhone , Reading 17.


iOS 13 NFC - What has changed ?, Up until iOS13, no iPhone could read this UID. to an NFC tag with an appropriate App. Additionally, it is also now possible to lock NFC tags. It is possible to read an NFC Chip’s UID with a 3 rd party iPhone app using Core NFC. There is not a direct way to access the NFC chip UID on an iPhone using Background NFC Tag Reading, unless the UID is copied or mirrored into the NDEF message. However this is not a secure way to access the UID and the UID in the NDEF message could be spoofed.


Is it possible to read the UID of a MiFare Card using iOS 13's Core , markov spam in the post above. Figured it out in the end: https://stackoverflow. com/questions/57978507/reading-uids-of-nfc-cards-in-ios-13  The phones NFC reader is correctly detecting the card however the unique identifier is always returned as empty or nil. I can read the payload however and irrelvant to iOS but I can do this in Android (confirms the card isn't faulty or just odd)


#53 First steps with NFC on iOS 13 – swifting.io, In iOS 13 Apple expanded possibilities of Core NFC. Now iOS is able to read more complex NFC tags, including those that meet ISO 7816 and ISO 15693 standards. Now is identifier (UID); historicalBytes; applicationData. With iOS 13, iPhones will be able to scan NFC chipped IDs and store their details. With appropriate apps, you could then save a digital copy of your ID on your iPhone and pull it up when needed. If you’ve ever used the Wallet app on iPhone, you’ll know why this is powerful and something to get excited over.