ANSI-X99MAC演算法和PBOC的3DES MAC演算法,附DES演算法工具
/**************************************************
* PBOC-3DES MAC計算
**************************************************/
void PBOC_3DES_MAC( U08 *buf, U32 buf_size, U08 *key, U08 *mac_buf )
{
U08 val[8],xor[8];
U08 keyL[8],keyR[8];
U08 block[512];
U16 x,n;
U16 i;
memcpy(keyL,key,8 );
memcpy(keyR,&key[8],8);
//準備工作
memcpy( block, buf, buf_size ); //將輸入資料賦值給臨時變數block
x = buf_size / 8; //計算有多少個完整的塊
n = buf_size % 8; //計算最後一個塊有幾個位元組
if( n != 0 ) //y非0,則在其後補上0x00...
{
memset( &block[x*8+n], 0x00, 8-n );
block[x*8+n]=0x80;
}
else
{
memset( &block[x*8], 0x00, 8 );//如果最後一塊長度是8個位元組,則最後加80 00。。
block[x*8]=0x80;
}
//開始運算
memset( val, 0x00, 8 );//初始向量
memcpy( val, UPPAN,8 );
DataXOr(val,&block[0], 8,xor);
for( i = 1; i < x+1; i++ ) //有多少塊迴圈多少次
{
CurCalc_DES_Encrypt(keyL,xor,val );//DES加密
DataXOr(val,&block[i*8], 8,xor);
// j += 8; //用於取下一塊的資料
}
CurCalc_DES_Encrypt(keyL,xor,val);
CurCalc_DES_Decrypt(keyR,val,xor);
CurCalc_DES_Encrypt(keyL,xor,val);
memcpy(mac_buf,val, 8 );
}
只要有標準的DES加密和解密演算法,類似ANSI-X99MAC演算法和PBOC3DES演算法就很好實現。他們都是用DES演算法再經過一層演算法實現的。實現原理看圖就能看明白。3DES演算法實現就更簡單了。就是DES演算法再加解密一次。
/*
**************************************************************************************************************
*
* 函式原型:void CurCalc_3DES_Encrypt( U08 *inkey, U08 *indata, U08 *outdata )
*
* 函式功能:3DES加密
*
* 函式輸入:inkey 16位元組密碼
* indata 8位元組需要加密的資料
*
* 函式輸出:outdata 8位元組加密結果輸出
*
* 函式返回:無
*
**************************************************************************************************************
*/
void CurCalc_3DES_Encrypt( U08 *inkey, U08 *indata, U08 *outdata )
{
U08 LKey[8];
U08 RKey[8];
U08 TmpDest[8];
MyCopy( LKey, inkey, 8 );
MyCopy( RKey, inkey+8, 8 );
CurCalc_DES_Encrypt( LKey, indata, outdata ); //加
CurCalc_DES_Decrypt( RKey, outdata, TmpDest ); //解
CurCalc_DES_Encrypt( LKey, TmpDest, outdata ); //加
}
/*
**************************************************************************************************************
*
* 函式原型:void CurCalc_3DES_Decrypt( U08 *inkey, U08 *indata, U08 *outdata )
*
* 函式功能:3DES解密
*
* 函式輸入:inkey 8位元組密碼
* indata 8位元組需要解密的資料
*
* 函式輸出:outdata 8位元組解密結果輸出
*
* 函式返回:無
*
**************************************************************************************************************
*/
void CurCalc_3DES_Decrypt( U08 *inkey, U08 *indata, U08 *outdata )
{
U08 LKey[8];
U08 RKey[8];
U08 TmpDest[8];
MyCopy( LKey, inkey, 8 );
MyCopy( RKey, inkey+8, 8 );
CurCalc_DES_Decrypt( LKey, indata, outdata ); //解
CurCalc_DES_Encrypt( RKey, outdata, TmpDest ); //加
CurCalc_DES_Decrypt( LKey, TmpDest, outdata ); //解
}
222
/*******************************************************
* 名稱:獲取報文MAC值
* 功能:報文MAC演算法
* 入口:
* *buf ,要計算的資料緩衝區;buf_size,計算資料的長度
* *key ,金鑰(8B)
* 出口:mac_buf,計算出來的MAC值(8B)
ansi x9.9 MAC演算法
********************************************************/
void Ansi99X_Get_MAC( U08 *buf, U32 buf_size, U08 *key, U08 *mac_buf )
{
U08 val[8],xor[8];
U08 block[512];
U16 x,n;
U16 i,j=0;
//準備工作
memcpy( block, buf, buf_size ); //將輸入資料賦值給臨時變數block
x = buf_size / 8; //計算有多少個完整的塊
n = buf_size % 8; //計算最後一個塊有幾個位元組
if( n != 0 ) //y非0,則在其後補上0x00...
{
memset( &block[x*8+n], 0x00, 8-n );
x += 1; //將補上的這一塊加上去
}
//開始運算
memset( val, 0x00, 8 );
for( i = 0; i < x; i++ ) //有多少塊迴圈多少次
{
DataXOR(val,&block[j], 8,xor);
CurCalc_DES_Encrypt(key,xor,val);//DES加密
j += 8; //用於取下一塊的資料
}
memcpy(mac_buf,val, 8 );
}
333
/*
*************************************************************************************************
* 異或
*************************************************************************************************
*/
void DataXOR( U08 *source, U08 *dest, U32 size, U08 *out )
{
int i;
for( i = 0; i < size; i++ )
{ out[i] = dest[i] ^ source[i]; }
}
實現MAC演算法的原理,可以參考CPU卡指令手冊或PBOC規範。如圖:
MAC的計算:
Mac計算步驟:
1、 終端向CPU卡傳送GET CHALLENGE指令,取得4位元組隨機數,後補“0x00000000”,得到的8位元組結果作為MAC計算的初始值。
2、 檢查“04D6960024 + val”的位元組數是否為8的倍數,不是則補“0x8000…”,是則補“0x8000000000000000”,然後將得到的結果按8位元組每塊分成D1、D2、D3…
3、 判斷金鑰的長度。
如果金鑰長度為8位元組,則按如下方式計算MAC:
如果金鑰長度為16位元組,則按如下方式計算MAC:
MAC簡介
MAC是使用命令的所有元素(包括命令頭)產生的。一條命令的完整性,包括命令資料域(如果存在的話)中的資料元,通過安全報文傳送得以保證。按照如下的方式使用單重或三重DEA加密方式產生MAC:
第一步:取8個位元組的16進位制數字’0’作為初始變數。
第二步:按照順序將資料串聯在一起形成資料塊。
第三步:將該資料塊分成8位元組為單位的資料塊,標號為D1、D2、D3、D4等。最後的資料塊有可能是1-8個位元組。
第四步:如果最後的資料塊長度是8位元組的話,則在其後加上16進位制數字’80 00 00 00 00 00 00 00’,轉到第五步。如果最後的資料塊長度不足8位元組,則在其後加上16進位制數字’80’,如果達到8位元組長度,則轉入第五步;否則在其後加入16進位制數字’0’直到長度達到8位元組。
第五步:對這些資料塊使用MAC過程金鑰進行加密。如果安全報文傳送支援單長度的MAC DEA金鑰,則依照下圖的方式使用MAC 過程金鑰來產生MAC。
第六步:最終得到是從計算結果左側取得的4位元組長度的MAC。
原始碼實現:
void DoSSMac(const BYTE* input, intnInLen, const BYTE* key, int nKeyLen, BYTE* output)
{
BYTE byInitVec[8]; //初始向量
BYTE byTemp[8];
memset(byInitVec, 0x00,sizeof(byInitVec));
memset(byTemp, 0x00,sizeof(byTemp));
memcpy(byInitVec, input, 8);
BYTEbySubKey[3][16][48]; //祕鑰
memset(bySubKey, 0x01, sizeof(bySubKey));
int i = 0;
int j = (nInLen >> 3);
//構造並生成SubKeys
BYTE nKey = (nKeyLen >> 3) > 3 ?3 : (nKeyLen >> 3);
for (i = 0; i < nKey; i++)
{
SetSubKey(&bySubKey[i], &key[i << 3]);
}
memcpy(output, input, 8);
if (1 == nKey) //單倍長Key(8位元組)
{
j--;
for (int i = 0; i <j; ++i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0], output);
//memcpy(byInitVec, output, 8); //將輸出設定為扭轉變數
}
}
<span style="color:#ff0000;"> //轉換關係就在這裡
else if (2 == nKey) //雙倍長Key(16位元組)
{
j -= 2;
for (i = 0; i < j;++i)
{
Xor(input + 8 * (i + 1), output, 8, output);
RunDes(output, 0, &bySubKey[0],output); //將輸出設定為扭轉變數
}
Xor(input + 8 * (++i),output, 8, output); //最後一塊資料和上面加密結果異或
RunDes(output, 0,&bySubKey[0], output);
RunDes(output, 1,&bySubKey[1], output);
RunDes(output, 0,&bySubKey[0], output);
}</span>
else //三倍長Key(24位元組) 尚未驗證
{
//j -= 2;
for (i = 0, j =(nInLen >> 3) - 2; i < j; ++i, input += 8)
{
Xor(input + 8 * (i + 1), output, 8, byTemp);
RunDes(byTemp, 0, &bySubKey[0], output);
memcpy(byInitVec, output, 8); //將輸出設定為扭轉變數
}
Xor(input + 8 * i,output, 8, output);
RunDes(output, 2,&bySubKey[0], output);
RunDes(output, 1,&bySubKey[1], output);
RunDes(output, 0,&bySubKey[0], output);
}
}