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