在 iOS 13 中读取 NFC 卡的 UID

Posted

技术标签:

【中文标题】在 iOS 13 中读取 NFC 卡的 UID【英文标题】:Reading UIDs of NFC Cards in iOS 13 【发布时间】:2019-09-17 16:33:06 【问题描述】:

我想检索 MiFare 卡的 UID。我使用的是 iPhone X、Xcode 11 和 ios 13。

我知道这在 iOS 13 之前是不可能的(特别是读取 UID),根据这个网站:https://gototags.com/blog/apple-expands-nfc-on-iphone-in-ios-13/ 和这个人:https://www.reddit.com/r/apple/comments/c0gzf0/clearing_up_misunderstandings_and/

手机 NFC 读取器正确检测到卡,但唯一标识符始终返回为空或 nil。但是我可以读取有效负载并且与 iOS 无关,但我可以在 android 中执行此操作(确认卡没有故障或只是奇怪)

Apple 示例项目: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))
                    
                
            
        

我知道这些黑客行为:CoreNFC not reading UID in iOS

但它们已关闭,过去仅在短时间内适用于 iOS 11。

【问题讨论】:

【参考方案1】:

好的,我有答案了。

tag.identifier 不是空的——本质上——如果你从 Xcodes 调试器中检查它会显示为空(0x00 是值!)。它的类型是数据,打印它会显示数据的长度,但不会显示它的编码方式。在这种情况下,它是一个 [UInt8] 但存储为一袋位,我不明白为什么 Apple 会这样做——它很笨重——我相信他们有充分的理由。我会将它存储为 String 类型——毕竟像 Swift 这样的高级语言的全部意义在于将我们从这些硬件实现细节中抽象出来。

以下代码将从 MiFare 卡中检索 UID:

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)")
        
    

【讨论】:

如果您只想打印标识符,则不需要连接或发送 APDU。在tags.first! 之后,您可以通过print(tag.identifier as NSData) 来查看控制台中的内容。 谢谢 Scott -- 一旦我可以验证您的解决方案如何工作,我会将您的答案标记为正确答案。这与我的方法略有不同。 嘿@ScottCondron。你能看看这个问题吗?在 iOS 13 ***.com/questions/58191748/… NFC 最初的日子里,很难找到所需的支持。【参考方案2】:

我知道你说过它会返回 nil,但为了让未来的读者更清楚:

假设不是Felica标签,检测到时应该在identifier字段上:

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

但在您的情况下,它是空的(请参阅下面的编辑)。对于大多数标签,获取标签 UID 的 APDU 是

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

所以您可以尝试使用tag.sendMiFareCommand 手动发送该命令。

编辑:来自 OP 的响应,它不是空的,但不清楚,因为在 Swift 中打印数据不会显示在控制台中

【讨论】:

我正在尝试使用比 9 月 18 日更新的 xcode 来实现这一点,但遇到了一些麻烦。 didDetedt NFCTag] 没有被触发,而且我还收到了来自 xcode 的警告,它几乎与他们的可选协议方法相匹配......所以我更新了较新的,然后无法转换为 mifare。您是否在最新版本中实现了这一点?如果有机会,请在此处填写完整的 q:***.com/questions/58285425/…【参考方案3】:

在 iOS13 中,我能够读取各种 MIFARE 系列的 DESfireUltraLight 标签的 Tag.identifier 值,与 @scott-condron 的答案相同,但对于各种 MIFARE Classic IC(unknown 家庭成员? ) 我的控制台显示不同的错误类型。

也许类似于the hack you mentioned 中的 iOS11 解决方法的私有框架 API 在这些情况下会有所帮助,例如拦截和修改发现轮询例程,但我不知道哪些或如何使用它们。

您可以在下面找到一些 MIFARE Classic 4K(仿真)标签的测试结果,this github thread 和 this MIFARE support thread 也报告了这些结果。在Table 6 of Application Note #10833 之后,下面仿真标签的0x38 的选择确认(SAK) 值转换为位8..1 的0 0 1 1 1 0 0 0,即位6、5 和4 是1,因此这些 SAK 值根据 Figure 3 of Application Note #10834 分类为 Smart MX with CLASSIC 4K

    Infineon Classic 4k Emulation 成功记录 1 tags found 并使用正确的 UID (31:9A:2F:88)、ATQA (0x0200)、SAK(检测到 0x20,即 ISO 14443-4 协议,0x18,即MIFARE 4K,都是预期值的一部分:0x38)和各自的标签类型(Generic 4AMiFare分类正确),但随后抛出一个@ 987654344@:

    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
    

    最初发现具有 UID CF:3E:40:04NXP SmartMX(经典 4k 仿真),但在 ISO 14443-4A 存在检查 (Proc Iso-Dep pres chk ntf: Receiption failed) 期间出现接收错误会不断重新启动发现轮询,直到会话最终到期,可能会阻止接收其他 SAK 值 0x18(用于 MIFARE 4K 标记类型):

    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
    

    UID 2D:FE:9B:87 的实际 NXP Classic 4k 仍然未被检测到并且不会引发错误。此标签的发现轮询会话在 60 秒后简单地超时,并记录最近发送 (Tx) 和接收 (Rx) 的 128 条发现消息,其中重复以下模式(其中确实包括预期的 UID:@ 987654353@):

    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'
    

【讨论】:

以上是关于在 iOS 13 中读取 NFC 卡的 UID的主要内容,如果未能解决你的问题,请参考以下文章

如何从 NFC 卡获取 cardnummer - 而不是 UID

是否可以使用 PhoneGap 读取 nfc 标签 UID?如何?

如果您有 IClass 卡的 UID,则读取卡上的卡号

PN532 串口通讯读取IC卡UID

iOS12如何设置NFC后台读取关联域

wpf读取低频卡