Неправильный размер зашифрованных данных (AES)

Мне нужно выполнить шифрование массива байтов []. Я использовал пример, доступный в Microsoft. К сожалению, зашифрованные данные усекаются до размера, кратного 16. Если в примере данных я добавлю 8 раз байт 0, данные будут зашифрованы должным образом. Padding был установлен, но я не вижу ничего, чтобы изменить его. Как решить эту проблему, данные не становятся отрезанными.

public byte[] EncryptAES(byte[] plainBytes)
{
    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    byte[] FKey = encoding.GetBytes("A002AD9AD73C402190C3E733D82CEA00");
    byte[] FIV = encoding.GetBytes("zyxwvutsrqponmlk");

    // Check arguments.
    if (plainBytes == null || plainBytes.Length <= 0)
        throw new ArgumentNullException("plainText");
    if (FKey == null || FKey.Length <= 0)
        throw new ArgumentNullException("Key");
    if (FIV == null || FIV.Length <= 0)
        throw new ArgumentNullException("Key");
    byte[] encrypted;
    // Create an RijndaelManaged object
    // with the specified key and IV.
    using (RijndaelManaged rijAlg = new RijndaelManaged())
    {
        rijAlg.Key = FKey;
        rijAlg.IV = FIV;
        rijAlg.Padding = PaddingMode.Zeros;
        rijAlg.Mode = CipherMode.CBC;

        // Create a decrytor to perform the stream transform.
        ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

        // Create the streams used for encryption.
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                // plainBytes.Length = 2216 
                csEncrypt.Write(plainBytes, 0, plainBytes.Length);

                // encrypted.Length = 2208
                encrypted = msEncrypt.ToArray();
            }
        }
    }

    // Return the encrypted bytes from the memory stream.
    return encrypted;
}

4 ответа

Решение

CryptoStream:

Вы всегда должны явно закрывать свой объект CryptoStream после того, как вы закончили использовать его, вызвав метод Close. Это очищает поток и вызывает обработку всех оставшихся блоков данных объектом CryptoStream. Однако если перед вызовом метода Close возникает исключение, объект CryptoStream может не закрыться. Чтобы метод Close вызывался всегда, поместите вызов метода Close в блоке finally оператора try/catch.

(Мой акцент)

Итак, позвоните Close прежде чем пытаться что-либо сделать с результатами.


По сути, заполнение используется для обработки последнего блока последовательности зашифрованных блоков. Так как CryptoStream не знает, сколько раз вы намереваетесь позвонить Write(), он не применяет заполнение или запись окончательного незавершенного блока, пока вы не вызовете Close,

(Или, как указывает Монкибой, FlushFinalBlock также может использоваться, чтобы указать, что вы закончили)

Просто вызов FlushFinalBlock() решает проблему, кратную 16.

Попробуй это

    using (MemoryStream msEncrypt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            csEncrypt.Write(plainBytes, 0, plainBytes.Length);
        }
        encrypted = msEncrypt.ToArray();
    }

Также важно соблюдать осторожность при расшифровке данных с помощью CryptoStream. Рекомендуется читать с использованием loop. Вызов Readтолько один раз может привести к усеченным результатам.

      using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
{
    plainTextBytes = new byte[cleanCipherBytes.Length];

    int read = 0, rem = plainTextBytes.Length;

    do
    {
        read = crypto.Read(plainTextBytes, read, rem);
        rem -= read;
    }
    while (read > 0);
}

Это заняло у меня довольно много времени, чтобы понять. Я надеюсь, что это сэкономит чье-то время.

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