NRF52832实现Mifare K1门禁卡模拟的探索


      由于产品规划的因素,想实现NRF52832单片机模拟NFC门禁卡的功能;我通过这段时间查找资料和学习,对NFC实现门禁卡需要做的工作,以及其中的难点,做如下总结。
一、NFC的协议分层、卡类型
      先上一张图,这张图可以清楚看到NFC的协议结构,以及NFC支持的卡类型:
        图片上标注灰色的部分是标准协议,常用的就是ISO1443A,  在之上不同的厂家会实现各自独特的通讯协议和加密验证算法。从这张图可以看到,NXP的卡的种类比较多。
二、MIFARE 1K 卡
     目前主流的门禁卡还是M1卡,M1卡是由NXP公司研发的门禁卡,目前是市场上主流的门卡;它的存储空间由1K,分为16个扇区,每个扇区有64个字节,每个扇区分为4个块,每块16个字节。
      
       如下图所示:
        第0扇区的第0块,保存卡UID和厂家信息,可读不可写,其它的扇区和块一般可读可写;每个扇区的最后一块保存每个扇区单独的密钥以及访问控制字。
        读卡器能够正确的从M1卡中读取数据,需要经历如下步骤:读卡器发起请求、选卡、认证、读写数据,下列的图片展示了读取数据的流程:
        
、MIFARE 1K 卡 的加密和认证
       M1卡采用一种叫做Crypto1的加密算法进行加密,这是一种流加密算法,在github上搜索就能找到源码。最初设计此算法的是NXP公司,此算法不开源。
  1. 当 MIFARE Classic 卡接近读卡器的磁场区域时,卡片会接收到读卡器发来的寻卡指令,然后按照防冲突协议发出自己的卡号UID(寻卡过程)。
  2. 收到UID 后,读卡器会选择这张卡(选卡过程)。
  3. 接着读卡器发出对某一块的认证请求,然后就开始了一个标准的三步认证协议(认证过程)。
  4. 卡片产生一个随机数nT 并以明文方式发送给读卡器。
  5. 紧接着读卡器发出它的随机数nR和对卡片的应答aR
  6. 最后卡片返回一个对读卡器的应答aT认证完成

      选卡的过程和放冲突模式是硬件自动操作的,所以从第三步开始的协议解析、身份认证、数据加密,才是工作难点。

标签对读卡器的认证

crypto1_init(&state, (uint64_t)tc[k].key); //通过密钥初始化 

crypto1_word(&state, tc[k].uid ^ tc[k].tag_challenge, 0);//输入UID和标签的随机数 

crypto1_word(&state, tc[k].reader_challenge_enc, 1);//读卡器发送的随机数 

rresp = prng_successor(tc[k].tag_challenge, 64);//验证标签的随机数和 

rresp ^= crypto1_word (&state, 0, 0); 

if(rresp == tc[k].reader_response)//验证读卡器的随机数是否和标签发送的数据数一样   
     printf("TAG> Reader is authentic.\n"); 

else 
     printf("TAG> Reader is NOT authentic.\n");

读卡器对标签的认证

        crypto1_init(&state, tc[k].key);
        crypto1_word(&state, tc[k].uid ^ tc[k].tag_challenge, 0);
        rchal = crypto1_word(&state, tc[k].reader_challenge, 0);
        rresp = prng_successor(tc[k].tag_challenge, 64);
        rresp ^= crypto1_word (&state, 0, 0);
        tresp = prng_successor(tc[k].tag_challenge, 96);
        tresp ^= crypto1_word (&state, 0, 0);
        if(tresp == tc[k].tag_response)//读卡器验证随机数
            printf("Reader> Tag is authentic.\n");
        else
            printf("Reader> Tag is NOT authentic.\n");

ISO14443 crc校验算法

#define CRC_A 1
#define CRC_B 2
#define BYTE unsigned char

unsigned short UpdateCrc(unsigned char ch, unsigned short *lpwCrc)
{
    ch = (ch^(unsigned char)((*lpwCrc) & 0x00FF));
    ch = (ch^(ch<<4));

    *lpwCrc = (*lpwCrc >> 8)^((unsigned short)ch << 8)^((unsigned short)ch<<3)^((unsigned short)ch>>4);
    return(*lpwCrc);
}

void ComputeCrc(int CRCType, char *Data, int Length,BYTE *TransmitFirst, BYTE *TransmitSecond)
{
    unsigned char chBlock;
    unsigned short wCrc;

    switch(CRCType) {
        case CRC_A:
            wCrc = 0x6363; // ITU-V.41
        break;
        case CRC_B:
            wCrc = 0xFFFF; // ISO 3309
        break;
        default:
    return;
    }
    do {
        chBlock = *Data++;
        UpdateCrc(chBlock, &wCrc);
    } while (--Length);
    if (CRCType == CRC_B)
       wCrc = ~wCrc; // ISO 3309
    *TransmitFirst = (BYTE) (wCrc & 0xFF);
    *TransmitSecond = (BYTE) ((wCrc >> 8) & 0xFF);
     return;
}
BYTE BuffCRC_A[] = {  0x53,0x45,0x47,0x47,0x45,0x52,0x20,0x52};
BYTE BuffCRC_B[] = { 0xC8,0xF0,0xD8,0x2E,0x7B};
unsigned short Crc;
BYTE First, Second;

int crc_main(void)
{
printf("CRC-16 reference results 3-Jun-1999\n");

printf("by Mickey Cohen - mickey@softchip.com\n\n");
printf("Crc-16 G(x) = x^16 + x^12 + x^5 + 1\n\n");

printf("CRC_A of [ ");
printf("%02X ",BuffCRC_A[i]);

ComputeCrc(CRC_A, BuffCRC_A, sizeof(BuffCRC_A), &First, &Second);


printf("] Transmitted: %02X then %02X.\n", First, Second);

return(0);
}

、使用NRF52832模拟M1门卡遇到的问题
      我在52832开源代码hal_nfc_tct上修改的,防冲突和选卡已经成功了,读卡器下发认证指令 60 00 F5 7B后, 标签回复4字节随机数+2个字节CRC,此时读卡器应该回复4字节的随机数+4字节的应答 +2字节的CRC的数据,一共10个字节,但是我只收到了读卡器的9个字节。数据流如下
      reader :  60 00 F5 7B 
      tag: 82 a4  16 6c 85 46
       reader :  1a 21 6a 40 f2 ef 52 ee 32(一共只有9个字节)
      如果最后这一步CRC校验成功了的话,才能开始标签对读卡器的认证;读卡器使其他的卡测试可以正常使用,我目前卡在这里:。
      目前可以排查方向如下:
            1.接收的数据中第一个字节丢失
            2.读卡器发送的数据有特殊的协议格式,我这边解析错误
       由于这两个方向都需要知道读卡器发送的数据,但是目前的读卡器是直接买的,我是不知道读卡器发送的具体数据,目前也没有什么好的方法。
  
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值