AT88SCXX有三种模式:普通读写,密码验证,身份认证,加密认证;
身份认证:主机读取设备的Cryptogram C 和Secret Seed G 。主机生成随机数与Cryptogram C 和Secret Seed G
相结合生成一个挑战码。挑战码生成(由DES(F1,F2)算法计算出);再将主机生成的八字节随机数和八字节的挑战码发送给设备。最后重新读取Cryptogram ,将读取的Cryptogram 与主机自己生成的Cryptogram(由DES(F1,F2)算法产生)比较。相同则成功。
加密认证:身份认证后进行加密认证。过程与身份认证类似,将身份认证中的Secret Seed替换成Session Encryption Key(由身份认证时(DES(F1,F2)算法产生))。
假设用户区0:使用加密认证,步骤:(1)主机读取设备的Cryptogram C 和Secret Seed G 。主机生成随机数与设备Cryptogram C 和Secret Seed G相结合生成一个挑战码。挑战码生成(由DES(F1,F2)算法计算出);再将主机生成的八字节随机数和八字节的挑战码发送给设备。最后重新读取Cryptogram ,将读取的Cryptogram 与主机自己生成的Cryptogram(由DES(F1,F2)算法产生)比较。相同则成功,重复(1)过程,只要将(1)过程中的Secret Seed替换成Session Encryption Key。
注意:在身份认证成功后需要将Cryptogram 加入到F1,F2算法中。
DES算法(F1,)头文件
#define RA (ucGpaRegisters[0])
#define RB (ucGpaRegisters[1])
#define RC (ucGpaRegisters[2])
#define RD (ucGpaRegisters[3])
#define RE (ucGpaRegisters[4])
#define RF (ucGpaRegisters[5])
#define RG (ucGpaRegisters[6])
#define TA (ucGpaRegisters[7])
#define TB (ucGpaRegisters[8])
#define TC (ucGpaRegisters[9])
#define TD (ucGpaRegisters[10])
#define TE (ucGpaRegisters[11])
#define SA (ucGpaRegisters[12])
#define SB (ucGpaRegisters[13])
#define SC (ucGpaRegisters[14])
#define SD (ucGpaRegisters[15])
#define SE (ucGpaRegisters[16])
#define SF (ucGpaRegisters[17])
#define SG (ucGpaRegisters[18])
#define Gpa_byte (ucGpaRegisters[19])
#define Gpa_Regs (20)
// Defines for constants used
#define CM_MOD_R (0x1F)
#define CM_MOD_T (0x1F)
#define CM_MOD_S (0x7F)
// Macros for common operations
#define cm_Mod(x,y,m) ((x+y)>m?(x+y-m):(x+y))
#define cm_RotT(x) (((x<<1)&0x1e)|((x>>4)&0x01))
#define cm_RotR(x) (((x<<1)&0x1e)|((x>>4)&0x01))
#define cm_RotS(x) (((x<<1)&0x7e)|((x>>6)&0x01))
// Externals
extern uint8_t ucGpaRegisters[Gpa_Regs];
DES算法(F1,F2)源代码
返回值即为产生的一个字节挑战码(这里将返回值设置成全局)
// Generate next value
uint8_t cm_GPAGen(uint8_t Datain)
{
uint8_t Din_gpa;
uint8_t Ri, Si, Ti;
uint8_t R_sum, S_sum, T_sum;
// Input Character
Din_gpa = Datain^Gpa_byte;
Ri = Din_gpa&0x1f; //Ri[4:0] = Din_gpa[4:0]
Si = ((Din_gpa<<3)&0x78)|((Din_gpa>>5)&0x07); //Si[6:0] = {
//Din_gpa[3:0], Din_gpa[7:5]
//}
Ti = (Din_gpa>>3)&0x1f; //Ti[4:0] = Din_gpa[7:3];
//R polynomial
R_sum = cm_Mod(RD, cm_RotR(RG), CM_MOD_R);
RG = RF;
RF = RE;
RE = RD;
RD = RC^Ri;
RC = RB;
RB = RA;
RA = R_sum;
//S ploynomial
S_sum = cm_Mod(SF, cm_RotS(SG), CM_MOD_S);
SG = SF;
SF = SE^Si;
SE = SD;
SD = SC;
SC = SB;
SB = SA;
SA = S_sum;
//T polynomial
T_sum = cm_Mod(TE,TC,CM_MOD_T);
TE = TD;
TD = TC;
TC = TB^Ti;
TB = TA;
TA = T_sum;
// Output Stage
Gpa_byte =(Gpa_byte<<4)&0xF0; // shift gpa_byte left by 4
Gpa_byte |= ((((RA^RE)&0x1F)&(~SA))|(((TA^TD)&0x1F)&SA))&0x0F; // concat 4 prev bits and 4 new bits
return Gpa_byte;
}
主机产生挑战码和Ci,sk,
//此函数功能:主机产生自身的Cyptogram和Session Encryption Key ,产生设备需要的挑战码。
/* function Do authenticate/encrypt challenge
* pQ: host generate random number
*
* pCi: read at88sc Cyptogram and generate host Cyptogram
* pCh : cryptogram and secret seed to generate a 64-bit challenge for the devic
* pSK : Secret Seed
*/
void KM_AuthenticationCal(uint8_t *pCi,uint8_t *pSK,uint8_t*pQ ,uint8_t *pCh)
{
int i = 0,j = 0;
cm_ResetCrypto();
// Setup the cyptographic registers
for(j = 0; j < 4 ;j++)//总执行四次。不能更改次数
{
for(i = 0; i<3; i++) cm_GPAGen(pCi[2*j]);
for(i = 0; i<3; i++) cm_GPAGen(pCi[2*j+1]);
cm_GPAGen(pQ[j]);
}
for(j = 0; j<4; j++ ) //总执行四次。不能更改次数
{
for(i = 0; i<3; i++) cm_GPAGen(pSK[2*j]);
for(i = 0; i<3; i++) cm_GPAGen(pSK[2*j+1]);
cm_GPAGen(pQ[j+4]);
}
cm_GPAGenN(6); // 6 0x00s
pCh[0] = Gpa_byte;
for (j = 1; j<8; j++) //总执行8次。不能更改次数
{
cm_GPAGenN(7); // 7 0x00s
pCh[j] = Gpa_byte;
}
pCi[0] = 0xFF;//new ci
for(j = 1; j < 8; j++)//总执行8次。不能更改次数
{
cm_GPAGenN(2); // 2 0x00s
pCi[j] = Gpa_byte;
}
for(j = 0; j < 8; j++)//总执行8次。不能更改次数
{
cm_GPAGenN(2); // new sk
pSK[j] = Gpa_byte;
}
cm_GPAGenN(3);
}
//例子:加密认证
int main()
{
AuthenEncypt();
setUser(0xB4,0x03,zone,0x00);
read(0xB2,0x00,0x00,0x08,缓存的BUFF,大小)//读取用户区
}
bool AuthenEncypt(void)
{
char * Cyptogram[0x08],SecretSeed[0x08],RandomNumber[0x08],Changlleng[0x08];
char *wAT88[0x10];
1.读取设备 Cyptogram,Secret Seed 。
read(指令,高地址,低地址,读取到的八个字节,读取的大小(0x08));//读取
2.主机生成随机数(可自定义八个)
for()
{
RandomNumber[i] = rand()%255+1;
}
3.将读取出来的Cyptogram,Secret Seed,和random 三个相结合。调用函数
void KM_AuthenticationCal(uint8_t *pCi,uint8_t *pSK,uint8_t*pQ ,uint8_t *pCh);
KM_AuthenticationCal(Cyptogram,SecretSeed,RandomNumber,Changlleng);
4.将随机数RandomNumber和挑战码Changlleng合并成一个16字节
for()
{
wAT88[i] = RandomNumber[i];
}
for()
{
wAT88[i+8] = Changlleng[i];
}
5.发送到AT88SC
write(0xB8,0x0X(X=key set 0-3),0x00,0x10);
6.读AT88SC配置区中Cryptogram(G0-G3)所对应的八字节
read(0xB6,0x00,0x50(例如选择G0),0x08,存放Cryptogram缓冲区wAT88);
7.比较读到的Cryptogram和主机产生的Cryptogram。
for(i = 0; i < 8; i++)
{
if(Cyptogram[i] != wAT88[i])//Cyptogram在调用KM_AuthenticationCal时候产生的,wAT88c执行完第五步后产生的。
{
//错误提示,身份认证失败
}
}
8.执行完成第七部后如果成功,就执行第八步:注意第八步的第三小步:
1.读取设备 Cyptogram,Secret Seed 。
read(指令,高地址,低地址,读取到的八个字节,读取的大小(0x08));//读取
2.主机生成随机数(可自定义八个)
for()
{
RandomNumber[i] = rand()%255+1;
}
3.重新读取设备Cyptogram。在上面的第三大步中产生了一个Session Encryption Key 在变量SecretSeed[0x08]八个字节
void KM_AuthenticationCal(uint8_t *pCi,uint8_t *pSK,uint8_t*pQ ,uint8_t *pCh);
KM_AuthenticationCal(Cyptogram,SecretSeed,RandomNumber,Changlleng);
4.将随机数RandomNumber和挑战码Changlleng合并成一个16字节
for()
{
wAT88[i] = RandomNumber[i];
}
for()
{
wAT88[i+8] = Changlleng[i];
}
5.发送到AT88SC
write(0xB8,0x1X(X=key set 0-3),0x00,0x10);
6.读AT88SC配置区中Cryptogram(G0-G3)所对应的八字节
7.比较读到的Cryptogram和主机产生的Cryptogram。
for(i = 0; i < 8; i++)
{
if(Cyptogram[i] != wAT88[i])//Cyptogram在调用KM_AuthenticationCal时候产生的,wAT88c 执行完第五步后产生的。
{
//错误提示,加密认证失败
}
}
9.到这里说明加密认证成功。最后要读写,需要如下:
for(int i = 0; i < 5; i++){
cm_GPAGen(0x00);//执行五次
}
cm_GPAGen(DataIn);//DataIn:在第八步骤中第6小步读出的Cyptogram所在的地址数据。
for(i = 0; i < 8; i++)
{
cm_GPAGen(ucCM_Ci2[i]);//ucCM_Ci2[i] 读出的Cyptogram八个字节。
for(int i = 0; i < 5; i++){
cm_GPAGen(0x00);//执行五次
}
}
}
}
void setUser(0xB4,0x03,zone,0x00);
{
cm_GPAGen(zone);//将第几用户区加入到DES算法中
//发送 0xB4,0x03,zone,0x00这条指令到at88sc
}
void read(0xB2,0x00,0x00,缓存的BUFF,大小len)//读取用户区
{
for(i < 5;)
{
cm_GPAGen(0x00);//需要 for 循环五次
}
cm_GPAGen(0x00);//0x00:要读的区域高地址一般时0x00;注意执行一次
for(i < 5;)
{
cm_GPAGen(0x00);//需要 for 循环五次
}
cm_GPAGen(len);//len:要读取的大小;注意执行一次
发送0xB2,0x00,要读取的地址,要读取的大小len,接收的数据,接收的大小。这条指令到AT88SC
// 最后对读取的数据进行解密:
for(i = 0; i < len(读取的大小);i++)
{
if(加密的话执行if语句里)//加入时读取AT88SC中的配置区,那么这个判断语句必须是一个大 于从密码区的起始地址例如AT88SC104那么这个必须大于 0xB0
{
缓冲区buff[i] = read[i]^Gpa_byte //read[i] 读取到的数据抑或上Gpa_byte :此函数中返 回值的全变量cm_GPAGen();
}
cm_GPAGen(buff[i]);
for(j<5){//单独执行cm_GPAGen(0x00);五次
cm_GPAGen(0x00);
}
}
}
void write()//加密写入用户区
{
for(i < 5;)
{
cm_GPAGen(0x00);//需要 for 循环五次
}
cm_GPAGen(0x00);//0x00:要写入的区域高地址一般时0x00;注意执行一次
for(i < 5;)
{
cm_GPAGen(0x00);// 循环五次
}
cm_GPAGen(len);//len:要写入的大小;注意执行一次
for(i = 0; i < len(读取的大小);i++)
{
temp = write[i]//read[i] 写入到的数据
for(j<5){//单独执行cm_GPAGen(0x00);五次
cm_GPAGen(0x00);
}
if(加密的话执行if语句里)//加入时写入AT88SC中的配置区,那么这个判断语句必须是一个大 于从密码区的起始地址例如AT88SC104那么这个必须大于 0xB0
{
缓冲区buff[i] = read[i]^Gpa_byte //read[i] 读取到的数据抑或上Gpa_byte :此函数中返 回值的全变量cm_GPAGen();
}
cm_GPAGen(temp);
}
}
|