Dường như có 6 biến thể đối với thuật toán CBC-MAC. Tôi đã cố gắng để phù hợp với thuật toán MAC trên PINPad 1000SE [mà theo hướng dẫn là ISO 9797-1 Algorithm 1].Thuật toán ISO 9797-1 1 [CBC-MAC] trong C#
Tôi đã có một khởi đầu tuyệt vời từ here.
Và tôi mã hóa thuật toán như sau:
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;
}
Sau đó, tôi phát hiện có đang 3 phương án đệm và một trong đó đã cho tôi một sự khởi đầu có thể không nhất thiết phải đúng. Hướng dẫn đến để giải cứu tôi một lần nữa. Có vẻ như thiết bị chỉ có miếng đệm bằng 0. khối bổ sung cũng là hư không đề cập vì vậy tôi đã thay đổi dưới đây:
Action<byte[], int> prepArray = (bArr, offset) =>
{
bArr[offset] = 0; ... }
Không khối bổ sung (nếu mod 0 [chia hết cho 8] không thay đổi chiều dài mảng)
var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 0);
Các gợi ý ban đầu muốn tôi để giải mã ở bước thứ hai ... nhưng Valery here cho thấy rằng nó mã hóa tất cả các cách. Vì vậy, tôi đã thay đổi Decrypt thành Encrypt. Nhưng tôi vẫn không thể nhận được MAC cần thiết ...
Hướng dẫn sử dụng cho khóa "6AC292FAA1315B4D8234B3A3D7D5933A" [vì khóa phải là 16 byte, tôi đã tìm khóa ở đây là chuỗi hex nên tôi lấy giá trị byte là 6A, C2 , 92, FA ... byte mới [] {106, 194, 146, ...] MAC phải là 7B, 40, BA, 95 [4 byte] nếu thông báo là [mảng 0x1a + MENTERODOMETER]
Ai đó có thể trợ giúp? Xin vui lòng?
Kể từ Pinpad đòi hỏi ký tự đầu tiên trong bài viết là một 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);
}
Tôi gọi đoạn mã trên với đầu vào này:
var result = pad.CalculateAugmentedMAC("MENTERODOMETER", new byte[] { 106, 194, 146, 250, 161, 49, 91, 77, 130, 52, 179, 163, 215, 213, 147, 58 });
Tò mò. Tại sao bạn cần phải tham gia vào việc en/giải mã dữ liệu PINPad? Quy trình làm việc của PINPad được thiết kế để gửi dữ liệu được mã hóa trực tiếp đến ngân hàng của người bán bằng các khóa DUKPT do ngân hàng tạo và được cài đặt trong PINPad bởi Nhà cung cấp PINPad. Thậm chí đến khi chúng tôi viết phần mềm để kiểm soát trực tiếp giao diện người dùng và hành vi khác của PINPads, chúng tôi cũng không thể mã hóa/giải mã phong bì dữ liệu mã PIN được cung cấp như một phần của quy trình. – Bill
Bill, bạn nói đúng ... Nhưng nếu bạn viết một ứng dụng quản lý khách hàng trung thành, cho phép khách hàng quen biết mã PIN, bạn cần sử dụng nó mà không cần các khóa được lập trình trước đó ... Mô hình trước đó của PINPad 1000SE - không thể nhớ trên đầu của tôi - đã cho phép bạn nhận được mã PIN và gửi đó dưới dạng văn bản rõ ràng. Các mô hình sau này mã hóa mã PIN và chúng tôi không thể nhận được mã PIN ... –