Входные данные не являются полным блоком при расшифровке AES с указанным c смещением? - PullRequest
0 голосов
/ 01 мая 2020

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

Входные данные не являются полным блоком.

Что с моим ограниченным знанием шифрования и дешифрования совершенно бесполезно для меня при отладке проблемы. Я искал высоко и низко, и ни один из ответов на эту проблему, которые я нашел, кажется, не решил мою проблему. Ответы, как правило, совпадают с тем, что разработчик не расшифровывает byte[], а вместо этого что-то вроде строки base 64.

private static Guid TestGuid = Guid.NewGuid();
private static DateTime Timestamp = DateTime.Now;
private static string key = "PPPQmyuzqKtjzYlWM3mP0aDxaxCzlsACajIkTVN4IjI=";
public static void Main()
{
    string data = TestGuid + "|" + Timestamp;
    Console.WriteLine("Request Parameter: " + data);
    string encryptedData = AESEncrypt(key, data, 1);
    Console.WriteLine("Encrypted: " + encryptedData);
    string decryptedData = AESDecrypt(key, encryptedData, 1);
    Console.WriteLine("Decrypted: " + decryptedData);
}

public static string AESEncrypt(string key, string data, int offset)
{
    if (string.IsNullOrWhiteSpace(data))
        throw new ArgumentException("Data");
    byte[] encryptedData;
    byte[] keyData = Convert.FromBase64String(key);
    using (Aes algo = Aes.Create())
    {
        algo.Key = keyData;
        algo.GenerateIV();
        algo.Padding = PaddingMode.PKCS7;
        byte[] iv = new byte[offset + 16];
        Random r = new Random();
        using (MemoryStream ms = new MemoryStream())
        {
            for (int i = 0; i < offset; i++)
                iv[i] = (byte)r.Next(1, 200);
            for (int i = 0; i < algo.IV.Length; i++)
                iv[offset + i - 1] = algo.IV[i];
            ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
            using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
                using (BinaryWriter bw = new BinaryWriter(cs))
                {
                    bw.Write(iv, 0, offset);
                    ms.Write(iv, offset, algo.IV.Length);
                    bw.Write(data);
                    cs.FlushFinalBlock();
                }

                encryptedData = ms.ToArray();
            }
        }
    }

    if (encryptedData != null)
        return Convert.ToBase64String(encryptedData);
    throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}

public static string AESDecrypt(string key, string data, int offset)
{
    if (string.IsNullOrWhiteSpace(data))
        throw new ArgumentException("Data");
    string decryptedData;
    byte[] keyData = Convert.FromBase64String(key);
    using (Aes algo = Aes.Create())
    {
        algo.Key = keyData;
        algo.Padding = PaddingMode.PKCS7;
        byte[] decodedData = Convert.FromBase64String(data);
        using (MemoryStream ms = new MemoryStream(decodedData))
        {
            byte[] ivData = new byte[offset + 16];
            ms.Read(ivData, 0, offset + 16);
            List<byte> iv = new List<byte>();
            for (int i = offset - 1; i < ivData.Length - 1; i++)
                iv.Add(ivData[i]);
            algo.IV = iv.ToArray();
            ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
            List<byte> dataToDecrypt = new List<byte>();
            for (int i = 0; i + offset < decodedData.Length; i++)
                dataToDecrypt.Add(decodedData[i + offset]);
            using (MemoryStream ds = new MemoryStream(dataToDecrypt.ToArray()))
            {
                using (CryptoStream cs = new CryptoStream(ds, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader sr = new StreamReader(cs))
                    {
                        decryptedData = sr.ReadToEnd();
                    }
                }
            }
        }
    }

    if (!string.IsNullOrWhiteSpace(decryptedData))
        return decryptedData;
    throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}

В чем причина этой ошибки, почему она вызывает ошибка, как я могу устранить ошибку и почему это разрешение работает?

1 Ответ

3 голосов
/ 01 мая 2020

Использование последнего потока шифрования в процессе шифрования (подача в него необработанных байтов) является фатальной ошибкой, и ее следует избегать

Данная проблема возникает из-за того, что

bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);

Feeding первые случайные байты модифицированного IV в потоке шифрования и оставшиеся его в необработанный выходной поток, первые байты модифицированного IV не будут немедленно записаны в поток памяти и вместо этого будут частью первого блока шифрования, таким образом, размер шифра во время дешифрования будет иметь некоторые байты, например, ему не хватает 1 байта, где смещение = 1

Но вы ожидаете, что они будут записаны немедленно как независимые байты, потому что в части дешифрования вы читаете смещение + 16 байт из потока, и, таким образом, вы считываете в зашифрованный блок и делаете его меньше размера блока для AES. Вы можете увидеть это, если отладите код. Окончательный размер зашифрованных байтов составляет 0x50, а размер байтов для расшифровки равен 0x50 - смещение = 0x4f (смещение = 1)

Для решения

  1. Вы можете получить IV из ключа (который небезопасен, если вы повторно используете ключ) и вам не нужно будет включать его в ваш шифр.
  2. Вы можете добавить IV (и ваши случайные байты) к вашему зашифрованному буферу и прочитать его сначала используйте его для расшифровки,

как:

public static string AESEncrypt(string key, string data, int offset)
{
    if (string.IsNullOrWhiteSpace(data))
        throw new ArgumentException("Data");
    byte[] encryptedData;
    byte[] keyData = Convert.FromBase64String(key);
    using (Aes algo = Aes.Create())
    {
        algo.Key = keyData;
        algo.GenerateIV();
        algo.Padding = PaddingMode.PKCS7;
        Random r = new Random();
        using (MemoryStream ms = new MemoryStream())
        {
            for (int i = 0; i < offset; i++)
            {
                ms.WriteByte((byte)r.Next(0, 200));
            }
            ms.Write(algo.IV, 0, 16);

            ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
            using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
                using (BinaryWriter bw = new BinaryWriter(cs))
                {
                    bw.Write(data);
                    cs.FlushFinalBlock();
                }

                encryptedData = ms.ToArray();
            }
        }
    }

    if (encryptedData != null)
        return Convert.ToBase64String(encryptedData);
    throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}

public static string AESDecrypt(string key, string data, int offset)
{
    if (string.IsNullOrWhiteSpace(data))
        throw new ArgumentException("Data");
    string decryptedData;
    byte[] keyData = Convert.FromBase64String(key);
    using (Aes algo = Aes.Create())
    {
        algo.Key = keyData;
        algo.Padding = PaddingMode.PKCS7;
        byte[] decodedData = Convert.FromBase64String(data);
        using (MemoryStream ms = new MemoryStream(decodedData))
        {
            for (int i = 0; i < offset; i++) ms.ReadByte();
            byte[] iv = new byte[16];
            ms.Read(iv, 0, 16);

            algo.IV = iv.ToArray();

            ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);

            using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader sr = new StreamReader(cs))
                {
                    decryptedData = sr.ReadToEnd();
                }
            }
        }
    }

    if (!string.IsNullOrWhiteSpace(decryptedData))
        return decryptedData;
    throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
...