当前位置: 首页>编程语言>正文

RC663 基于NXP NFC reader 读取 FM1216

前言

最近由于项目需要使用 RC663 读取 FM1216 的 卡片,最初的项目是基于 S70(mifare) 来开发的,而且仅仅是对卡号进行了读取,并未对卡片的内容进行读写操作.而且加之使用的NFC Reader 库是比较老的版本,所以我就下载了新版本,开始了整(踩)合(坑)之路.

1.NXP NFC reader library 的集成

我使用的NFCLib 的版本为: NxpNfcRdLib_RC663_LPC1769_v05.21.00_Full

首先是导入源文件 , 导入头文件 , 这部分就跳过了,因为都是重复操作,没有什么需要注意的,缺什么文件就导入什么文件.

然后,因为我使用的是RC663 ,所以定义 宏 NXPBUILD__PHHAL_HW_RC663 .
而且,我 定义了PHDRIVER_PIRC663_BOARD 用于 控制NSS 脚的拉高拉低.
其次,我没有使用FreeRTOS .所以声明了 PH_OSAL_NULLOS

在这些都弄好后, 就到了驱动层了, 我现在用的是SPI, 所以将 SPI 初始化以及读写部分的函数实现替换为自己的函数.
并且将控制 POWER-DOWN 及 NSS 两个GPIO的 实现替换为自己的实现.

中断部分目前我没有弄.

2. NFC Reader library 的初始化

1. 首先初始化NfcLib

phStatus_t wStatus ;
phNfcLib_Status_t     dwStatus;

phNfcLib_AppContext_t AppContext;
phbalReg_Type_t sBalParams;

wStatus = phbalReg_Init(&sBalParams, sizeof(phbalReg_Type_t));

AppContext.pBalDataparams = &sBalParams ;

dwStatus = phNfcLib_SetContext(&AppContext);

dwStatus = phNfcLib_Init();

2. 初始化 14443 协议层

phhalHw_Rc663_DataParams_t    * pHal;
void *pspalI14443p3a;
void *pspalI14443p3b;
void *pspalI14443p4a;
void *pspalI14443p4;

pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
pspalI14443p3a = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3A);
pspalI14443p3b = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3B);
pspalI14443p4a = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4A);
pspalI14443p4 = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);

/* Configure HAL to ISO mode */
wStatus = phhalHw_SetConfig(
              pHal,
              PHHAL_HW_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-A PAL to ISO mode */
wStatus = phpalI14443p3a_SetConfig(
              pspalI14443p3a,
              PHPAL_I14443P3A_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-B PAL to ISO mode */
wStatus = phpalI14443p3b_SetConfig(
              pspalI14443p3b,
              PHPAL_I14443P3B_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-4A PAL to ISO mode */
wStatus = phpalI14443p4a_SetConfig(
              pspalI14443p4a,
              PHPAL_I14443P4A_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-4 PAL to ISO mode */
wStatus = phpalI14443p4_SetConfig(
              pspalI14443p4,
              PHPAL_I14443P4_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);


到这里 NfcLib 以及14443 的协议层就已经初始化完成了. 接下来就是使用了.

这里唯一需要注意的就是 phbalReg_Init 中的实现了,这部分的实现是根据自身所使用的接口来选择的,我用的是SPI,所以这里就是初始化SPI

3. NFC Reader library 的使用

1. 引用 14443 协议

wStatus = phhalHw_ApplyProtocolSettings(pHal, PHHAL_HW_CARDTYPE_ISO14443A);

这里因为我需要读取的是FM1216 的卡片,所以就 应用的是 14443A Type-A

2. 打开 Field

wStatus = phhalHw_FieldOn(pHal);

3. 做一个简单的延时 , 可以确保Field 打开

wStatus = phhalHw_Wait(pHal,PHHAL_HW_TIME_MILLISECONDS, 6);

4. 激活14443A的卡.

wStatus = phpalI14443p3a_ActivateCard(
              pspalI14443p3a,
              NULL,
              0x00,
              bUid,
              &bLength,
              &bSak,
              &bMoreCardsAvailable);

5. 判断是否 PICC (Proximity Card) 是否符合 ISO/IEC 14443-4

 if ( (0x08 == (bSak & 0x08)) &&  (0x20 == (bSak & 0x20)) )

参考自 <ISO/IEC 14443-3 Part 3: Initialization and anticollision> 6.4.3.4 Coding of SAK(Select acknowledge) . Table 6.8 - Coding of SAK

6. Send RATS

wStatus = phpalI14443p4a_Rats(
              pspalI14443p4a,
              0,
              bCid,
              Ats);

7. 获取 14443-4A 的参数并设置 14443-4 协议参数

/* Get parameters from 4A */
wStatus = phpalI14443p4a_GetProtocolParams(
              pspalI14443p4a,
              &bCidEnabled,
              &bCid,
              &bNadSupported,
              &bFwi,
              &bFsdi,
              &bFsci);

/* Apply parameters to layer 4 */
wStatus = phpalI14443p4_SetProtocol(
              pspalI14443p4,
              bCidEnabled,
              bCid,
              0,
              0,
              bFwi,
              bFsdi,
              bFsci);

8. 交换数据

wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              pTxBuffer,
              wTxLength,
              ppRxBuffer,
              pRxLength);

9. 关闭Field

wStatus = phhalHw_FieldOff(pHal);

关于上述流程,参考自 <ISO/IEC 14443-4 Part 4: Transmission protocol> 5. Protocol activation of PICC Type A . Figure 1 (the activation sequence for a PICC type A in the view of a PCD)
另外每完成一个步骤,应该先检查是否执行成功,如果执行成功,才继续往下走.

4. FMCOS 的使用

参考资料 :

  • CPU卡开发指南
  • FMCOS2.0建设部新版互联互通手册

我使用的是FM1216系列CPU 卡 ,而他搭载的COS 正是 FMCOS . 这里我不得不吐槽下,FMCOS 的资料真的是好少...

首先要执行发卡流程.
1. 取随机数

uint8_t CMD[] = {0x00, 0x84, 0x00, 0x00, 0x04};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              ppRxBuffer,
              pRxLength);

2. 当取随机数成功后, 返回状态 为 '90 00' 的时候.对齐进行DES 加密后,进行外部认证

uint8_t ExternalAuthentiateData[13] = {0x00,0x82,0x00,0x00,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} ;
uint8_t Data[8] ;
uint8_t EncryptData[8] ;
uint8_t i ;

memset(Data,0,sizeof(Data));
memcpy(Data,Challenge,4);

des(Data,ExternalKey,0,EncryptData);

for(i=5; i<13; i++) {
    ExternalAuthentiateData[i] = EncryptData[i-5] ;
}

printBuf("ExternalAuthentiateData:", ExternalAuthentiateData, 13, 32);
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              ExternalAuthentiateData,
              sizeof(ExternalAuthentiateData),
              &pRxData,
              &wRxDataLength);

  • 基于单片机的DES加密解密算法C源码

3. 卡片擦除

uint8_t CMD[] = {0x80,0x0E,0x00,0x00,0x00} ;
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              &pRxData,
              &wRxDataLength);

4. 选择MF

uint8_t choose_file [] = {0x00,0xA4,0x00,0x00,0x02,0x3F,0x00};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              choose_file,
              sizeof(choose_file),
              &pRxData,
              &wRxDataLength);

5. 创建密钥文件

uint8_t CMD [20] = {0x80,0xE0,
                    0x00,0x00,  // 文件标识
                    0x07, // lc
                    0x3F,  // 文件类型
                    0x00,0xB0, // 文件空间
                    0x01,  //读权限
                    0xF0,  //写权限
                    0xFF,
                    0xFF  // 详细见6.13.3
                   };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              &pRxData,
              &wRxDataLength);

6. 添加 PIN 到密钥中

uint8_t AddPin2KEY[18] = { 0x80,0xD4,
                           0x01,0x00, //文件标识
                           0x0D,  // 长度
                           0x39,  // 文件类型. 0x39为 外部认证密钥
                           0xF0,  // 读权限
                           0xF0,  // 写权限
                           0xAA,  // 后续状态
                           0x88,  // 错误计数 ,高字节为最多错误次数,低字节为还可以继续错误次数
                           0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF         //密钥
                         } ;
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              AddPin2KEY,
              sizeof(AddPin2KEY),
              &pRxData,
              &wRxDataLength);

7. 建立目录(DF)

uint8_t CMD[29] = { 0x80, 0xE0, // 创建文件
                    (uint8_t)(FileID >> 8),(uint8_t)FileID,  // 文件标识
                    0x0D, // 文件长度
                    0x38,  // 文件类型
                    0x05, 0x20,  //  文件空间大小
                    0xF0,  // 读权限
                    0xF0,  // 写权限
                    0x95,  // 应用文件ID
                    0xFF, 0xFF,   // reversed
                    // DF 名称 ASCII 码 5- 16 个字节
                  };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              AddPin2KEY,
              sizeof(AddPin2KEY),
              &pRxData,
              &wRxDataLength);

8. 选择DF(其实和选择MF 是一样的命令,只是 文件标识不同

uint8_t choose_file [] = {0x00,0xA4,0x00,0x00,0x02,0x3F,0x01};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              choose_file,
              sizeof(choose_file),
              &pRxData,
              &wRxDataLength);

9. 创建 DF 内的密钥 文件. 参考 5 创建密钥文件

10. 添加 PIN 到 DF 内的密钥中. 参考 6 添加 PIN 到密钥中

11. 建立二进制文件

uint8_t CreateFile_EF_BIN [] = {0x80,0xE0,
                                0x00,0x03,//File ID
                                0x07, // lc
                                0x28,  //文件类型. 
                                0x00,0x1E, //  文件大小
                                0xF0,  //读权限
                                0xF0,  //写权限
                                0xFF,
                                0x02  // 详细见6.13.3
                               };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CreateFile_EF_BIN,
              sizeof(CreateFile_EF_BIN),
              &pRxData,
              &wRxDataLength);

12. 选择二进制文件 ,参考 选择MF,只是 文件标识不同

13. 写入数据到二进制文件 , 需要注意的是 数据大小不能超过文件空间的大小;

uint8_t WriteFile_BIN [] = {0x00,0xD6,
                            0x00,0x00,//P1 , P2
                            0x05, // lc
                            0x01,0x02,0x03,0x02,0x01 //  写入的数据
                           };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              WriteFile_BIN,
              sizeof(WriteFile_BIN),
              &pRxData,
              &wRxDataLength);

然后是读卡流程

1. 选择DF ,参考 发卡流程的选择DF

2. 验证口令

uint8_t Verify_Pin [] = {0x00,0x20,
                         0x00,0x01,// 密钥标识
                         0x03, // lc
                         0x12,0x34,0x56// 密码
                        };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              Verify_Pin,
              sizeof(Verify_Pin),
              &pRxData,
              &wRxDataLength);                        

3. 选择二进制文件 参考 发卡流程的选择二进制文件

4. 读取二进制文件

uint8_t ReadFile_BIN [] = {0x00,0xB0,
                           0x00,0x00,//P1 , P2 
                           0x00,0x00
                          };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              ReadFile_BIN,
              sizeof(ReadFile_BIN),
              &pRxData,
              &wRxDataLength);                        

目前还没有弄循环记录文件 ,等弄好了之后再继续更新.


https://www.xamrdz.com/lan/5kv1849741.html

相关文章: