RFID 卡片充值扣款流程 | 学习笔记

简介: 快速学习 RFID 卡片充值扣款流程

开发者学堂课程【嵌入式之 RFID 开发与应用2020版:RFID 卡片充值扣款流程】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/665/detail/11125


RFID 卡片充值扣款流程

内容介绍:

一、前言

二、为什么重置扣款更加安全

三、充值的基本演示

四、扣款的基本操作

五、充值的原理

六、扣款和充值函数的说明

七、RFID 总结

 

一、前言

能够通过密码验证并且完成数据的读写,其实数据的读写它的可靠性并不是特别高,这里存在一个问题,如果通过卡片保存了个人信息,那么卡坏了怎么办?一张卡片价格是几毛钱一块钱,用户可以买 10 张卡,可以往 10 张卡里面存入个人信息。

另外,就是信息单纯的读写其实不是特别安全,真正的更安全的方式是通过充值和扣款的方式去操作卡片,接下来要考虑的充值扣款的问题。

 

二、为什么重置扣款更加安全

充值和扣款之前是直接读写,每一个 block 是 16 个字节,16 个字节可以随便用,但是充值扣款里面 16 个字节是没有用完的,它只用到 16 个字节里面的前 4 个字节,后面的 12 个字节全部拿来做了校验,所以它更安全的,因为它做了校验,数据有错误校验就会失败,写入会失败读取也会失败,所以它就更安全。

如果不需要这么高的安全性,直接读写没有问题的,所以充值扣款它有一个前提就是它的数据是要经过校验的,在充值和扣除之前,数据的格式必须要有一个约定

int main(void)

unsigned char type[2],ret,card_id[4];int i,ops;

int snr = 3;unsigned char b_data[ 16],block = 2;

unsigned char a_key[6] = {oxff,oxff,oxff,oxff,oxff,oxff};

unsigned char def_data[16] ={ 0x00,0x00,0x00,0x00,oxff ,oxff ,oxff ,oxff ,0x00,0x00,0x00,0xo0,block ,~block,block~block}

unsigned char inc_dec[4] = {ox0o,ox00,ox00,oxo1};

rfid_reset();

rfid_carda_init();

while(1){

ret = rfid_carda_request(PICC_REQALL,type);

if(ret == OK){

printf( "card type = ox%02×%02x\n",type[0],type[1]);

// waitcardoff();

}else continue;

ret = rfid_anticol1(card_id);

处理数据的默认格式必须满足校验的格式,校验格式如下前4个字节是保存的实际数据,接下来 4 个字节了,接下来 4 个字节是实际数据的按位取反。也就是说双重保障,比前面的某个 bit 位,比如它电子存储设备,它可能出现未翻转未来,可能里面某一位翻转为 1,但是它一直唯一,改不了它,那值不就出错了。在读写的时候它会跟后面的值进行比较,取反之后值不相等,数据就会有问题的,就不能进行充值和扣款的操作,所以它有一个取反操作。

然后再接下来 4 字节又是实际数据,第 1 遍是原始数据,第 2 遍取反,第 3 遍还是原始数据,最后 4 个字节是当前块的原值和取反值,就是当前的数据到底存在于哪一块,就是充值的金额,比如说是第 0 块,那 block 就是 0,取反后就是 1。但是需要注意的是这里的块 block 不是 0~63,而是 0~3,它是针对于当前扇区而不是整个扇区。之间读写数据的时候,它是 0~63block,现在是 0~3block,不要搞错了。有了之后就必须先符合代码的规定充值才会成功。可以去看一下之前的一读二写三充值四扣款五初始化,初始化其实就是把 before 通过 write 的方式写进去才能进行充值和扣款。

 

三、充值的基本演示

接下来演示,因为卡片刚才已经输入了一个 ABCD 进去,看一下能不能往里面充值扣款成功。依然是先退出,然后进入到最后一个程序

image.png

数据跑起来后把卡片贴近阅读器,选择 1read,结果输入为:

[root@qfedu 04_rfid_inc_dec]#lsMakefile

rfid lib.h

Untitled Project.si4project rfid_lib.odemo

uart _init.c

main.c

uart init.h

main.o

uart_init.o

rfid lib.c

[root@qfedu 04_rfid_inc_dec]#. / demoversion=fc

doing close !

version=88

card type = 0x040o

card ID:0x34 0xa9 0xa5 0x4d

1.read;2.write;3.Increment4.Decrement5.init

1

block data:0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ox00 0x00 0x00 0x00 0x00 0x00 0x00 ox00

结果是有问题的,read 后结果为 0,它的值应该是 ABCD,看一下是不是它程序的读的扇区跟之前不一样,int snr=3 ; unsigned char b_ data[16], block=2; 之前是第 3 个扇区的第 0 个 block,现里写的是第 2 个 block,把它改成 block=0,改成 0 就是把之前的数据读出来,重新编译一下再运行,输出结果为:

card type = 0x0400

card ID:0x34 0xa9 0xa5 0x4d

1. read;2. write ;3. Increment4. Decrement5.init

block data:0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x00 0

x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

abcdefg

这次可以把之前的 ABCD 读出来,读出来之后,把卡拿开,拿开了之后,重新再贴近阅读器来进行充值。充值的金额每次增长一块钱,1 代表的含义需要自己进行定义。重新贴上这张卡,然后输入一个3就是充值,输出结果为:

card type = 0x0400

card ID:0x34 0xa9 0xa5 0x4d

1. read;2. write;3. Increment4.Decrement5.init

Increment error !

card type = 0x0400

card ID:0x34 0xa9 0xa5 0x4d

1. read;2. write;3. I ncrement4. Decrement5.init

结果显示出错,第 1 步充值错误,它是充不进去的,重新把卡片贴近阅读器,先输入一个 5 写入成功初始化成功,拿开卡片重新贴上,然后输入一个 1 把数据读出来看一下,此时读到的数据如下

write success!

card type = 0x0400

card ID:0x34 0xa9 0xa5 0x4d

1. read;2.write; .3. I ncrement4. Decrement5.init

block data:0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0xff 0x00 0xff

因为操作是第 0 块,所以出现 0F。接下来充值充一块钱进去,卡片贴近阅读器,输入一个 3 进行充值,输入结果为:

card type = 0x0400

card ID:0x34 0xa9 0xa5 0x4d

1. read;2. write;3. Increment4. Decrement

5.init

Increment success !

Transfer success !

充值成功了,接下来看一下卡里面的金额,再把卡贴上去

image.png

通过第 1 个 read 可知里面的 0 现在变成了 1 就表示有充值进去,而且后面的校验也变了,之前的FF现在变成FE了,还可以继续充值,贴上卡片后拿开,充值成功再拿开再贴上。

 

四、扣款的基本操作

卡片贴近阅读器,输入 4,扣款之后再贴上去,输入 1 又变成了一块钱,这就是整个的充值扣款的整个过程。

image.png

 

五、充值的原理

接下来要看一下它到底是怎么充进去的,实际的数据保存的空间只有 4 个字节

case 3:

ret = PcdIncrement( snr*4+block,inc_ dec) ;

if(ret == CMD_ SUCCESS){

puts( " Increment success!");

ret = PcdTransfer( snr*4+block);

if(ret == CMD_ SUCCESS)

puts("Transfer success!");

else

puts("Transfer error!");

WaitCardoff();

}else

puts("Increment error!' ' ) ;

break;

首先输入充值的金额,然后确定金额被传递到哪一个扇区里面以及充到扇区具体的哪一块。

char P cdIncrement(unsigned char addr, unsigned char *pData)

char status = CMD_ SUCCESS;

unsigned int

unLen ;

unsigned char i, ucComMF522Buf[MAXRLEN];

ucComMF522Buf[0] = PICC_ _INCREMENT;

ucComMF522Buf[1] = addr;

CalulateCRC(ucComMF522Buf,2 , &ucComMF522Buf[2]);

status = rfid_ cmd(PCD_ TRANSCEIVE , ucComMF522Buf ,4, ucComMF522Buf, &unLen);

if ((status != CMD_ SUCCESS) 11 (unLen = 4) 11 ((ucComMF522Buf[0] & 0x0F) != exBA))

{

status = CMD_ FAIL; }

if (status = CMD_ SUCCESS)

{

for (i=0; i<4; i++)

{

ucComMF522Buf[i] = *(pData+i);

CalulateCRC (ucComMF522Buf ,4, &ucComMF522Buf[4]);

rfid_ cmd(PCD_ TRANSCEIVE , ucComMF522Buf, 6, ucComMF522Buf, &unLen);

函数的主要作用,就是实现就是充值的初始化,充值并没有真正的把金额写入到的卡片里面去。先来看一下,首先是的块的地址,然后充的钱,就代表要对卡片进行充值操作,之后接下来要对它进行 crc 的校验。

CalulateCRC(ucComMF522Buf. , 2, &ucComMF522Buf[2]);

status = rfid_ .cmd(PCD_ TRANSCEIVE , ucComMF522Buf , 4, ucComMF522Buf , &unLen);

if ((status != CMD_ SUCCESS) |I (unLen != 4) II ((ucComMF522Buf[0] & 0x0F) != 0x0A) )

{ status = CMD_ FAIL; }

if (status = CMD_ SUCCESS)

{

for (i=0; i<4; i++)

ucComMF522Buf[i] = *(pData+i);

}

CalulateCRC(ucComMF522Buf , 4, &ucComMF522Buf[4]);

rfid_ cmd(PCD_ TRANSCEIVE , ucComMF522Buf , 6, ucComMF522Buf , &unLen);

return status ;

然后通过 rfid_cmd 传输命令把它写入到 buf,写完后会返回数据,对返回的数据再次做 crc 校验,PcdIncrement 的操作只是把钱通过 rfid_cmd,把它保存到了 fifodatareg 里面,钱并没有写到卡里面去。中间存在和卡片发生信息的交互的操作。

 

六、扣款和充值函数的说明

PcdIncrement () 和 PcdDecrement(), 这两个函数是做数据格式的合法性检测,也就是充的值符不符合卡片内部的数据格式,如果不符合是不会对块进行操作的。如果符合还需要调用另一个 PcdTransfer 接口。PcdTransfer 接口要下达传输指令才能将缓充区的充值或者扣款金额写入块中。

char PcdTransfer(unsigned char addr)

{

char status = CMD_ _SUCCESS;

unsigned int

unLen ;

unsigned char ucComMF 522Buf[MAXRLEN];

ucComMF522Buf[0] = PICC_ _TRANSFER;

ucComMF522Buf[1]

= addr;

CalulateCRC( ucComMF522Buf , 2 , &ucComMF522Buf[2]);

status = rfid_ .cmd(PCD_ _TRANSCEIVE , ucComMF522Buf , 4,ucComMF 522Buf, &unLen) ;

if (status != CMD_ _SUCCESS)

status = CMD_ FAIL;

return status ;

通过 PCDTRANSFER 指令才能真正的写入,上面的 PCDINCREMENT 是写不进去的,可以去测试一下,把后面代码给屏蔽掉,上面提示充值成功了,但是实际上卡里面是没有存储的,可以读出来看。所以整个充值扣款的过程就非常的清晰,从块的读写到块的充值扣款,就通过的标准的金融卡的指令

image.png

以及 PCP 的命令

image.png

pcd 的命令是由各个厂家提供的,命令可能厂家都不是特别一样,但是金融卡的指令都是规范的,至少中国是通用的。

 

七、RFID 总结

各个扇区的默认秘钥是多少?

如何对加密扇区的某一数据块进行读写?

如何修改扇区的秘钥?具体步骤是啥?

控制字有什么作用,如何进行修改?

通过上面的内容,这 4 个问题是不是能够进行回答,各个扇区的默认的密钥是多少,默认全是 1。如何对加密扇区的某一数据块进行读写?首先是对某一块进行读写,对块所在的扇区进行密码的认证,而且密码要看权限,就是权限里面验证密码之后允不允许对块进行读写。如果允许的情况下才能进入系统,如果不允许还要去修改它的权限,就是修改中间的 4 个字节。

image.png

如果不允许读写,中间的 4 个字节需要改一改,改成它允许为止。

另外就是如何修改扇区的密钥。首先要密码验证通过,其次就是权限允不允许修改A 密或者是 B 密,允不允许修改需要看表

image.png

如果表中不允许修改,还要再次回来修改权限,把权限改到它允许修改 A 密或者 B密的密码为止。

控制字的修改和的密码的修改是一样的,也就是说除了改密码以外,还可以修改控制字,控制字也依然遵循着以下的条件

image.png

A/B 密码到底对谁进行验证通过之后才可以进行改,读的权限其实很高,但是改的权限并不高。只要符合图中的三种情况就可以进修改。以上就是整个的 RFID 从基本的原理介绍、协议、阅读器、卡片做了一个详细的介绍。

相关文章
PSN 港服申请退费流程(订阅退费流程差不多)
PSN 港服申请退费流程(订阅退费流程差不多)
2283 0
|
17天前
|
前端开发 PHP 数据库
小利特惠/生活缴费/电话费/油卡燃气/等充值业务类源码附带U商承兑系统
全新首发小利特惠/生活缴费/电话费/油卡燃气/等充值业务类源码附带U商承兑系统
40 0
小利特惠/生活缴费/电话费/油卡燃气/等充值业务类源码附带U商承兑系统
|
5月前
|
安全 前端开发 数据安全/隐私保护
会员系统03-前台系统UI,利用页面展示大宗农产品价格走势曲线,添加银行卡,前还要进行实名认证,密码密文,隐私安全
会员系统03-前台系统UI,利用页面展示大宗农产品价格走势曲线,添加银行卡,前还要进行实名认证,密码密文,隐私安全
|
7月前
|
JavaScript Java 新能源
基于Java的新能源充电系统的设计与实现(亮点:完整合理的充电流程,举报反馈机制、余额充值、在线支付、在线聊天)
基于Java的新能源充电系统的设计与实现(亮点:完整合理的充电流程,举报反馈机制、余额充值、在线支付、在线聊天)
288 1
|
7月前
|
数据可视化 BI API
无纸化登记二维码应用方案:扫码填写表单,信息收集无纸化
日常生活中的申请表、签到表、报名表等纸质表格,收集到的信息常常不规范,可以搭建用于信息收集的二维码应用,通过扫码填写电子表单的方式,实现核销、业务申请、内部审批等场景的无纸化登记,并能将填写的信息导出为Excel表格存档。
206 0
支付宝提现方案
说明   首先使用支付宝接口实现提现功能,需要使用到【单笔转账到支付宝账户接口】   大家需要转变一个思路,单笔转账接口可以转账给个人支付宝账户,对于用户而言收到商家转账就是提现成功。所以我们可以针对这个接口来说,转账就是提现。
1348 12
关于宜搭体验版权益调整的公告
由于产品策略调整,2022年8月25 日起,针对2022年7月6日以前开通的宜搭体验版组织,免费使用人数将调整为上限10 人,每月可提交数据量调整为 1000 条,数据量免费总量仍为 2 万条。
5068 0
关于宜搭体验版权益调整的公告
|
C# 开发工具
新版支付宝手机支付流程_C#版
新版支付宝手机支付流程_C#版
199 0
|
移动开发 小程序 API
微信分账和支付宝分账
微信分账和支付宝分账
1597 0
J3
快捷餐饮之店家后台订单管理实现
快捷餐饮之店家后台订单管理实现
J3
145 0
快捷餐饮之店家后台订单管理实现