使用 S-MAC 计算 MAC 以使用“单个 DES 加最终三重 DES”对数据进行签名

calculate the MAC with S-MAC to sign the data with `single DES plus final triple DES`

我想用 S-MAC 计算 MAC 以在 Secure Channel 中用 single DES plus final triple DES 签署 plain。我尝试如下但没有用。 谁能帮我?谢谢。

byte[] mac_iv = ToHexBytes("0000000000000000");
byte[] mac_key = ToHexBytes("C6713F31B8DC1F8905DFECB4065CB81E"); // S-MAC
byte[] mac_plain = BytesAppend(ToHexBytes("8482000010"), ToHexBytes("1122334455667788"));
byte[] mac_cipher = DES_MAC8_ISO9797_M2_ALG3_Encrypt(mac_iv, mac_key, mac_plain);
Debug.Print("\nmac_cipher: " + ToHexString(mac_cipher));

//

private byte[] DES_MAC8_ISO9797_M2_ALG3_Encrypt(byte[] iv, byte[] key, byte[] plain)
{
    try
    {
        // split the 16 byte key into key A and key B
        var key1 = new byte[8];
        Buffer.BlockCopy(key, 0, key1, 0, key1.Length);

        var key2 = new byte[8];
        Buffer.BlockCopy(key, 8, key2, 0, key2.Length);

        // init DES CBC encryption with key A and an all-zero IV of 8 bytes
        DES des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.CBC;
        des.Padding = PaddingMode.None;
        MemoryStream streamOut = new MemoryStream();
        CryptoStream streamCrypto = new CryptoStream(streamOut, des.CreateEncryptor(key1, iv), CryptoStreamMode.Write);

        // iterate over all full blocks within the message & for each block perform CBC encryption,
        // throwing away the result (using the same cipher instance, you need to keep the state after all)

        int fullBlocks = plain.Length / 8;
        for (int i = 0; i < fullBlocks; i++) {
            int off = i * 8;
            byte[] block = new byte[off + 8];
            Buffer.BlockCopy(plain, off, block, off, block.Length);

            streamCrypto.Write(block, 0, block.Length);
            streamCrypto.FlushFinalBlock();
        }

        // create a final block and copy the left over bytes from the message into it
        byte[] final_block = new byte[8];
        int left = plain.Length % 8;
        Buffer.BlockCopy(plain, left, final_block, left, final_block.Length);

        // at the next position add the initial padding indicator byte
        // ???

        // finalize the CBC encryption by encrypting the final block, and keep the result
        streamCrypto.Write(final_block, 0, final_block.Length);
        streamCrypto.FlushFinalBlock();
        byte[] res = streamOut.ToArray();

        // perform DES ECB decryption over the result with key B, replacing the result
        des.Mode = CipherMode.ECB;
        streamCrypto = new CryptoStream(streamOut, des.CreateDecryptor(key2, iv), CryptoStreamMode.Write);
        streamCrypto.Write(res, 0, res.Length);
        res = streamOut.ToArray();

        // peform DES ECB encryption over the result with key A, replacing the result
        des.Mode = CipherMode.ECB;
        streamCrypto = new CryptoStream(streamOut, des.CreateDecryptor(key1, iv), CryptoStreamMode.Write);
        streamCrypto.Write(res, 0, res.Length);
        res = streamOut.ToArray();

        return res;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    return new byte[0];
}

我在 C# Implementation of Retail MAC Calculation (ISOIEC 9797-1 MAC algorithm 3) 中通过@Jeff2022 的回答解决了我的问题。谢谢。

private static byte[] getCC_MACNbytes(string Key_MAC, byte[] eIFD, string Init_Vec)
{
    byte[] Kmac = StringToByteArray(Key_MAC);

    // Split the 16 byte MAC key into two keys
    byte[] key1 = new byte[8];
    Array.Copy(Kmac, 0, key1, 0, 8);
    byte[] key2 = new byte[8];
    Array.Copy(Kmac, 8, key2, 0, 8);

    DES des1 = DES.Create();
    des1.BlockSize = 64;
    des1.Key = key1;
    des1.Mode = CipherMode.CBC;
    des1.Padding = PaddingMode.None;
    des1.IV = new byte[8];

    DES des2 = DES.Create();
    des2.BlockSize = 64;
    des2.Key = key2;
    des2.Mode = CipherMode.CBC;
    des2.Padding = PaddingMode.None;
    des2.IV = new byte[8];

    // Padd the data with Padding Method 2 (Bit Padding)
    System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream();
    out_Renamed.Write(eIFD, 0, eIFD.Length);
    out_Renamed.WriteByte((byte)(0x80));
    while (out_Renamed.Length % 8 != 0)
    {
        out_Renamed.WriteByte((byte)0x00);
    }
    byte[] eIfd_padded = out_Renamed.ToArray();
    int N_bytes = eIfd_padded.Length/8;  // Number of Bytes 

    byte[] d1 = new byte[8];
    byte[] dN = new byte[8];
    byte[] hN = new byte[8];
    byte[] intN = new byte[8];

    // MAC Algorithm 3
    // Initial Transformation 1
    Array.Copy(eIfd_padded, 0, d1, 0, 8);
    hN = des1.CreateEncryptor().TransformFinalBlock(d1, 0, 8);

    // Split the blocks
    // Iteration on the rest of blocks
    for (int j = 1; j<N_bytes; j++)
    {
        Array.Copy(eIfd_padded, (8*j), dN, 0, 8);
        // XOR
        for (int i = 0; i < 8; i++)
            intN[i] = (byte)(hN[i] ^ dN[i]);

        // Encrypt
        hN = des1.CreateEncryptor().TransformFinalBlock(intN, 0, 8);
    }

    // Output Transformation 3
    byte[] hNdecrypt = des2.CreateDecryptor().TransformFinalBlock(hN, 0, 8);
    byte[] mIfd = des1.CreateEncryptor().TransformFinalBlock(hNdecrypt, 0, 8);

    //  Get check Sum CC
    return mIfd;
}