浅谈M1卡

M1卡就是Mifare非接触式感应卡,M1卡数据保存期为10年,可改写10万次,读无限次。无电源,自带天线,工作频率为13.56MHZ.M1卡内含加密控制逻辑和通讯逻辑电路。M1卡主要有两种,一种是S50和一种是S70。

M1卡的工作原理

读写器向M1卡发一组固定频率的电磁波,卡片内有一个 LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。简单地说,就是感应产生电流来工作的一种卡片。

存储结构

浅谈M1卡_第1张图片
M1卡存储扇区

第0扇区的块0(即绝对地址0块),它用于存放厂商代码,已经固化,不可更改。
每个扇区的块0、块1、块2为数据块,可用于存贮数据。数据块可作两种应用:
★ 用作一般的数据保存,可以进行读、写操作。
★ 用作数据值,可以进行初始化值、加值、减值、读值操作。
而每个扇区的控制块,包括了密码A、存取控制、密码B。具体结构如下:


控制块的结构

每个扇区都是独立的,也就是说,每个扇区都可以设置独立的密码和数据,从而实现一卡多用的好处,对于每个扇区的数据块的数据写入具有一定的格式要求,比如在用于余额计算的钱包功能时数据的格式为


浅谈M1卡_第2张图片
数据块格式

寻卡

首先我们用读卡器读卡时,读卡器发送相应的指令寻取感应区内的某一指定类型的卡片。

防冲撞

当寻完卡后,就进入防冲撞,避免多卡乱像,此时读取卡片序列号,对于卡片的序列号,经过多次测验可以确定它的格式为十六进制的4字节数组,网上很多资料并没有说明此序列号的格式,所以在用单片机发送出去时必须转换格式才能正常显示。

选定卡片

选择被选中的卡的序列号,并同时返回卡的容量代码。

验证卡片密码

选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)。一般的白卡的默认密码为6个0xFF数组,所以有些破解方法还是的破解密钥才进行修改数值的。

读取数据/写入数据

验证密码后就能进行读取相应扇区的数据了。

/////////////////////////////////////////////////////////////////////
//功 能:寻卡
//参数说明: req_code[IN]:寻卡方式
// 0x52 = 寻感应区内所有符合14443A标准的卡
// 0x26 = 寻未进入休眠状态的卡
// pTagType[OUT]:卡片类型代码
// 0x4400 = Mifare_UltraLight
// 0x0400 = Mifare_One(S50)
// 0x0200 = Mifare_One(S70)
// 0x0800 = Mifare_Pro(X)
// 0x4403 = Mifare_DESFire
//返 回: 成功返回MI_OK //其中MI_OK=0
/////////////////////////////////////////////////////////////////////
`

     char PcdRequest(unsigned char req_code,unsigned char            *pTagType) 
{
     char status;   //status状态
     unsigned int  unLen;
     unsigned char ucComMF522Buf[MAXRLEN];  //存储卡类型的数组
     ClearBitMask(Status2Reg,0x08);    //清RC522寄存器位函数
     WriteRawRC(BitFramingReg,0x07);  //    写RC632寄存器函数
     SetBitMask(TxControlReg,0x03);   //置RC522寄存器位函数
     ucComMF522Buf[0] = req_code;
   status =         PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522    Buf,&unLen); //数组ucComMF522Buf已通过函数PcdComMF522()读取得卡信息,其中unLen为数据长度
   if ((status == MI_OK) && (unLen == 0x10))
     {    
         *pTagType     = ucComMF522Buf[0];
         *(pTagType+1) = ucComMF522Buf[1];  //使指针指向下一个地址
   }
   else
     {   status = MI_ERR;   }

        return status;
    }

/////////////////////////////////////////////////////////////////////
//功 能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////

    char PcdAnticoll(unsigned char *pSnr)  //防冲撞函数
{
char status;
unsigned char i,snr_check=0;
unsigned int  unLen;
unsigned char ucComMF522Buf[MAXRLEN]; 
ClearBitMask(Status2Reg,0x08);
WriteRawRC(BitFramingReg,0x00);
ClearBitMask(CollReg,0x80);
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x20;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
if (status == MI_OK)
{
     for (i=0; i<4; i++)
     {   
         *(pSnr+i)  =ucComMF522Buf[i] ;
         temp_ucTempbuf[i]=ucComMF522Buf[i];
         if(temp_ucTempbuf[1]==16)
          sen_char(temp_ucTempbuf[0]);
         snr_check ^= ucComMF522Buf[i];
         //sen_char(snr_check);
     }
     if (snr_check != ucComMF522Buf[i])
     {   status = MI_ERR;    }
}    
SetBitMask(CollReg,0x80);

return status;
}

/////////////////////////////////////////////////////////////////////
//功 能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////

char PcdSelect(unsigned char *pSnr)  //选定卡片函数
{
char status;
unsigned char i;
unsigned int  unLen;
unsigned char ucComMF522Buf[MAXRLEN];    
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x70;
ucComMF522Buf[6] = 0;
for (i=0; i<4; i++)
{
    ucComMF522Buf[i+2] = *(pSnr+i);
    ucComMF522Buf[6]  ^= *(pSnr+i);
}
CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);  
ClearBitMask(Status2Reg,0x08);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);    
if ((status == MI_OK) && (unLen == 0x18))
{   status = MI_OK;  }
else
{   status = MI_ERR;    }
return status;
}

/////////////////////////////////////////////////////////////////////
//功 能:验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
// 0x60 = 验证A密钥
// 0x61 = 验证B密钥
// addr[IN]:块地址
// pKey[IN]:密码
// pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////

  char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)  //验证卡片密码
{
char status;
unsigned int  unLen;
unsigned char i,ucComMF522Buf[MAXRLEN]; 
ucComMF522Buf[0] = auth_mode;
ucComMF522Buf[1] = addr;
for (i=0; i<6; i++)
{    ucComMF522Buf[i+2] = *(pKey+i);   }
for (i=0; i<6; i++)
{    ucComMF522Buf[i+8] = *(pSnr+i);   } 
status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
{   status = MI_ERR;   }    
return status;
}

/////////////////////////////////////////////////////////////////////
//功 能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
// pData[OUT]:读出的数据,16字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////

 char PcdRead(unsigned char addr,unsigned char *pData)  //读取M1卡一块数据函数
{
char status;
unsigned int  unLen;
unsigned char i,ucComMF522Buf[MAXRLEN]; 
ucComMF522Buf[0] = PICC_READ;
ucComMF522Buf[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);   
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
{
    for (i=0; i<16; i++)
    {    *(pData+i) = ucComMF522Buf[i];   }
}
else
{   status = MI_ERR;   }    
return status;
}

你可能感兴趣的:(浅谈M1卡)