若把iPhone NFC芯片当作RFID标签使用,这种操作是否可行?

7
我知道 iPhone 6 不支持读取 RFID 标签,我也知道 iPhone API 只允许在 Apple Pay 中使用 NFC,但是否可以通过将 iPhone 的 NFC 芯片解释成 RFID 标签来读取它呢?
也就是说,是否可以使用像 Arduino 或 Raspberry Pi 这样的设备与 RFID 读写器一起使用,以获取芯片的唯一 ID 或类似的被动信息?
3个回答

8
Michael Gillett所述,防碰撞标识符(RFID中经常用作ID)是动态的,并且在iPhone中安全元件每次激活时都会更改。您可以尝试访问安全元件上的EMV付款卡(“tokenized”信用卡)。此信用卡至少包含一个PAN(已标记的主帐号)和可能也包含用于签名验证的公钥。这些信息应该是静态的(即使在令牌化的情况下也是如此),因此可以用于识别设备。
请参阅触摸式支付系统的EMV规范(http://emvco.com),以了解如何访问付款应用程序。基本上,您需要执行以下操作:
  • 选择PPSE
  • 在选择响应中查找付款应用程序的AID
  • 选择付款应用程序(按AID)
  • 读取包含PAN / ICC公钥的记录的RECORD(文件+记录号)
但是,您需要一些接触式智能卡读卡器来发送必要的APDU命令。仅执行防碰撞以获取ID的RFID读卡器不足够。然而,对于Arduino和RPI,都有此类读卡器(例如NFC shield)。

6
当您按下大拇指尝试进行Apple Pay支付时,似乎可以检测到来自iPhone的信号。然而,每次按下时它会发送不同的ID号码。这使得几乎不可能做任何与安全相关的事情。以下是一个人让它工作的视频链接:https://www.youtube.com/watch?v=fhpMVFte2mE。因为iPhone每次都会发出不同的NFC标签号码,所以阅读器设置为使用任何标记,这对于像上面视频中的锁定等安全应用程序来说并不好。

2
该死,在观看了那个Youtube视频之后,我不知何故花了接下来的半个小时看人们摧毁新iPhone...同样令人昏昏欲睡的原因,我避免看电视。 - Chris A
真遗憾。希望苹果最终会开放API(就像他们之前限制的许多API一样),以便可以用于其他目的! - Nick Anderegg
我觉得他们肯定会在某个时候开放它,特别是随着他们最近推出的家庭自动化技术HomeKit的推动。这将成为锁定的完美钥匙。 - Mike G
@MichaelGillett 这正是我想用它的地方!用于解锁我的前门!我想我最终会选择蓝牙和一个安装在门上的小键盘进行双重身份验证。 - Nick Anderegg
现在是2022年,距离这个问题被提出已经有7年了,苹果从未公开HCE的API。有没有人有解决方法? - b.john
在我的国家,Apple Pay还没有启用。具体来说,在添加卡时,我可以启动NFC扫描弹出对话框“准备扫描...”,但我希望能够从那里生成ID。 - b.john

1
使用PN532板。为了简化与基于Arduino的主机的工作,请使用this library
定义连接。
#include <Arduino.h>
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>

PN532_SPI intfc(SPI,5);
PN532 nfc(intfc);

检查卡/手机是否存在:

success = nfc.inListPassiveTarget();
   if (success) { ...

定义通信缓冲区:

   uint8_t apdubuffer[255] = {};
   uint8_t apdulen;

并发送SELECT PPSE命令:

apdulen = 255;
success2 = sendAPDU(0x00, 0xA4, 0x04, 0x00, "2PAY.SYS.DDF01", 0x00, &apdubuffer[0], &apdulen);

如果成功,则:
//fromHEX("A0000000031010") - VISA
//fromHEX("A0000000041010") - MC
success2 = sendAPDU(0x00, 0xA4, 0x04, 0x00, fromHEX("A0000000031010"), 0x00, &apdubuffer[0], &apdulen);

而且您可以读取卡片的内部文件(SFI / RECs),例如:

success2 = sendAPDU(0x00, 0xB2, rec_num, (sfi_num << 3)+4, 0x00, &apdubuffer[0], &apdulen);

最好找到PAN / ICC公钥,因为它是卡的唯一标识,但在PAN / ICC之前会有许多字节呈现,我认为这些字节相当独特且足以执行身份验证。

毕竟,您需要这些重载:

bool sendAPDU(byte cla, byte ins, byte p1, byte p2, String aid, byte le, uint8_t *response, uint8_t *resp_len)
{
  uint8_t cmdbuf[255];
  memset(&cmdbuf[0],0,255);
  cmdbuf[0] = cla;
  cmdbuf[1] = ins;
  cmdbuf[2] = p1;
  cmdbuf[3] = p2;
  cmdbuf[4] = aid.length();  
  int i;
  for (i=0;i<aid.length();i++)
    cmdbuf[5+i] = aid[i];
  cmdbuf[6+i] = le;
  //printbuf((char*)&cmdbuf[0],5+aid.length());
  return nfc.inDataExchange(&cmdbuf[0], 5+aid.length(), response, resp_len);
}

bool sendAPDU(byte cla, byte ins, byte p1, byte p2, uint8_t* aid, byte le, uint8_t *response, uint8_t *resp_len)
{
  uint8_t cmdbuf[255];
  memset(&cmdbuf[0],0,255);
  cmdbuf[0] = cla;
  cmdbuf[1] = ins;
  cmdbuf[2] = p1;
  cmdbuf[3] = p2;
  cmdbuf[4] = aid[0];  
  int i;
  for (i=0;i<aid[0];i++)
    cmdbuf[5+i] = aid[i+1];
  cmdbuf[6+i] = le;
  //printbuf((char*)&cmdbuf[0],5+cmdbuf[4]);
  return nfc.inDataExchange(&cmdbuf[0], 5+cmdbuf[4], response, resp_len);
}

bool sendAPDU(byte cla, byte ins, byte p1, byte p2, byte le, uint8_t *response, uint8_t *resp_len)
{
  uint8_t cmdbuf[255];
  memset(&cmdbuf[0],0,255);
  cmdbuf[0] = cla;
  cmdbuf[1] = ins;
  cmdbuf[2] = p1;
  cmdbuf[3] = p2;
  cmdbuf[4] = le;
  //printbuf((char*)&cmdbuf[0],5);
  return nfc.inDataExchange(&cmdbuf[0], 5, response, resp_len);
}


还有这个:

/*
  Funny, non-C approach to return array from a function
  Returns ptr to global static buf... 
  Just to improve readability of sendAPDU() function...
  Not really needed in real app,
*/
uint8_t fromHexBuf[255];  
uint8_t* fromHEX(String hexs) {
  int i = hexs.length()/2;
  fromHexBuf[0] = i;
  int x=0;
  while (i) {
    char buf[3];
    char *tmp;
    buf[0] = hexs[2*x];
    buf[1] = hexs[2*x+1];
    buf[2] = 0;    
    uint8_t v = strtol(&buf[0], &tmp, 16);
    //Serial.printf("-> %s = %x\n", buf, v);
    fromHexBuf[x+1] = v;
    x=x+1;
    i--;
  }
  return &fromHexBuf[0];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接