10

CBC-MAC算法似乎有6种变体。我一直在尝试匹配 PINPad 1000SE 上的 MAC 算法 [根据手册是 ISO 9797-1 算法 1]。

我从这里有了一个很好的开始。

我将算法编码如下:

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 建议它一直加密。所以我将解密更改为加密。但我仍然无法获得必要的 MAC ......

手册说密钥“6AC292FAA1315B4D8234B3A3D7D5933A”[因为密钥应该是 16 个字节,我认为这里的密钥是十六进制字符串,所以我取了 6A、C2、92、FA 的字节值 ... new byte[] { 106, 194, 146, ...] 如果消息是 [0x1a + MENTERODOMETER 的字节数组],MAC 应该是 7B,40,BA,95 [4 个字节]

有人可以帮忙吗?请?


由于 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 });
4

3 回答 3

2

大多数 CBC MAC 算法都在BouncyCastle的 JCE 提供程序中实现。

看:BouncyCastleProvider.java

您可能正在寻找DESEDEISO9797ALG1MACWITHISO7816-4PADDING,它是 的别名DESEDEMAC64WITHISO7816-4PADDING,在此处实现(嗯,它是使用 DESedeEngine 和 ISO7816d4Padding 的 CBCBlockCipherMac 的特定配置,您必须在一些类之间跳转才能获得完整的图片): JCEMac.java

另外,看看jPos:

JCESecurityModule.java

以及他们贡献的零售 MAC 算法实现:

零售-mac-contributed-by-vsalaman.zip

于 2009-09-22T12:46:34.433 回答
0

无法回答您的特定终端,但我用它来测试 MAC。

public static byte[] GenerateMAC(byte[] key, byte[] data)
{
    using (MACTripleDES mac = new MACTripleDES(key))
        return mac.ComputeHash(data);
}
于 2010-08-04T15:49:46.090 回答
0

我很确定(IIRC)你需要TransformFinalBlock在最后(每个加密器)调用。

于 2009-09-22T12:51:30.990 回答