銀行系統的密鑰有三種,主密鑰/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=[%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 ;
}