【STM32學習】(11)STM32 Mifare_One(S50) M1S50的使用(讀、寫、密鑰修改,控制位解讀)

最近在研究RFID(射頻識別),我用的是 M1卡(Mifare_One(S50)),是一種常用的非接觸式IC卡

基礎知識不用多講,網上資料一堆,講的很詳細。

現在我們就直入主題,首先介紹一下卡的執行流程圖,如下圖。

中文資料裏的圖,如下:

英文資料裏的圖,如下:

查資料會發現,所有的參考代碼都是按照這個流程圖寫,很容易懂。不管你在寫還是讀的時候一定要選卡,放衝突,驗卡等流程後才能實現讀寫操作。

再看一下他的存儲結構:

////*********引用一個博客文檔  開始

我們可以根據控制字來確定卡的讀寫形式。

M1卡分爲16個扇區,每個扇區由4塊(塊0、塊1、塊2、塊3)組成,前3個塊是數據區,第4塊是密鑰區。每個塊都能存儲16個字節的數據,密鑰區的16個字節數據是有特殊含義的:
6個字節的密碼A + 4個字節密鑰控制位 + 6個字節的密碼B
其中密鑰控制位決定這個扇區的讀寫規則,對於M1卡密鑰控制位及控制規則的說明,這篇文章裏面講述得很清楚了:
https://wenku.baidu.com/view/76afde36312b3169a451a4e6.html
這裏只是給沒有耐心看文章朋友提煉一下,控制字的組合方式雖然多,但實際用得比較多的方案自認爲無外乎四種:

1.默認方式 控制位爲“FF 07 80 69”
這種方式下密鑰A或密鑰B都可以讀寫數據區,密鑰A可寫密鑰區,優點是密鑰控制字無需重新計算,讀寫方便,缺點是安全性能差,密鑰A容易泄露。

2.密鑰B寫方式 控制位爲“7F 07 88 69”
這種方式下密鑰A或密鑰B都可以讀寫數據區,而對於密鑰區只能由密鑰B來寫。優點是密鑰B權限最高,只要知道密鑰B,無論密鑰A寫成什麼都可以改寫,由最高管理員掌握密鑰B,可下發多種密鑰A的一般管理員,一般不會廢卡的。缺點是密鑰B很重要,一旦忘記,卡就不能再改寫密鑰了。

3.A讀B寫方式 控制位爲“08 77 8F 69”
這種方式下由密鑰A讀密鑰B來寫,可以說是上面一種方式的變體,對於密鑰B有更強的保護。

4.只讀不寫方式 控制位爲“FF 00 F0 69”
這種方式下密鑰A或密鑰B都可以讀數據區,但都不能寫數據區(數值可減少,不能增加),密鑰A可以改寫密鑰區。這種方式對於數據是極大的保護,尤其是定額卡,裏面的錢只能減少而不能增加。

 

以上是常用的幾種控制方式,更多的組合方式可以利用“M1+卡控制字節生成工具.exe”工具來生成

結束   ******////////////

1.完成RFID卡的讀函數代碼

/* 讀取RFID卡片信息 **/
void Read_RFID_Card_wt(void)
{
	char status = MI_ERR;
	uint8_t CT[2];									//卡類型
	uint8_t SN[4]; 									//卡號
	uint8_t KEY[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //密鑰	//	密鑰已被我修改   2019.11.19  	  王艇
	uint8_t s = 0x01;       						  	
	#define  DATA_LEN    16                     	//定義數據字節長度	

	LED1 = 0;
	LED2 = 0;
	LED3 = 0;
	LED4 = 0;
	
		status = PcdRequest(PICC_REQALL,CT);		//尋卡
		//Send_ZigbeeData_To_Fifo(CT,2); // wt   2019.10.18
		if(status == MI_OK)							//尋卡成功
		{
			status=MI_ERR;
			LED1 = 1;
			status = PcdAnticoll(SN);				//防衝撞
			//Send_ZigbeeData_To_Fifo(SN,4); // wt    2019.10.18
			if(status == MI_OK)
			{
				status=MI_ERR;
				LED2 = 1;				
				status =PcdSelect(SN);				//選定此卡
				if(status == MI_OK)					//選定成功
				{
					status=MI_ERR;	
					LED3 = 1;
					MP_SPK = 1;					
					status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN);		//驗證密鑰
					if(status == MI_OK)
					{
						status = MI_ERR;
																	
						status=PcdRead(s,RXRFID);				//讀卡 
						
						if(status == MI_OK)
						{
							status = MI_ERR;
							LED4 = 1;							//讀卡成功
							MP_SPK = 0;								
							//Send_InfoData_To_Fifo(RXRFID,16);
							//Send_InfoData_To_Fifo("\n",2);  
							//Send_ZigbeeData_To_Fifo(RXRFID,16); 
						}						
					}
				}
			}
	}
}

這裏我是讀取0扇區第二塊(0X01)的數據,其實讀取其他也很簡單,需要修改0X03(這個是0-15扇區的控制塊,如:0扇區的控制塊是0X03,1扇區的控制塊是0X07 等等)

隨後還要修改,s,這個s就是你要驗證的哪個扇區的數據塊地址還控制塊地址(如:想讀1扇區的0塊數據,這個s的值就是0X04,我們這裏讀取的是0扇區第二塊(0X01)的數據):

注意:一般新卡的默認密鑰都是KEYA或KEYB   0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,但有時候密鑰會被修改,那這時就要填寫正確的key值,才能驗證成功,這樣也很容易理解,只有配上正確的密碼才能激活卡片。

2.完成RFID卡的寫函數代碼

void Write_RFID_Card_wt(void)
{
	char status = MI_ERR;
	uint8_t CT[2];									//卡類型
	uint8_t SN[4]; 									//卡號
	uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密鑰	//	密鑰已被我修改   2019.11.19  	  王艇
	uint8_t s = 0x01;       						  	
	#define  DATA_LEN    16                     	//定義數據字節長度	

	LED1 = 0;
	LED2 = 0;
	LED3 = 0;
	LED4 = 0;
	
		status = PcdRequest(PICC_REQALL,CT);		//尋卡
		//Send_ZigbeeData_To_Fifo(CT,2); // wt   2019.10.18
		if(status == MI_OK)							//尋卡成功
		{
			status=MI_ERR;
			LED1 = 1;
			status = PcdAnticoll(SN);				//防衝撞
			//Send_ZigbeeData_To_Fifo(SN,4); // wt    2019.10.18
			if(status == MI_OK)
			{
				status=MI_ERR;
				LED2 = 1;				
				status =PcdSelect(SN);				//選定此卡
				if(status == MI_OK)					//選定成功
				{
					status=MI_ERR;	
					LED3 = 1;
					MP_SPK = 1;					
					status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN);		//驗證密鑰
					if(status == MI_OK)
					{
						status = MI_ERR;
											
						status = PcdWrite(s,TXRFID);			//寫卡 
						if(status == MI_OK)
						{
							status = MI_ERR;
						}							
												
					}
				}
			}
	}
}

這裏是給0扇區1數據塊(0X01)寫數據,這個寫函數也是可以給其他扇區中數據塊寫數據的,如現在要給我1扇區,2塊中寫入數據:uint8_t TXRFID[16]  =  {0x7C,0x32,0x2F,0X30,0X33,0X2D,0X32,0X7C,0X7C,0X33,0X2F,0X30,0X35,0X2D,0X31,0X7C}

這裏選擇的是默認密鑰,全F,驗證A密鑰(PICC_AUTHENT1A

下面的 0X03需要改成0X07(扇區1 控制塊地址),因爲控制塊中包含密鑰,需要驗證

下面s要修改成0X06(表示1扇區,數據塊2的地址)TXRFID 是所要寫入的數據

這樣就完成了對指定扇區,指定數據塊中寫入指定數據。
3.修改RFID卡的密鑰代碼

void Write_RFID_Card_wt(void)
{
	char status = MI_ERR;
	uint8_t CT[2];									//卡類型
	uint8_t SN[4]; 									//卡號
	uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密鑰	//	密鑰已被我修改   2019.11.19  	  王艇
	uint8_t s = 0x03;       						  	
	#define  DATA_LEN    16                     	//定義數據字節長度	

	LED1 = 0;
	LED2 = 0;
	LED3 = 0;
	LED4 = 0;
	
		status = PcdRequest(PICC_REQALL,CT);		//尋卡
		//Send_ZigbeeData_To_Fifo(CT,2); // wt   2019.10.18
		if(status == MI_OK)							//尋卡成功
		{
			status=MI_ERR;
			LED1 = 1;
			status = PcdAnticoll(SN);				//防衝撞
			//Send_ZigbeeData_To_Fifo(SN,4); // wt    2019.10.18
			if(status == MI_OK)
			{
				status=MI_ERR;
				LED2 = 1;				
				status =PcdSelect(SN);				//選定此卡
				if(status == MI_OK)					//選定成功
				{
					status=MI_ERR;	
					LED3 = 1;
					MP_SPK = 1;					
					status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN);		//驗證密鑰
					if(status == MI_OK)
					{
						status = MI_ERR;
											
						status = PcdWrite(s,TXRFID);			//寫卡 
						if(status == MI_OK)
						{
							status = MI_ERR;
						}							
												
					}
				}
			}
	}
}

上面的代碼仔細看可以發現和2.完成RFID卡的寫函數代碼,中的代碼基本一致,也就是簡單修改了幾個參數。上面函數的功能是:將扇區0,控制塊密鑰修改0x01,0xB2,0xC3,0xD4,0xE5,0xF6,原來的密鑰是0xff,0xff,0xff,0xff,0xff,0xff

當修改完成後,他的密鑰就成了0x01,0xB2,0xC3,0xD4,0xE5,0xF6。

uint8_t TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};    

現在假如需要修改扇區1的A密鑰,之前扇區A的密鑰爲0xff,0xff,0xff,0xff,0xff,0xff,修改爲:0x01,0xB2,0xC3,0xD4,0xE5,0xF6

所以需要修改成的地方有:

  修改控制塊地址爲0X07,這個地址就是扇區1,控制塊地址

這邊的控制塊地址改成0X07

這個數組爲:TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 

 

執行成功後,扇區1的密鑰A的密碼就被修改成功了。

 

這樣就完成了數據的讀取,和密鑰的修改

後期對卡的扣款 充值操作就更容易一點。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章