2008-12-11 43 views
10

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

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

+0

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 ... –

Trả lời

2

Hầu hết CBC MAC các thuật toán được triển khai trong nhà cung cấp JCE của BouncyCastle.

Nhìn vào: BouncyCastleProvider.java

Bạn đang có lẽ tìm kiếm DESEDEISO9797ALG1MACWITHISO7816-4PADDING, đó là một bí danh cho DESEDEMAC64WITHISO7816-4PADDING, khai báo ở đây (tốt, nó là một cấu hình cụ thể của CBCBlockCipherMac sử dụng DESedeEngine và ISO7816d4Padding, bạn sẽ phải nhảy giữa một số lớp học để có được hình ảnh đầy đủ): JCEMac.java

Ngoài ra, có một cái nhìn tại jPos:

JCESecurityModule.java

và góp phần bán lẻ MAC thực hiện thuật toán của họ:

retail-mac-contributed-by-vsalaman.zip

0

Tôi khá chắc chắn (IIRC) mà bạn cần phải gọi TransformFinalBlock vào cuối (mỗi encryptor).

0

Không thể trả lời cho thiết bị đầu cuối cụ thể của bạn, nhưng tôi sử dụng điều này để kiểm tra MAC.

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