2008-12-11 46 views
10

似乎CBC-MAC算法有6種變化。我一直試圖在PINPad 1000SE [每個手冊是ISO 9797-1算法1]上匹配MAC算法。ISO 9797-1算法1 [CBC-MAC] in C#

我從here得到了一個很好的開始。

我編碼如下算法:

public static byte[] CalculateMAC(this IPinPad pinpad, byte[] message, byte[] key) 
{ 
    //Divide the key with Key1[ first 64 bits] and key2 [last 64 bits] 
    var key1 = new byte[8]; 
    Array.Copy(key, 0, key1, 0, 8); 

    var key2 = new byte[8]; 
    Array.Copy(key, 8, key2, 0, 8); //64 bits 

    //divide the message into 8 bytes blocks 
    //pad the last block with "80" and "00","00","00" until it reaches 8 bytes 
    //if the message already can be divided by 8, then add 
    //another block "80 00 00 00 00 00 00 00" 
    Action<byte[], int> prepArray = (bArr, offset) => 
            { 
             bArr[offset] = 0; //80 
             for (var i = offset + 1; i < bArr.Length; i++) 
              bArr[i] = 0; 
            }; 
    var length = message.Length; 
    var mod = length > 8? length % 8: length - 8; 

    var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 0); 
    //var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 8); 
    Debug.Assert(newLength % 8 == 0); 

    var arr = new byte[newLength]; 
    Array.Copy(message, 0, arr, 0, length); 
    //Encoding.ASCII.GetBytes(message, 0, length, arr, 0); 
    prepArray(arr, length); 
    //use initial vector {0,0,0,0,0,0,0,0} 
    var vector = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; 

    //encrypt by DES CBC algorith with the first key KEY 1 
    var des = new DESCryptoServiceProvider { Mode = CipherMode.CBC }; 
    var cryptor = des.CreateEncryptor(key1, vector); 
    var outputBuffer = new byte[arr.Length]; 
    cryptor.TransformBlock(arr, 0, arr.Length, outputBuffer, 0); 

    //Decrypt the result by DES ECB with the second key KEY2 [Original suggestion] 
    //Now I'm Encrypting 
    var decOutputBuffer = new byte[outputBuffer.Length]; 
    des.Mode = CipherMode.ECB; 
    var decryptor = des.CreateEncryptor(key2, vector); 
    //var decryptor = des.CreateDecryptor(key2, vector); 
    decryptor.TransformBlock(outputBuffer, 0, outputBuffer.Length, decOutputBuffer, 0); 

    //Encrypt the result by DES ECB with the first key KEY1 
    var finalOutputBuffer = new byte[decOutputBuffer.Length]; 
    var cryptor2 = des.CreateEncryptor(key1, vector); 
    cryptor2.TransformBlock(decOutputBuffer, 0, decOutputBuffer.Length, finalOutputBuffer, 0); 

    //take the first 4 bytes as the MAC 
    var rval = new byte[4]; 
    Array.Copy(finalOutputBuffer, 0, rval, 0, 4); 
    return rval; 
} 

後來我發現那裏是3個填充方案,這給了我一跳不一定是正確的一個。手冊又來了我的救援。看來該設備只填充0。其他塊也是無處提到所以我作出了以下改變:

Action<byte[], int> prepArray = (bArr, offset) => 
            { 
             bArr[offset] = 0; ... } 

無需額外的塊(如果MOD 0 [8整除]不改變陣列長度)

var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 0); 

原始的建議要我在第二步解密......但Valery here表明它一直在進行加密。所以我把Decrypt改成了Encrypt。但仍然我無法獲得必要的MAC ...

手冊中說「6AC292FAA1315B4D8234B3A3D7D5933A」[因爲密鑰應該是16個字節,我想這裏的關鍵是十六進制字符串,所以我把字節值6A,C2 ,92,FA ... 如果消息是[0x1a + MENTERODOMETER的字節數組],MAC應該是7B,40,BA,95 [4字節],新字節[] {106,194,146,...]

有人可以幫忙嗎?請?


由於Pinpad需要在消息中的第一個字符是0X1A ...

public static byte[] CalculateAugmentedMAC(this IPinPad pinpad, string message, byte[] key) 
{ 
    var arr = new byte[message.Length + 1]; 
    var source = Encoding.ASCII.GetBytes(message); 
    arr[0] = 0x1a; //ClearScreenIndicator 
    Array.Copy(source, 0, arr, 1, source.Length); 
    return CalculateMAC(pinpad, arr, key); 
} 

我正在與該輸入呼叫上面的代碼:

var result = pad.CalculateAugmentedMAC("MENTERODOMETER", new byte[] { 106, 194, 146, 250, 161, 49, 91, 77, 130, 52, 179, 163, 215, 213, 147, 58 }); 
+2

好奇。你爲什麼需要參與解密PINPad數據? PINPad工作流程旨在使用由銀行生成並由PINPad供應商安裝在PINPad中的DUKPT密鑰將加密數據直接發送至商戶銀行。即使到了我們編寫軟件來直接控制各種PINPads的UI和其他行爲的程度,我們也無法加密/解密作爲該過程一部分提供的加密PIN數據信封。 – Bill 2009-09-18 13:50:42

回答

2

大多數CBC MAC算法在BouncyCastle的JCE提供程序中實現。

看:BouncyCastleProvider.java

你可能尋找DESEDEISO9797ALG1MACWITHISO7816-4PADDING,這是DESEDEMAC64WITHISO7816-4PADDING的別名,在這裏實現(當然,它使用DESedeEngine和ISO7816d4Padding是CBCBlockCipherMac的具體配置,你必須跳一些類之間得到充分的畫面): JCEMac.java

而且,看看初級警務人員:

JCESecurityModule.java

和他們的貢獻零售MAC算法的實現:

retail-mac-contributed-by-vsalaman.zip

0

我敢肯定(IIRC),您需要在(每加密)結束調用TransformFinalBlock

0

無法回答您的特定終端,但我用它來測試MAC。

public static byte[] GenerateMAC(byte[] key, byte[] data) 
{ 
    using (MACTripleDES mac = new MACTripleDES(key)) 
     return mac.ComputeHash(data); 
}