Метод расшифровки безопасных сообщений C#

Я пытаюсь реализовать этот метод расшифровки с Java на С#: 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

Без детального анализа кода кажется, что во втором тесте (который проверяет случай успеха) уже происходит сбой сравнения MAC (т.е. аутентификации), которое выполняется до фактической расшифровки, т.е. либо реализация, либо тестовые данные. неисправен. Вам следует сначала решить эту проблему. Даже если дешифрование реализовано правильно, нельзя ожидать успешного дешифрования, если аутентификация не удалась.

Topaco 05.04.2024 12:04

Проблема в том, что проверка Mac всегда не удалась, и я не знаю, как ее обновить. у меня такое: проверка MAC безопасного обмена сообщениями не удалась. Я реализовал недостающее.

Bouls 05.04.2024 14:15

Проблема в вашей реализации. Это ошибка.

Topaco 05.04.2024 16:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
117
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В коде есть две проблемы: одна с аутентификацией, другая с расшифровкой:

Проблема аутентификации:

Аутентификация не удалась, поскольку ваша реализация класса TLV и/или связанных с ним классов ошибочна. Точнее, ошибка заключается в портировании перечисления TagClass. Хотя типы перечислений могут содержать статические методы в Java, в C# это невозможно (см. здесь). При портировании статический метод TagClass.getTagClass() просто не был портирован.

Возможное решение — реализовать отсутствующий метод в классе Tag, например:

public static TagClass GetTagClass(byte octet)
{
    byte classByte = (byte)((octet >> 6) & 0x03);
    switch (classByte)
    {
        case 0: return TagClass.UNIVERSAL;
        case 1: return TagClass.APPLICATION;
        case 2: return TagClass.CONTEXT;
        case 3: return TagClass.PRIVATE;
        default: throw new GeneralSecurityException("Unknown tag class: " + classByte);
    }
}

Кроме того, в методе Tag.FromBer() замените строку:

TagClass tagClass = (TagClass)data[0];

с линией:

TagClass tagClass = GetTagClass(data[0]);  

При этом изменении аутентификация проходит успешно.

Проблема с расшифровкой:

Недостающее дешифрование можно реализовать компактно, например. с 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);
} 

Благодаря этому изменению зашифрованный текст успешно расшифровывается.


Редактировать: Если, как отмечено в комментарии, DecryptCbc() недоступен в используемой версии .NET, его можно расшифровать следующим образом:

using (Aes aes = Aes.Create())
{
    aes.Key = keyENC;
    aes.IV = getCipherIV(secureMessagingSSC);
    aes.Padding = PaddingMode.None;
    using (ICryptoTransform decryptor = aes.CreateDecryptor())
    {
        byte[] decryptedPadded = decryptor.TransformFinalBlock(dataObject, 0, dataObject.Length);
        byte[] decrypted = Unpad(decryptedPadded);
        baos.Write(decrypted, 0, decrypted.Length);
    }
}

У меня ошибка aes.DecrptCbc, я пытаюсь это исправить dotnetfiddle.net/wQMngy но проверка Mac не удалась

Bouls 08.04.2024 10:48

@Bouls - В моем первом комментарии есть код, который доказал свою эффективность. Почему бы вам не использовать его?

Topaco 08.04.2024 11:09

Я взял тот же код, вы можете проверить его по ссылке, предоставленной ранее, SDK использует другую версию .Net, у меня есть ошибка с DecryptCbc, которой нет. Ошибка, которую я пытался обойти.

Bouls 08.04.2024 11:13

@Bouls - Если вы не «используете» текущую версию .NET, это необходимо указать! Откуда нам это знать? Итак, какую версию вы используете?

Topaco 08.04.2024 11:17

@Bouls - В вашей реализации отсутствует отключение заполнения по умолчанию PKCS # 7, см. раздел «Редактирование» в моем ответе.

Topaco 08.04.2024 11:24

Извини за это ! Текущая версия — 4.8, однако у меня ошибка была только в файле aes.DecryptCbc.

Bouls 08.04.2024 11:27

Другие вопросы по теме