9

我想检索 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 中执行此操作(确认卡没有故障或只是奇怪)

苹果示例项目: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。

4

3 回答 3

4

好的,我有一个答案。

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)")
        }
    }
}
于 2019-09-18T14:58:52.487 回答
3

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

在这些情况下,可能类似于您提到的黑客中的 iOS11 解决方法的私有框架 API会有所帮助,例如拦截和修改发现轮询例程,但我不知道哪些或如何使用它们。

您可以在下面找到 MIFARE Classic 4K(仿真)标签的一些测试结果,此 github 线程此 MIFARE 支持线程中也有报告。在应用说明 #10833 的表 6之后,下面仿真标签的 Select Acknowledge ( SAK) 值0x38转换0 0 1 1 1 0 0 0为位 8..1,即位 6、5 和 4 是1,因此这些 SAK 值Smart MX with CLASSIC 4K图分类3 应用笔记#10834

  1. Infineon Classic 4k Emulation使用1 tags found正确的 UID ( )、 ATQA 31:9A:2F:88( 0x0200)、SAK(检测0x20,即 ISO 14443-4 协议 0x18,即 MIFARE 4K,两者都是预期值的一部分:)0x38和相应的标签类型(两者Generic 4AMiFare分类正确),但随后抛出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. 最初发现带有 UID的NXP SmartMX(经典 4k 仿真),CF:3E:40:04但在 ISO 14443-4A 存在检查( ) 收到:Proc Iso-Dep pres chk ntf: Receiption failed0x18

    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. 带有 UID的实际NXP Classic 4k2D:FE:9B:87仍未检测到并且不会引发错误。此标签的发现轮询会话在 60 秒后简单地超时,并记录最后发送 ( Tx) 和接收 ( Rx) 的 128 条发现消息,其中重复以下模式(其中确实包括预期的 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'
    
于 2019-10-21T08:29:00.377 回答
3

我知道你说过它会返回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 中打印数据不会显示在控制台中

于 2019-09-18T12:39:59.577 回答