首页 > 代码库 > 银行密钥体系

银行密钥体系

银行系统的密钥有三种,主密钥/pinkey/Mackey,其中pinkey是用来加密密码的,而mackey是用来校验报文是否有错码,主密钥是用来加密pinkey和mackey的.

其中主密钥加密pinkey和mackey是是用3des来加解密的

代码如下:

 

/*param:    pKey:密钥(十六进制)    strPlainAKey:需要加解密的字符串(十六进制)     ciperAKey:返回值    iflag:1解密 0加密*/void getCiper(char* pKey, char* strPlainAKey, char* ciperAKey,  int iflag){    unsigned char binPlainAKey[64] = {0};    hex2binary(binPlainAKey, strPlainAKey, strlen(strPlainAKey));    ASCIIStr2BinCharStrBy3DES(pKey,(unsigned char*)binPlainAKey,strlen(strPlainAKey)/2, (unsigned char*)ciperAKey, iflag);}/*param:    pKey:密钥(十六进制)    inBinary:加解密字符串的字节形式    inLen:加解密字符串的长度    binCharString:返回值    iflag:1解密 0加密*/void ASCIIStr2BinCharStrBy3DES(char* pKey, unsigned char* inBinary, int inLen, unsigned char* binCharString,int iflag){    unsigned char targetIdBin[DESBINARY_LEN] = {0}; //TargetIdLen=8    // 3DES encription    unsigned char key[LEN_OF_KEY];    unsigned char block_key[9];       memset(key, 0, LEN_OF_KEY);    hex2binary(key, pKey, strlen(pKey));    DES_key_schedule ks,ks2,ks3;    memset(block_key, 0, sizeof(block_key));      memcpy(block_key, key + 0, 8);     DES_set_key_unchecked((const_DES_cblock*)block_key, &ks);     memcpy(block_key, key + 8, 8);      DES_set_key_unchecked((const_DES_cblock*)block_key, &ks2);    memcpy(block_key, key + 0, 8);      DES_set_key_unchecked((const_DES_cblock*)block_key, &ks3);     unsigned char input[8];    memset(input, 0, sizeof(input));    unsigned char encryptedOutBinary[DESBINARY_LEN];    memset(encryptedOutBinary, 0, sizeof(encryptedOutBinary));    for(int i=0; i<inLen/8; i++)    {        memset(targetIdBin, 0, sizeof(targetIdBin));        memcpy((void*)targetIdBin, (const void*)(inBinary+i*8), 8);        DES_ecb3_encrypt((const_DES_cblock*)targetIdBin, (DES_cblock*)encryptedOutBinary, &ks, &ks2, &ks3, iflag);        binary2char((char*)binCharString+i*16, encryptedOutBinary, DESBINARY_LEN);    }}//// A public function: convert binary string to character string, the character string‘s length = 2 // binary string.// @param charArray: character array. output.// @param binArray: binary array. input.// @param binLen: length of binary array.//void binary2char(char* charArray, const unsigned char* binArray, int binLen){        int i;        for(i = 0; i < binLen; i++)        {                sprintf(charArray + 2*i, "%02X", binArray[i]);        }        charArray[2*i] = \0;}//// A public function: convert hex string to binary string, the hex string‘s length = 2 * binary string.// @param binArray: binary array. output.// @param hexCharArray: character array contains hex string. input.// @param hexLen: length of hex string array. input.//  void hex2binary(unsigned char* binArray, const char* hexCharArray, int hexLen){        if (hexLen%2 != 0)        {            printf("hex2binary(): length of input parameter hexCharArray should be even number!\n");            return;        }        int i, j;        //convert two hex chars to one byte        char atom[2 + 1] = "\0";        for (i = 0, j = 0; i < hexLen/2; i++, j+=2)        {            strncpy(atom, hexCharArray + j, sizeof(atom) - 1);            atom[sizeof(atom) - 1] = \0;            binArray[i] = (unsigned char)strtol(atom, NULL, 16);        }}

 

一般来说,ATM拿到pinkey密文会使用主密钥解密,得到pinkey明文,然后是用帐号+密码生成pinblock明文,然后使用pinkey使用3des加密,然后传给后端

生成pinblock明文的算法为:

 

char uniteBytes(char a,char b){    char c = (int(a-0)<<4)+b-0;    return c;}/**    * getHPin    * 对密码进行转换    * PIN格式    * BYTE 1 PIN的长度    * BYTE 2 – BYTE 3/4/5/6/7 4--12个PIN(每个PIN占4个BIT)    * BYTE 4/5/6/7/8 – BYTE 8 FILLER “F” (每个“F“占4个BIT)    * @param pin String    * @return byte[]    */void getHPin(char* pin, char* encode) {    encode[0] = 6;    encode[1] = uniteBytes(pin[0], pin[1]);    encode[2] = uniteBytes(pin[2], pin[3]);    encode[3] = uniteBytes(pin[4], pin[5]);    encode[4] = 255;    encode[5] = 255;    encode[6] = 255;    encode[7] = 255;}    /**    * getHAccno    * 对帐号进行转换    * BYTE 1 — BYTE 2 0X0000    * BYTE 3 — BYTE 8 12个主帐号    * 取主帐号的右12位(不包括最右边的校验位),不足12位左补“0X00”。    * @param accno String    * @return byte[]    */char* getHAccno(char* accno,char* encode) {    int len = strlen(accno);    int beginPos = len < 13 ? 0 : len - 13;    char arrTemp[13] = {0};    memcpy(arrTemp, accno+beginPos, len-beginPos-1);    char arrAccno[12];    for(int i=0; i<12; i++)    {    arrAccno[i] = (i <= strlen(arrTemp) ? arrTemp[i] : 0);    }    encode[0] = 0;    encode[1] = 0;    encode[2] = uniteBytes(arrAccno[0], arrAccno[1]);    encode[3] = uniteBytes(arrAccno[2], arrAccno[3]);    encode[4] = uniteBytes(arrAccno[4], arrAccno[5]);    encode[5] = uniteBytes(arrAccno[6], arrAccno[7]);    encode[6] = uniteBytes(arrAccno[8], arrAccno[9]);    encode[7] = uniteBytes(arrAccno[10], arrAccno[11]);    return encode;}/**    * getPinBlock    * 标准ANSI X9.8 Format(带主帐号信息)的PIN BLOCK计算    * PIN BLOCK 格式等于 PIN 按位异或 主帐号;    * @param pin String    * @param accno String    * @return byte[]    */void process(char* pin, char* accno,char* pHexRet) {    char arrAccno[128]={0};    getHAccno(accno,arrAccno);    char arrPin[128]={0};    getHPin(pin, arrPin);    unsigned char arrRet[8]={0};    for(int i=0; i<8; i++){    arrRet[i] = (unsigned char)(arrPin[i] ^ arrAccno[i]);    }        binary2char(pHexRet, arrRet, 8);}

 

Mac运算:

ATM拿到mackey,通过主密钥解密得到密钥明文,使用一串双方协议好的macdata格式,通过ANSI 9.19得到macblock,随报文发到后端,后端也会做同样的操作,然后比对,得到校验结果

Ansi 9.19的算法如下

 

void xor(unsigned char *input1,unsigned char *input2,unsigned char *output,int len){    while (len) {        *output++=*input1++^*input2++;        len--;    }}/**@brief: 根据输入数据计算MAC,初始IV向量默认为"x00x00x00x00x00x00x00x00"*@param: sMacKey 密钥*@param: pInData 输入数据*@param: pRetData 计算出来的MAC*@调用自定义xor和des函数*/void MacArithmetic(char *sMacKey,char *inBinary,char *pRetData){//MAC算法://将字符串pInata分为8字节为单位的数据块,不足补x00,分别标号为D1,D2,D3,...,Dn//设置初始向量E0="x00x00x00x00x00x00x00x00"//将E0^D1 —---->E1(E0,D1异或的后结果经使用密钥左8位des加密得到E1)//将E1^D2 ----->E2//如此类推,知道得出En结束,//使用密钥右8位des解密En得到En0//使用密钥左8位加密En0得到En1//En1即是计算出来的MAC    unsigned char sUpData[512];    unsigned char sData[20];    unsigned char sXorData[20];    unsigned char sDesData[20];    int i,n,iNum,iInLen;    unsigned char key[16];    unsigned char block_key[9];       iInLen=strlen(inBinary);    memset(key, 0, sizeof(key));    hex2binary(key, sMacKey, strlen(sMacKey));    DES_key_schedule ks,ks2,ks3;    memset(block_key, 0, sizeof(block_key));      memcpy(block_key, key + 0, 8);     DES_set_key_unchecked((const_DES_cblock*)block_key, &ks);     memcpy(block_key, key + 8, 8);      DES_set_key_unchecked((const_DES_cblock*)block_key, &ks2);    memcpy(block_key, key + 0, 8);      DES_set_key_unchecked((const_DES_cblock*)block_key, &ks3);     memset(sUpData,0,sizeof(sUpData));    memset(sData,0,sizeof(sData));    memset(sXorData,0,sizeof(sXorData));    memset(sDesData,0,sizeof(sDesData));//补全要加密数据成8倍数到sUpData,不足补x00    memcpy(sUpData,inBinary,iInLen);    iNum = iInLen%8;    if (iNum == 0)        n=iInLen/8;    else {        n=iInLen/8+1;        memcpy(sUpData+iInLen,"\0\0\0\0\0\0\0\0",8-iNum);    }    printf("n=%dnsUpData=http://www.mamicode.com/[%s]n",n,sUpData);    memset(sDesData,0,sizeof(sDesData)); //初始向量赋给sDesData    for (i=0;i<n;i++) {        memcpy(sData,sUpData+i*8,8);        xor(sDesData,sData,sXorData,8); //异或        DES_ecb_encrypt((const_DES_cblock*)sXorData, (DES_cblock*)sDesData, &ks,1);    }    DES_ecb_encrypt((const_DES_cblock*)sDesData, (DES_cblock*)sXorData, &ks2,0);    DES_ecb_encrypt((const_DES_cblock*)sXorData, (DES_cblock*)sDesData, &ks,1);    binary2char(pRetData, sDesData, 8);    return ;}