AT88S153工作原理与应用

AT88SC153加密卡的原理和应用

AT88SCxx系列加密存储芯片是Atmel生产的具有多用途的加密存储系列芯片
其中AT88SC153是该系列芯片的典型代表。由于其具有多达2KB的EEPROM,利用I2C串行总线通信,采用认证或加密验证等方式进行数据访问。

1. 器件简介

1.1引脚图

在嵌入式系统中,AT88SC153常采用SOIC和PDIP两种典型封装。由于器件采用I2C串行总线接口,因此引脚数目少,体积小。各引脚功能如下:
SCL——串行时钟输入脚,用来控制器件所有的数据输入相输出;
SDA——串行数据输入/输出脚;
RST——复位引脚
VCC——电源电压,工作电压为2.7V~5.5V;
GND——地;
NC——不连接。

2.主要特点

1.AT88SC153具有1个64字节的设置区和3个64字节的应用分区,3个应用区可以设置为同一套密码组合而自由合并,也可以分别指定不同的读写密码(共两套,每套读写密码各三个字节),错误计数4/8次。
2.高安全性。对于用户民应用区,具有标准访问、认证访问和加密验证访问两种方式,同时提供多组密码集供读写访问使用。每个应用分区在配置区中都有相应的寄存器控制其安全等级和访问方式。
3.高可靠性。提供多达10万次擦写次数和10年的数据保存期。
4.多种封装。除8脚的PDIP、SOIC封装外,还具有智能卡片封装,可广泛应用于IC卡系统。
5.高速度。AT88SC153时钟频率为1MHz,支持页写模式(8字节/页),如果以页写方式访问的话,访问时间为10ms(最大)/页。通讯协议符合ISO/IEC7816-3同步协议

3.工作原理

1.存储结构


AT88SC153逻辑加密芯片是一款串行EEPROM,共有192B的用户应用存储区和64B的系统配置区,其中前3组64字节为应用区,最后64字节为配置区。
2.配置区结构

应用存储区通过配置可划分成3个相同容量的应用存储区。分别受2套(4个)读写密码的控制,错误计数最大8次。这3个应用分区也可以通过配置使用相同的密码和安全等级可自由合并使用。
Answer-to-Reset:复位应答,由ATMEL定义,不可修改,每次发送复位信号后由SC153自动送到SDA上,复位应答为–2C AA 55 A1。
Lot History Code:历史代码,由ATMEL定义,不可修改。
Fab Code:厂商代码,由ATMEL定义,不可修改。
CMC:卡商代码,由卡商定义,不可修改。
AR0-2:设置应用区0-2的访问权限
MTZ:测试区,在任何情况下都可以进行读写操作。
DCR: 设备寄存器,在这里可以扩展密码校验错误次数和认证错误次数为8次(默认都是4次)。
Issuer Code(IC):发行号。个人化前定义。
AAC:认证错误计数器。初始值为8,每次认证错误后减2,共四次 ,设置DCR可扩展为8次。同时也可以为NC的一部分,注意如果修 改了AAC,会影响下一次认证的Ci值。
NC:识别码,通常用作卡的唯一标识—卡号。个人化前定义。
Ci:密文,个人化前可写一随机数,认证卡时使用,每次认证会被自动改写。
Gc:密钥,64位的保密种子,由Nc通过F1公式推算出来,在个人化前,写入卡中。
PAC: 分区密码错误计数器。初始值为8,每次认证错误后减2,共四次 ,设置DCR可扩展为8次。
WP0,WP1,RP0,RP1:2套读写密码集,每个分区可以分别指向唯一的密码集,也可以指向同一套密码集,这样就可以只核对一套密码而进入多个分区,使多个分区合成为一个大的分区。默认WP1、RP1为读写密码。写密码1(WP1)还作为传输密码(SC)。另外,如果需要修改读写密码时,也必须核对同一套密码集的写密码。
SC:传输密码。初始值由ATMEL定认。发到每个卡厂都不同。可以修改,在个人化前一直使用SC,个人化后其它密码才会被用到。
3.芯片使用
AT88SC153芯片为用户访问应用存储区提供了标准、认证和加密三种方式,既方便用户根据实际情况灵活选择加密方式,又提高了系统的安全性。在标准访问方式下,对用户应用区的读写访问无任何限制;在认证方式下,用户必须经过认证,同时要通过不同用户区所设定的密码检验才能正确访问用户数据区,在这种方式下,总线上传输的数据是明文:加密验证模式下访问用户时用户必须首先经过认证,然后利用认证成功后配置区特定寄存器中更新的数据作为密钥再次进行认证,最后还要通过不同用户区设定的密码检验后才可访问用户区,这种方式下总线下传输的数据是经过加密的密文。
(1)标准模式初始化
在此模式下无需加密和认证就能完整使用芯片的存储和读取,但是需要知道一个重要的东西,就是传输密码(Source code)这个一般是由发卡商制定,购买时应该会告诉你。
在该模式下工作首先还是要验证密码,当芯片有一个复位信号后此次的验证就会失效,验证传输密码后才能完成配置区的读写,当然芯片的读写权限是已经规定好的,如下图

由于AT88SC153 内部有一内存测试区(memory test)不受安全和密码限制,因此为保证I2C读写时序的正确性,可先向该区进行读写测试,然后再向芯片正确写入各种命令。特别是密码传输密码验证,如果验证错误4次则此卡就被作废。
(2)设置参数
当通过传输密码验证后,就可以修改配置区,这样就能为后边的读写用户数据做好准备。
既然是加密卡,那数据的访问肯定是要有密码验证才能正确读写,所以需要配置用户密码,即写入Password的 Wtite 0 和 Read 0 Write 1和Read1,具体哪个区使用哪套密码都可以指定,在介绍WP0,WP1部分有解说,修改后还要配置Access Registers,其中的 WPE位和 RPE位是指定写、读是否需要密码验证,写 0 使能。如果写密码验证使能,则在写用户区时需要先做验证后才能写入
(3)读写用户区
当去读配置区的设置(AR)后,就会知道用户区是否被加密,如果加密就要验证对应的密码才能访问用户区,AT88S153可以任意访问其中的某一字节。

(4)认证
整个认证过程是一个双向认证的过程。
用户系统的MCU首先从芯片中读出Nc和Ci,根据自定义的F1(Nc,Ks)算法算出Gc,同时利用芯片内部的F2(Gc,Ci,Q0)算法算出Q1,并向芯片发送初始化认证参数Q1和Q0,其中,Q0是CPU方给出的随机数。芯片内部则利用自己的F2逻辑算出Ci+1=F2(Gc,Ci,Q0),同时得出Q2=F2(Gc,Q1)。芯片收到校验认证命令后,判断是否Ci+1=Q1,如是,则有Ci+2=F2(Gc,Ci+1),且用Ci+2更新Ci,芯片中的认证通过;同时更新芯片内部同组的SK(Session Encryption Key)的值。CPU方接收芯片中更新的Ci后,判断是否等于Q2,如果通过,则认证全部通过。
上面说的过程是认证模式,如果想进入加密难证模式的话,需要再次利用认证成功时返回更新的SK值,用它取代Gc,Ci再作为参数;利用F2函数,芯片和MCU方再计算一次并比较,判断相等后才进入加密认证模式。
上面提到的F2算法,是芯片内部的控制逻辑利用Gc、Ci、Q0三个参数初始化的一个DES算法的变种。这个算法是所有加密解密、完整性认证与信息认证的关键。

以下是测试代码:

/**
    SCL -- SCI_CLK -- PA8
    SDA -- SCI_IO   -- PA10
    REST -- SCI_RSTN -- PA9
    VCC -- 

    写数据时候需要适当延时
*/


#define ZNG_GPIOA_BASE  (0X4001D000)
#define ZNG_GPIOB_BASE  (0X4001D010)
#define ZNG_GPIOC_BASE  (0X4001D020)
#define ZNG_GPIOD_BASE  (0X4001D030)

#define ZNG_GPIOA_IODR  (ZNG_GPIOA_BASE)
#define ZNG_GPIOA_BSSR  (ZNG_GPIOA_BASE + 0X04)
#define ZNG_GPIOA_OEN   (ZNG_GPIOA_BASE + 0X08)
#define ZNG_GPIOA_PUE   (ZNG_GPIOA_BASE + 0X0C)

#define ZNG_GPIOA_ALT   (ZNG_GPIOA_BASE + 0X180)

#define REST_L              (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x02000000)
#define REST_H              (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x00000200)

#define SCL_L                   (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x01000000)
#define SCL_H                   (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x00000100)

#define SDA_L                   (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x04000000)   
#define SDA_H                   (*(volatile unsigned int *)(ZNG_GPIOA_BSSR) |= 0x00000400) 

#define SDA_IN              (*(volatile unsigned int *)(ZNG_GPIOA_OEN) |= 0x00000400); \
                                            (*(volatile unsigned int *)(ZNG_GPIOA_PUE) |= 0x00000400)

#define SDA_OUT             (*(volatile unsigned int *)(ZNG_GPIOA_OEN) &= ~0x00000400); \
                                            (*(volatile unsigned int *)(ZNG_GPIOA_PUE) |= 0x00000400)

#define SDA_READ            ((*(volatile unsigned int *)(ZNG_GPIOA_IODR) >> 26)& 0x00000001)

#define VCC_EN          
#define VCC_DS  

#define DELY_TIME           2


#define ZONE_NUM_USER0  0
#define ZONE_NUM_USER1  1
#define ZONE_NUM_USER2  2
#define ZONE_NUM_CONFIG 3


#define ERR_NO                  (0)
#define ERR_PASSWORD(-1)
#define ERR_CARDINVALID             (-2)
#define FAIL_CMDSEND  (3)
#define FAIL_WRDATA   (4)
#define FAIL_RDDATA   (5)

int i2c_card_init()
{
//  GPIO_InitTypeDef GPIO_InitStructure; 
    //PA-8 9、10配置为IO,配置IO的ALT1输出模式为开漏输出+上拉
    //*(volatile unsigned int *)(ZNG_GPIOA_ALT) &= ~0x00150000;
//  GPIO_PinRemapConfig(GPIOA, GPIO_Pin_4  | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14, GPIO_Remap_1);
    *(volatile unsigned int *)(ZNG_GPIOA_OEN) &= ~0x00000700;
    *(volatile unsigned int *)(ZNG_GPIOA_PUE) |= 0x0000700;
    REST_L;
    SDA_L;
    SCL_L;

    return 0;
}
void sda_set_out()
{
    GPIO_InitTypeDef GPIO_InitStructure; 
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Remap = GPIO_Remap_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void sda_set_in()
{
    GPIO_InitTypeDef GPIO_InitStructure; 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Remap = GPIO_Remap_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}
int sda_read()
{
//  (*(volatile unsigned int *)(ZNG_GPIOA_PUE) &= ~0x00000400);
    if((*(volatile unsigned int *)(ZNG_GPIOA_IODR) & 0x04000000) != 0)
        return 1;
    else
        return 0;
}

static void i2c_wait_clock(int n)
{
    int i;
    for(i = 0;i < n ;i++)
    {
        SCL_H;
        CpuLoopDelayUs(DELY_TIME);
SCL_L;
        CpuLoopDelayUs(DELY_TIME);
    }
}

static void i2c_start(void)
{
SDA_OUT;
SDA_H;
SCL_H;
CpuLoopDelayUs(DELY_TIME);
SDA_L;
CpuLoopDelayUs(DELY_TIME);
SCL_L;
        CpuLoopDelayUs(DELY_TIME);
}
static void i2c_stop(void)
{
        SDA_OUT;
        SDA_L;
SCL_H;
CpuLoopDelayUs(DELY_TIME);
SDA_H;
        CpuLoopDelayUs(DELY_TIME);

}

/**
    write ack or nack
    ack0 : ACK  1 : NACK
*/
static void i2c_wr_ack(unsigned char ack)  
{  
        SDA_OUT;
        CpuLoopDelayUs(DELY_TIME);
if(ack)
            SDA_H;//NACK
else
            SDA_L;//ACK     
SCL_H;
CpuLoopDelayUs(DELY_TIME);
SCL_L;
CpuLoopDelayUs(DELY_TIME);

}
/**
    read ack or nack
    return0 : ACK  1 : NACK
*/
static unsigned char i2c_rd_ack()
{
        unsigned char ack = 0;
        SDA_IN;
        CpuLoopDelayUs(DELY_TIME);
        SCL_H;
        CpuLoopDelayUs(DELY_TIME/2); 
ack = sda_read();//
CpuLoopDelayUs(DELY_TIME/2);  
SCL_L;  
CpuLoopDelayUs(DELY_TIME);  

return ack;  
}

static unsigned char i2c_send_byte(unsigned char byte)  
{  
unsigned char i;
        SDA_OUT;
SCL_L;
for(i = 0;i < 8;i++)
        {  

            if ((byte << i) & 0x80 ) 
                SDA_H;
            else
                SDA_L;
            CpuLoopDelayUs(DELY_TIME);
            SCL_H;
            CpuLoopDelayUs(DELY_TIME);
            SCL_L;  

            CpuLoopDelayUs(DELY_TIME);
        }

 return i2c_rd_ack();

}
static unsigned char i2c_read_byte(unsigned char ack)  
{  
unsigned char i;  
unsigned char byte=0;  

SDA_H;
        SDA_IN;
for(i = 0;i < 8;i++)  
        {  

             byte <<= 1;  
             CpuLoopDelayUs(DELY_TIME);
             SCL_H;  
             CpuLoopDelayUs(DELY_TIME);
             if(sda_read())  
                     byte |= 0x01;  
             SCL_L;  
             CpuLoopDelayUs(DELY_TIME);
        }

        i2c_wr_ack(ack);//write a ack

return byte;  
}
//------------------------------------------------

/**
    * @brief  读数据
    * @param  zone  :   区域
                                0  User 0
                                1  User 1
                                2    User 2
                                3  Configuration Zone
        @param  addr : zone区的偏移地址 0x00~0x40
        @param  len : data length
        @param  data : 
    * @retval pass          : 0

*/
int i2c_read_eeprom(unsigned char zone,unsigned char addr,unsigned char len,unsigned char *data)
{
        unsigned char i,ack;
        if(zone > 3 || addr > 0x3F || len > 8)
            return -1;
        i2c_start();
        ack = i2c_send_byte(0xB1 | (zone << 2));
//      if(ack)
//      {
//              i2c_stop();
//              return -1;
//      }
        ack = i2c_send_byte(addr & 0x3F);
//      if(ack)
//      {
//              i2c_stop();
//              return -1;
//      }
        for(i = 0;i < len - 1;i++)
        {
            data[i] = i2c_read_byte(0);
        }
        data[i++] = i2c_read_byte(1);
        i2c_stop();
//      i2c_wait_clock(5);
        return i;
}
/**
    * @brief  写数据
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval pass          : 0

*/
unsigned char i2c_write_eeprom(unsigned char zone,unsigned char addr,unsigned char len,unsigned char *data)
{
        int ret;
        unsigned char i,ack;
        if(zone > 3 || addr > 0x3F || len > 8)
            return -1;
        i2c_start();
        ret = i2c_send_byte(0xB0 | (zone << 2));

        ret = i2c_send_byte(addr & 0x3F);

        for(i = 0;i < len;i++)
        {
            ack = i2c_send_byte(data[i]);
//          if(ack)
//              break;
        }
        i2c_stop();
        i2c_wait_clock(8);

        return i;
}


//-------------------------------------------------
//Configuration Zone

//读取ATR  4 Byte
int i2c_card_read_ATR(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x00,0x04,data);
}
//读取历史字节  4 Byte
int i2c_card_read_LHC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x04,0x04,data);
}
//读取厂商代码 2 Byte
int i2c_card_read_FabC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x08,0x02,data);
}
//读取卡制造商代码 2 Byte
int i2c_card_read_CMC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x0A,0x02,data);
}



//读 每个用户区的访问权限 
//num : 0 - 2  : AR0 - AR2
int i2c_card_read_AR(unsigned char num,unsigned char *data)
{
        if(num > 2)
            return -1;
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x0C + num,0x01,data);
}
//写 每个用户区的访问权限
int i2c_card_write_AR(unsigned char num,unsigned char *data)
{
        if(num > 2)
            return -1;
        return i2c_write_eeprom(ZONE_NUM_CONFIG,0x0C + num,0x01,data);
}

//读测试区 1 Byte
int i2c_card_read_MTZ(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x0F,0x01,data);
}
//写测试区 1 Byte
int i2c_card_write_MTZ(unsigned char *data)
{
        return i2c_write_eeprom(ZONE_NUM_CONFIG,0x0F,0x01,data);
}

//读取发行代码 8 Byte
int i2c_card_read_IC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x10,0x08,data);
}
//写发行代码 8 Byte
int i2c_card_write_IC(unsigned char *data)
{
        return i2c_write_eeprom(ZONE_NUM_CONFIG,0x10,0x08,data);
}

//读设备配置寄存器 1 Byte
int i2c_card_read_DCR(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x18,0x01,data);
}
//写设备配置寄存器 1 Byte
int i2c_card_write_DCR(unsigned char *data)
{
        return i2c_write_eeprom(ZONE_NUM_CONFIG,0x18,0x01,data);
}

//读取识别码  7 Byte  通常用作卡的唯一标志即卡号,个人化前定义
int i2c_card_read_NC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x19,0x07,data);
}
//写取识别码  7 Byte  通常用作卡的唯一标志即卡号,个人化前定义
int i2c_card_write_NC(unsigned char *data)
{
        return i2c_write_eeprom(ZONE_NUM_CONFIG,0x19,0x07,data);
}

//身份验证计数器初始值为 81 Byte 
int i2c_card_read_AAC(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x20,0x01,data);
}

//读身份验证计数器 7 Byte 密文,个人化前可写一随机数,认证卡时使用,每次认证会被自动改写
int i2c_card_read_Ci(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x21,0x07,data);
}

/**
    秘钥 8 字节
    由Nc通过F1公式计算出来,在个人化前,写入卡中,个人化后不可访问,认证时作为F2公式的参数

*/
int i2c_card_read_Gc(unsigned char *data)
{
        return i2c_read_eeprom(ZONE_NUM_CONFIG,0x28,0x08,data);
}



//读取读密码 24bits3 Byte

/**
    * @brief  读密码
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval pass          : 0

*/
int i2c_card_read_pwd(unsigned char rw,unsigned char num,unsigned char *data)
{
        int addr = 0;

        addr = (rw << 2) + (num << 3);
        return i2c_read_eeprom(ZONE_NUM_CONFIG, 0x31 + addr, 0x03, data);
}
/**
    * @brief  写密码
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval pass          : 0

*/
int i2c_card_write_pwd(unsigned char rw,unsigned char num,unsigned char *data)
{
        int addr = 0;

        addr = (rw << 2) + (num << 3);
        return i2c_write_eeprom(ZONE_NUM_CONFIG, 0x31 + addr, 0x03, data);
}


/**
    * @brief  读PAC (密码验证计数器)
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval pass          : 0

*/
int i2c_card_read_pac(unsigned char rw,unsigned char num,unsigned char *data)
{
        int addr = 0;

        addr = (rw << 2) + (num << 3);
        return i2c_read_eeprom(ZONE_NUM_CONFIG, 0x30 + addr, 0x01, data);
}
/**
    * @brief  写PAC (密码验证计数器)
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval pass          : 0

*/
int i2c_card_write_pac(unsigned char rw,unsigned char num,unsigned char *data)
{
        int addr = 0;

        addr = (rw << 2) + (num << 3);
        return i2c_write_eeprom(ZONE_NUM_CONFIG, 0x30 + addr, 0x01, data);
}

//-------------------------------------------------


//-------------------------------------------------
/*
    复位卡片,获取ATR
*/

void i2c_card_rest(unsigned char *data)
{
    int i,j,ack;
    unsigned char byte = 0;

    SDA_IN;
    REST_H;
    SCL_L;
    CpuLoopDelayUs(DELY_TIME*50);
    SCL_H;
    CpuLoopDelayUs(DELY_TIME); 
    SCL_L;  
    CpuLoopDelayUs(DELY_TIME); 
    ack = sda_read();// 
    REST_L;
    CpuLoopDelayUs(DELY_TIME*10);//延时
//  if(ack == 0)//检测到IO有低电平,即 Answer
    {
        for(i = 0;i < 4;i++)
        {
            byte = 0;
            for(j = 0;j < 8;j++)  
            {  
                 CpuLoopDelayUs(DELY_TIME);
                 SCL_H;  
                 CpuLoopDelayUs(DELY_TIME);
                 if(sda_read())  
                         byte |= 0x01 << j;
                 else
                         byte &= ~(0x01 << j);
                 SCL_L;
                 CpuLoopDelayUs(DELY_TIME);
            }
            data[i] = byte;
            CpuLoopDelayUs(DELY_TIME*10);
        }
    }

}
void i2c_card_poweron()
{
    unsigned char data[64];
    VCC_EN;
    i2c_card_rest(data);
}
void i2c_card_poweroff()
{
    unsigned char data[64];
    i2c_card_rest(data);
    VCC_DS;
}

//读保险
int i2c_read_fuses(unsigned char *data)
{
        int ret;
        unsigned char ack;

        i2c_start();
        ret = i2c_send_byte(0xBE);
        *data = i2c_read_byte(1);
        i2c_stop();

        return 0;
}
//熔断保险
int i2c_write_fuses(unsigned char data)
{
        int ret;

        i2c_start();
        ret = i2c_send_byte(0xBA);
        ret = i2c_send_byte(data | 0x07);
        i2c_stop();
        return 0;
}

/**
    * @brief  密码验证
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval       : 0

*/
int i2c_verity_password(unsigned char rw,unsigned char num,unsigned char *password)
{
        int ret,i;
        unsigned char ack;

        i2c_start();
        ret = i2c_send_byte(0xB3 | (rw << 3) | (num << 2));

        for(i = 0;i < 3;i++)
        {
            ack = i2c_send_byte(password[i]);
//          if(ack)
//              break;
        }
        i2c_stop();

        return 0;
}

/**
  * @brief  验证密码接口
    * @param  rw    :   读写位
                                0 , 写数据的密码
                                1 , 读数据的密码
        @param  num : Password set number
    * @retval ERR_PASSWORD
                        ERR_CARDINVALID
                        ERR_NO
  */
int i2c_verity_pwd(unsigned char rw,unsigned char num,unsigned char *password)
{
    unsigned char data = 0;
    i2c_verity_password(rw,num,password);
    CpuLoopDelayMs(10);//必要的延时
    i2c_verity_password(rw,num,password);
    CpuLoopDelayMs(10);
    i2c_card_read_pac(rw,num,&data);
    if(data == 0xFF)
        return ERR_NO;
    else if(data == 0x00)
        return ERR_CARDINVALID;//已经锁定
    else 
        return ERR_PASSWORD;//密码错误
}
//验证传输密码
int i2c_verity_source_code(unsigned char *password)
{
    return i2c_verity_pwd(0,1,password);
}

/**
    Initialize Authentication
    data: 
*/
int i2c_init_auth(unsigned char *data)
{
        int i,ret;

        i2c_start();
        ret = i2c_send_byte(0xB2);
        for(i = 0;i < 8;i++)
        {
            data[i] = i2c_read_byte(0);
        }
        i2c_stop();
        return 0;
}
/**
    Verify Authentication
    p: Password set number
*/
int i2c_verify_auth(unsigned char *data)
{
        int i,ret;

        i2c_start();
        ret = i2c_send_byte(0xB6);
        for(i = 0;i < 8;i++)
        {
            data[i] = i2c_read_byte(0);
        }
        i2c_stop();
        return 0;
}

//-------------------------------------------------

//-------------------------------------------------
void i2c_test()
{
        int ret;
        unsigned char data[256] = {0};
        i2c_card_init();

        CpuLoopDelayMs(5);
        i2c_card_rest(data);
        MyPrint(1,"i2c_card_rest \r\n"); 
        MyPrintBuf(1,data,4);
        CpuLoopDelayMs(5);

        i2c_card_read_ATR(data);
//      i2c_card_read_LHC(data);    
//      i2c_card_read_FabC(data);
//      i2c_card_read_CMC(data);

//      ret = i2c_read_fuses(data);

        //Verify Source Code
        data[0] = 0x45;
        data[1] = 0x45;
        data[2] = 0x45;

        i2c_verity_source_code(data);
//      CpuLoopDelayMs(10); 

        //Read source code
//      i2c_card_read_pwd(0,1,data);



        //Write password write0
        data[0] = 'Z';
        data[1] = 'N';
        data[2] = 'G';
//      i2c_card_write_pwd(0,0,data);
//      CpuLoopDelayMs(10);
//      i2c_card_read_pwd(0,0,data);    

//      data[0] = 0xFF;
//      i2c_card_write_pac(0,0,data);
//      CpuLoopDelayMs(10); 


        //Verify Authentication
//      MyMemset(data,0xFF,sizeof(data));
//      i2c_init_auth(data);
//      CpuLoopDelayMs(5);
//      i2c_verify_auth(data);
//      CpuLoopDelayMs(5);  
//      i2c_card_read_AAC(data);

//      //read and write Access Register
//      i2c_card_read_AR(0,&data[1]);
//      data[1] &= ~0x80;
//      i2c_card_write_AR(0,&data[1]);

//      i2c_card_read_AR(1,&data[2]);

//      i2c_card_read_AR(2,&data[3]);


//      ret = i2c_card_read_DCR(data);
//      data[0] = 0xEB;
//      ret = i2c_card_write_DCR(data);
//      CpuLoopDelayMs(5);
//      MyPrint(1,"i2c_card_read_NC ret = %#x\r\n",ret); 
//      ret = i2c_card_read_DCR(data);


//      //Test Zone
//      ret = i2c_card_read_MTZ(data);
//      MyPrint(1,"i2c_card_read_MTZ ret = %#x data:%#x\r\n",ret,data[0]); 
//      data[0] = 0x46;
//      ret = i2c_card_write_MTZ(data);
//      CpuLoopDelayMs(5);
//      ret = i2c_card_read_MTZ(data);
//      MyPrint(1,"i2c_card_read_MTZ ret = %#x data:%#x\r\n",ret,data[0]); 

        //Write Issuer Code
//      ret = i2c_card_read_IC(data);
//      MyPrint(1,"i2c_card_read_IZ %d ::\n%s\r\n",ret,data); 
//      MyPrintBuf(1,data,ret);
//      
        data[0] = 'Z';
        data[1] = 'N';
        data[2] = 'G';
        data[3] = 'R';
        data[4] = 'E';
        data[5] = 'A';
        data[6] = 'D';
        data[7] = '1';

//      ret = i2c_card_write_IC(data);
//      CpuLoopDelayMs(5);
//      MyPrint(1,"i2c_card_write_IC %d ::\n%s\r\n",ret,data); 
//      MyPrintBuf(1,data,ret);

        ret = i2c_card_read_IC(data);
//      
//      ret = i2c_read_eeprom(3,0x08,0x8,data);
//       
//      MyPrintBuf(1,data,ret);
        ret = i2c_card_read_NC(data);
        CpuLoopDelayMs(5);

        i2c_card_read_Ci(data);
        CpuLoopDelayMs(5);


        data[0] = 'Z';
        data[1] = 'N';
        data[2] = 'G';
        i2c_verity_pwd(0,0,data);
        //Write User Zone 0
        data[0] = 0x23;
        data[1] = 0x7A;
        data[2] = 0x97;
        data[3] = 0xE1;
        data[4] = 0x8F;
        data[5] = 0xB7;
        data[6] = 0x5f;
        data[7] = 0xD3;

        ret = i2c_write_eeprom(0,0,8,data);
        MyPrint(1,"i2c_write_eeprom ret = %d\r\n",ret); 
        MyMemset(data,0,sizeof(data));
        CpuLoopDelayMs(5);
        ret = i2c_read_eeprom(0,0x00,0x8,data);
        MyPrint(1,"i2c_read_eeprom %d ::\n%s\r\n",ret,data); 
        MyPrintBuf(1,data,ret);

        ret = i2c_read_eeprom(1,0x00,0x8,data);
//      
//      MyPrint(1,"i2c_read_eeprom %d ::\n%s\r\n",ret,data); 
//      MyPrintBuf(1,data,ret);
//      
//      
        i2c_card_rest(data);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值