Я пытаюсь написать клиентское программное обеспечение, которое выполняет шифрование AES и дешифрование сообщений на устройство с помощью C #.

Используя класс AES из System.Security.Cryptography, нет проблем с отправкой зашифрованных сообщений на устройство. Устройство успешно их расшифровывает.

Проблема возникает при расшифровке сообщений, полученных с устройства. Получаем сообщение: «Заполнение недействительно и не может быть удалено».

Я искал в Интернете и пробовал три разных подхода, но все имели одну и ту же ошибку - см. Ниже. Я также попробовал три подхода, не задавая свойство KeySize.

В дополнение к клиенту, написанному на C #, был также написан клиент на Python, где все работает нормально - с использованием библиотеки python aes. Итак, получив версию на Python, я смог сравнить длину полученного cipherText, который составляет 32 байта и представляет собой массив байтов. 15 байт - заполнение. Я очень ценю помощь.

Option 1
byte[] messageBuffer = null;
using (Aes aesAlg = Aes.Create())
{
    aesAlg.BlockSize = 128;
    aesAlg.KeySize = 128;
    aesAlg.Mode = CipherMode.CBC;
    aesAlg.Key = encryptionKey;  //used by device to encrypt. encryptionKey is a 16 byte array
    aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
    //aesAlg.Padding = PaddingMode.PKCS7;  // this makes no difference

    byte[] cipherText = encryptedMessagePart;   //encryptedMessagePart is byte[] encryptedMessagePart

    // Create a decrytor to perform the stream transform. 
    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

    try
    {
        messageBuffer = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);  //****fails here ********************
    }

    catch (Exception ex)
    {
        ....;
    }
}



Option 2
byte[] messageBuffer = new byte [1024];
using (Aes aesAlg = Aes.Create())
{
    aesAlg.BlockSize = 128;
    aesAlg.KeySize = 128;
    aesAlg.Mode = CipherMode.CBC;
    aesAlg.Key = encryptionKey;  //used by device to encrypt. encryptionKey is a 16 byte array
    aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
    //aesAlg.Padding = PaddingMode.PKCS7;  // this makes no difference

    byte[] cipherText = encryptedMessagePart; //encryptedMessagePart is byte[] encryptedMessagePart

    // Create a decrytor to perform the stream transform. 
    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    using (var msDecrypt = new MemoryStream(cipherText))
    {
        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
        {
            try
            {
                var zx = csDecrypt.Read(messageBuffer, 0, cipherText.Length); //****fails here ********************
            }
            catch (Exception ex)
            {
                ....;
            }
       }
    }
}


Option 3
byte[] messageBuffer = new byte [1024];
using (Aes aesAlg = Aes.Create())
{
    aesAlg.BlockSize = 128;
    aesAlg.KeySize = 128;
    aesAlg.Mode = CipherMode.CBC;
    aesAlg.Key = encryptionKey;  //used by device to encrypt. encryptionKey is a 16 byte array
    aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
    //aesAlg.Padding = PaddingMode.PKCS7;  // this makes no difference

    byte[] cipherText = encryptedMessagePart; //encryptedMessagePart is byte[] encryptedMessagePart

    // Create a decrytor to perform the stream transform. 
    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    using (var msDecrypt = new MemoryStream(cipherText))
    {
        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
        {
        using (var srDecrypt = new StreamReader(csDecrypt))
            {
                try
                {
                    // Read the decrypted bytes from the decrypting stream 
                    // and place them in a string. 
                    var pt = srDecrypt.ReadToEnd(); //****fails here ********************
                    messageBuffer = Utils.GetBytes(pt); //convert to bytes
                }
                catch (Exception ex)
                {
                    ....;
                }
            }
        }
    }
}
1
Jon Anthony 2 Янв 2018 в 20:18

2 ответа

Лучший ответ

Ошибки заполнения ожидаются для всего, где был поврежден ключ или сообщение. Для небольших сообщений размером меньше одного блока также может быть некорректная обработка IV. Поскольку устройство, похоже, использует C #, это наиболее вероятная причина.

Гораздо менее вероятно, но возможно, что используется заполнение ISO 10126. Сообщения с дополнением PKCS # 7 могут быть отменены с помощью процедуры отмены дополнения ISO 10126. Однако обратное неверно, поскольку PKCS # 7 полагается на правильность всех значений в заполнении, а не только на последнее. В заполнении ISO 10126 только последний байт указывает количество используемых байтов заполнения; остальные байты могут иметь любое значение.

Вы, конечно, всегда можете посмотреть сами. Просто укажите «без заполнения» и распечатайте сообщение в шестнадцатеричном формате. Если сообщение является полным мусором, либо сообщение, либо, что более вероятно, неверный ключ. Если все в порядке, значит, вы сможете отличить метод заполнения от последних байтов; в статье Википедии о заполнении перечислены все распространенные схемы.

1
Maarten Bodewes 3 Янв 2018 в 10:00

Я решил эту проблему очень просто, в подпрограмме дешифрования, явно установив для режима заполнения значение none:

aesAlg.Padding = PaddingMode.None;

В исходных подпрограммах Python режим заполнения не использовался. Я предположил, что неправильно, если не указать режим заполнения, режим заполнения будет отсутствовать. (Если вам интересно, подпрограммы encrytpion были написаны только на python. Подпрограммы расшифровки были написаны на Python и C #)

1
H. Pauwelyn 13 Май 2020 в 18:00