C#安全消息解密方法

问题描述 投票:0回答:1

我正在尝试从java到c#实现这个解密方法: https://github.com/ecsec/open-ecard/blob/f66ae48e7bbb2bb27a524e12d3febabf162c17c7/ifd/ifd-protocols/pace/src/main/java/org/openecard/ifd/protocol/pace/SecureMessaging.java#L198C3-L198C90

/**
     * Decrypt the APDU.
     *
     * @param response the response
     * @param secureMessagingSSC the secure messaging ssc
     * @return the byte[]
     * @throws Exception the exception
     */
     private byte[] decrypt(byte[] response, byte[] secureMessagingSSC) throws Exception {
    ByteArrayInputStream bais = new ByteArrayInputStream(response);
    ByteArrayOutputStream baos = new ByteArrayOutputStream(response.length - 10);

    // Status bytes of the response APDU. MUST be 2 bytes.
    byte[] statusBytes = new byte[2];
    // Padding-content indicator followed by cryptogram 0x87.
    byte[] dataObject = null;
    // Cryptographic checksum 0x8E. MUST be 8 bytes.
    byte[] macObject = new byte[8];

    /*
     * Read APDU structure
     * Case 1: DO99|DO8E|SW1SW2
     * Case 2: DO87|DO99|DO8E|SW1SW2
     * Case 3: DO99|DO8E|SW1SW2
     * Case 4: DO87|DO99|DO8E|SW1SW2
     */
    byte tag = (byte) bais.read();

    // Read data object (OPTIONAL)
    if (tag == (byte) 0x87) {
        int size = bais.read();
        if (size > 0x80) {
        byte[] sizeBytes = new byte[size & 0x0F];
        bais.read(sizeBytes, 0, sizeBytes.length);
        size = new BigInteger(1, sizeBytes).intValue();
        }
        bais.skip(1); // Skip encryption header
        dataObject = new byte[size - 1];
        bais.read(dataObject, 0, dataObject.length);

        tag = (byte) bais.read();
    }

    // Read processing status (REQUIRED)
    if (tag == (byte) 0x99) {
        if (bais.read() == (byte) 0x02) {
        bais.read(statusBytes, 0, 2);
        tag = (byte) bais.read();
        }
    } else {
        throw new IOException("Malformed Secure Messaging APDU");
    }

    // Read MAC (REQUIRED)
    if (tag == (byte) 0x8E) {
        if (bais.read() == (byte) 0x08) {
        bais.read(macObject, 0, 8);
        }
    } else {
        throw new IOException("Malformed Secure Messaging APDU");
    }

    // Only 2 bytes status should remain
    if (bais.available() != 2) {
        throw new IOException("Malformed Secure Messaging APDU");
    }

    // Calculate MAC for verification
    CMac cmac = getCMAC(secureMessagingSSC);
    byte[] mac = new byte[16];

    synchronized (cmac) {
        ByteArrayOutputStream macData = new ByteArrayOutputStream();

        // Write padding-content
        if (dataObject != null) {
        TLV paddedDataObject = new TLV();
        paddedDataObject.setTagNumWithClass((byte) 0x87);
        paddedDataObject.setValue(ByteUtils.concatenate((byte) 0x01, dataObject));
        macData.write(paddedDataObject.toBER());
        }
        // Write status bytes
        TLV statusBytesObject = new TLV();
        statusBytesObject.setTagNumWithClass((byte) 0x99);
        statusBytesObject.setValue(statusBytes);
        macData.write(statusBytesObject.toBER());

        byte[] paddedData = pad(macData.toByteArray(), 16);
        cmac.update(paddedData, 0, paddedData.length);

        cmac.doFinal(mac, 0);
        mac = ByteUtils.copy(mac, 0, 8);
    }

    // Verify MAC
    if (!ByteUtils.compare(mac, macObject)) {
        throw new GeneralSecurityException("Secure Messaging MAC verification failed");
    }

    // Decrypt data
    if (dataObject != null) {
        Cipher c = getCipher(secureMessagingSSC, Cipher.DECRYPT_MODE);
        byte[] data_decrypted = c.doFinal(dataObject);
        baos.write(unpad(data_decrypted));
    }

    // Add status code
    baos.write(statusBytes);

    return baos.toByteArray();
    }

这是我的方法,我不知道如何实现注释部分:

       public byte[] decrypt(byte[] response, byte[] secureMessagingSSC)
        {
            using (MemoryStream bais = new MemoryStream(response))
            using (MemoryStream baos = new MemoryStream(response.Length - 10))
            {
                byte[] statusBytes = new byte[2];
                byte[] dataObject = null;
                byte[] macObject = new byte[8];
                byte tag = (byte)bais.ReadByte();

                if (tag == 0x87)
                {                
                    int size = bais.ReadByte();
                    if (size > 0x80)
                    {
                        byte[] sizeBytes = new byte[size & 0x0F];
                        bais.Read(sizeBytes, 0, sizeBytes.Length);
                        size = new BigInteger(1, sizeBytes).IntValue;
                    }
                    bais.Seek(1, SeekOrigin.Current); // Skip encryption header
                    dataObject = new byte[size - 1];
                    bais.Read(dataObject, 0, dataObject.Length);

                    tag = (byte)bais.ReadByte();
                }

                if (tag == 0x99)
                {

                    if (bais.ReadByte() == 0x02)
                    {
                        bais.Read(statusBytes, 0, 2);
                        tag = (byte)bais.ReadByte();
                    }
                }
                else
                {
                    throw new IOException("Malformed Secure Messaging APDU");
                }

                if (tag == 0x8E)
                {

                    if (bais.ReadByte() == 0x08)
                    {
                        bais.Read(macObject, 0, 8);
                    }
                }
                else
                {
                    throw new IOException("Malformed Secure Messaging APDU");
                }

                // Only 2 bytes status should remain
                if (bais.Length - bais.Position != 2)
                {
                    throw new IOException("Malformed Secure Messaging APDU");
                }

        // Calculate MAC for verification
        CMac cmac = getCMAC(secureMessagingSSC);
        byte[] mac = new byte[16];

        lock (cmac)
        {
            MemoryStream macData = new MemoryStream();

            // Write padding-content
            if (dataObject != null)
            {
                TLV paddedDataObject = new TLV();
                paddedDataObject.SetTagNumWithClass(0x87);
                paddedDataObject.SetValue(ByteUtils.Concatenate((byte)0x01, dataObject));
                macData.Write(paddedDataObject.ToBER(), 0, paddedDataObject.ToBER().Length);
            }
            // Write status bytes
            TLV statusBytesObject = new TLV();
            statusBytesObject.SetTagNumWithClass(0x99);
            statusBytesObject.SetValue(statusBytes);
            macData.Write(statusBytesObject.ToBER(), 0, statusBytesObject.ToBER().Length);

            byte[] paddedData = pad(macData.ToArray(), 16);
            cmac.BlockUpdate(paddedData, 0, paddedData.Length);

            cmac.DoFinal(mac, 0);
            mac = ByteUtils.Copy(mac, 0, 8);
        }

        // Verify MAC
        if (!ByteUtils.Compare(mac, macObject))
        {
            throw new GeneralSecurityException("Secure Messaging MAC verification failed");
        }
                baos.Write(statusBytes, 0, statusBytes.Length);


                return baos.ToArray();
            }
        }

当我解密加密值时,我总是有 900 : 您可以在这里测试代码:https://dotnetfiddle.net/33V9Bl

java c# cryptography smartcard apdu
1个回答
0
投票

身份验证失败,因为您的

TLV
类和/或与其关联的类的实现存在缺陷。这可以通过直接实现该功能来轻松验证,一次用于
dataObject
:

byte[] tlv_dataObject = [0x01, ..dataObject];
tlv_dataObject = [0x87, (byte)tlv_dataObject.Length, ..tlv_dataObject];
macData.Write(tlv_dataObject);

一次

statusBytesObject

byte[] tlv_statusBytesObject = [0x99, (byte)statusBytes.Length, ..statusBytes];
macData.Write(tlv_statusBytesObject, 0, tlv_statusBytesObject.Length);

完成此更改后,身份验证成功。

请注意,上述代码不能替代

TLV
及其关联类的完整且正确的移植。为了使所有用例正常工作,必须移植所有必需的功能。

TLV
及其关联类实现数据的 ASN.1/DER 编码,请参阅此处。另一种移植方法是识别所有必需的功能并使用 C# 库中合适的 ASN.1/DER 编码器/解码器。


缺失的解密可以紧凑地实现,例如与

Aes#DecryptCbc()
:

using System.Security.Cryptography;
...
using (Aes aes = Aes.Create())
{
    aes.Key = keyENC;
    byte[] decyptedPadded = aes.DecryptCbc(dataObject, getCipherIV(secureMessagingSSC), PaddingMode.None);
    byte[] decrypted = Unpad(decyptedPadded);
    baos.Write(decrypted);
} 

这样修改后,密文就成功解密了。

© www.soinside.com 2019 - 2024. All rights reserved.