1. 程式人生 > >ANSI-X99MAC演算法和PBOC的3DES MAC演算法,附DES演算法工具

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);  
        }  
    }