开发者学堂课程【嵌入式之 RFID 开发与应用2020版:RFID 验证密码并进行数据读写】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/665/detail/11124
RFID 验证密码并进行数据读写
内容介绍:
一、数据的读写
二、如何进行密码验证
三、数据验证通过的一系列操作
一、数据的读写
明白了 RFID 卡片的权限管理之后,才能够去对它进行读写,X 代表的是块。
如果要对里面的某一块进行操作,必须知道知道所对应的权限的值是多少,而权限的值是需要看默认权限的值的设置
默认的设置就是 A0 A1 A2 A3 A4 A5 FF 07 80 69 BO B1 B2 B3 B4 B5 看完以后再去对照表,看它的值符不符合这八种情况的某一种情况,找到这种情况之后,再去看对应的读写的条件是什么,是需要进行A密验证还是B密验证,或者验证以后看是否拥有权限。
一般情况下厂家默认的权限就是 6、7、8 三个字节,权限都比较高,基本上 A 密或者 B 密任何一个验证通过应该都可以进行操作了。
二、如何进行密码验证
#define KEYA 0x60
#define KEYB 0x61
ret = PcdAuthState(KEYA,snr*4+3,a_key , card_id);
if(ret != CMD_success)
puts ( "a_key error! " );continue;
如果里里面存的是 A 密,那就表示此时给的密码就是针对于 A 密的。
unsigned char type[2],ret,card_id[4];int i,ops;
int snr = 3;unsigned char b_data[1i6],block =0;
unsigned char a_key[6] = {oxff,6xff,Oxff,0xff,exff,exff};
如果存的是 B 密的话,就针对于 B 密进行验证,默认密码是 6 个 F。需要注意一下的传进去的编号,s50 卡共 64 块,16 个扇区,每个扇区的前 3 块是用户数据,第 4 块是用于保存密码和权限,所有出厂密码都 6 个 0xff。操作的 0~3 不是每个扇区的 0~3,而是以 0~63 为编号,所以说就规定 snr 是扇区,snr=3 就表示操作的是第 3 个扇区
ret = PcdAuthstate(KEYA, snr*4+3,a_key ,card_id);
if( ret != CMD_succESS){
puts( "a_key error!" );+continue;
每个扇区乘以 4 块再加上三就是的 0~63 的块的编号,一定要先指定块编号,块编号指定完了之后再指定密码,然后再把的这张卡的卡号传进去,那接下来的就可以完成验证。
char PcdAuthState(unsigned char auth_mode ,unsigned char addr , unsigned char*pKey,unsigned char
char status = CMD_success;
unsigned intunLen;
unsigned char ucComMF522Buf[MAXRLEN];
ucComMF522Buf[e] = auth_mode;
ucComMF522Buf[1] = addr;
memcpy(&ucComMF522Buf[2],pKey,6);
memcpy(&ucComMF522Buf[8], psnr, 4) ;
status = rfid_cmd(PCD_AUTHENT, ucComMF522Buf,12,ucComMF522Buf,&unLen);
if ( ( status != CMD_succEss) ll ( ! (reg_get(Status2Reg) & ex08) ) )i status = CMD_FAIL;}
return status;
首先它其实是一个 pacc 的指令,应该传输 PICC_AUTHENT1A,不要传输自己定义的内容。通过内容就可以知道是要对卡片进行操作。那如果要传 pcd 的,就是对读写器进行操作。现在是 A 密,要对卡片进行操作,把块的地址给 addr,把密码 6 个字节存到 memcpy(&ucComMF522Buf[2],pKey,6);
,然后再把卡号存在 ucComMF522Buf[8] 里面,传输的信息量非常大,6 字节的密码,4 字节的卡号,然后再加两字节的命令和参数,一共是 12 个字节,一次性的通过 rfid_cmd 把它写入到卡片里面。之前一直用的是 PCD_TRANSCEIVE,表示要读写数据,现在把它换成了 PCD_AUTHENT,表示要进行密码验证,验证通过返回的就是成功,只有返回成功之后,才可以进行接下来的所有的数据操作。
三、数据验证通过的一系列操作
puts ( "1.read;2.write; 3.Increment 4.Decrement");
scanf("%d",&ops);
switch(ops){
case 1:
bzero( b_data,16);
ret = PcdRead(snr*4+block,b_data) ;
if( ret ==CMD_succESS){i
printf( "block data : " );
for( i=;i<16;i++)
printf( "Ox%02x ",b_data[i]);
puts("");
puts(b_data);
waitCardOff();
要是不成功是不能进行下面的操作的,直接读或者是写就会返回失败,所以一定要先验证通过,如果不通过就又回到了开始重复这样一个过程。通过就可以对他进行读写。读写的过程和验证非常像,比如说要去读取数据,snr 是扇区,每个扇区是4 块,block 的值是多少就读取第几块, block=0 意思就是说要把第三个扇区的第0 块数据读出来,读到 b_data 里面。s50 卡共 64 块,16 个扇区,每个扇区的前 3 块是用户数据,第 4 块是用于保存密码和权限。每一块是 16 个字节。每一个扇区的每一个块有多少个自己?共 64 26 个山区,然后每个山区,那首先来看,一块是 16 个字节。
int main(void){
unsigned char type[2],ret,card_id[4];int i,ops;
int snr = 3;unsigned char b_data[16],block= ;
unsigned char a_key[6] = {exff,exff,0xff,exff,exff,0xff};
rfid_reset( );
rfid_carda_init( );while( 1)i
ret = rfid_carda_request(PICC_REQALL,type);
if( ret ==OK ){
printf( "card type = Ox%02x%02x\n",type[0],type[1]);
// waitCardOff();
}else continue;
ret = rfid_anticoll( card_id);
if( ret == OK )i
printf( "card ID:");
for(i=e;i<4;i++)
printf( "Ox%02x " ,card_id[i]);
所以读出来的就是什么 16 个字节的空间,读出来之后,将数据一一地以 16 进制方式进行输出,如果是字符串还可以输出字符串,接下来去读取一下,前提是密码是 6 个 1。开发板不能编译程序,开发板只能执行程序,要进入到虚拟机里面开发程序。
[root@qfedu 03_rfid_Rwblock]#ls
Makefile
rfid lib.h
Untitled Project.si4project rfid lib.o
Demo
uart_init.c
main.c
uart_init.h
main.o
uart_init.o
rfid_lib.c
[root@qfedu 03_rfid_Rw_block]#./ demo
version=ff
doing close !
version=88
第一次出现了错误,但是进行第二次初始化就成功了。初始化最好形成一个循环,接下来打开摄像头,根据的代码的要求,现在是要从卡片里面读取第 3 个扇区里面的第 0 块数据,把卡片贴上去
输出的结果为:
card type = 0x0400
card ID:0x34 0xa9 Oxa5 0x4d
1.read; 2.write; 3.Increment 4 .Decrement
read error!
card type = 0x0400
card ID:0x34 0xa9 0xa5 0x4d
1.read;2.write; 3.Increment 4. Decrement
可以看到里面出错了,因为当在输入 1 的时候,卡片已经离开了阅读器,这就是问题所在,所以操作过程中不能离开。接下来再重新把卡片贴到阅读器上面,输入 1以后,结果输出为:
read error!
card type = 0x0400
card ID:0x34 oxa9 oxa5 0x4d
1.read;2.write;3.Increment4.Decrement
block data:0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000x00 0x00 0x00 ox00 0x00 0x00 ox00 0x00
可以看到还是出现了一次错误,是因为没有重新进行初始化。后面数据读出来的结果全是 0,接下来可以往里面写一些数据,写数据操作为 ret = PcdRead( snr*4+block,b_data); 读数据操作为 ret = Pcdwrite(spr*4+block,b_data); 写数据和读数据几乎一模一样,只是指令不一样。读叫做 PICC_READ,写是pacc_write,读和写其实都一样写的话,因为没有写过数据,所以读出来就是第一,写数据就是通过键盘输入一个字符串存到 b_data 里面,然后 d_bata 写进去。然后再次去进行读操作,看看能不能读到的数据,再次卡片贴到读取器上面,输出结果为:
card type = 0x0400
card ID:0x34 0xa9 0xa5 0x4d
1.read;2.write;3.Increment4.Decrement
block data:0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ox00 ox00 ox00 ox00 0x00
它是读不到的,这时候必须要把卡拿开,然后再贴上去,要不然它会一直 wait 卡离开,输出结果为:
card type = 0x0400
card ID:0x34 0xa9 0xa5 0x4d
1.read;2.write;3.Increment4.Decrement
等待离开,然后再去写出一个2进行写操作,输出结果为:
abcdefg
write success !
写入是成功的,然后再把卡贴上去,再输入 1,输出结果为:
abcdefg
write success !
card type = 0x0400
card ID:0x34 oxa9 0xa5 0x4d
1.read;2.write;3.Increment4.Decrement
block data:0x61 0x620x63 0x64 0x65 0x66 0x67 0x00x00 0x00 ox00 ox00 ox00 ox00 0x00 0x00
Abcdefg
读取的结果就很明显,那、a 所对应的 ASCLL 就是分别是 616263 一直到最后。后面没有写的依然是保持为 0,然后读出来的时候也是 abcdefg,所以说卡片就满足了先写入的内容,然后再读取出来是正确的这样的要求。基本的读写过程就是这样的针对扇区,所以说卡片里可以用来存任何数据,不一定是充值数据,可能就是存放个人身份信息,姓名、家庭住址、车牌号,将来要想查看的信息的时候,比如有一个读卡器,把存入卡片的信息往某一个阅读器上面一贴,就可以把信息全部给打印出来。而且它有 1000 个字节的存储空间,也就是说可以存 1000 个字节的信息到里面,可以把这些信息可以把每一个扇区的密码都设成一样的,把每一个扇区的数据都读出来,卡片相当于是一个存储器,存储器需要阅读器和密码才能读取出来。假如说个人有一些隐私的账号信息之类的,那可以把它全部存到一张卡片里面,然后自己再做一个阅读器,当需要去知道这些信息的时候,就去刷一下卡,他把这信息全部给打印出来就知道了。如果是通过手机,也可以去开发一个简单的小应用,通过 NFC 把信息数据读取出来,这种存储方式的安全性比把个人的银行账号、密码这些存到笔记里面更安全一些,因为密码只有自己知道,更加的安全可靠一些。