AESManaged File Encryption and Decryption и предшествующий вектор инициализации

Я пытаюсь зашифровать/расшифровать байты. Я много читал о ключе и IV для алгоритма AES, используя класс AESManaged в System.Security.Cryptography. Я прочитал ответ Джеймса Джонсона на следующий вопрос http://www.techques.com/question/1-7025135/My-Length-of-the-data-to-decrypt-is-invalid-error, где он предлагает вам используйте случайный IV в процедуре шифрования и добавьте IV к зашифрованному сообщению. Функция расшифровки удаляет случайный IV из начала зашифрованного сообщения, чтобы инициализировать класс расшифровки, а затем расшифровывает остальные байты. Я попытался сделать это в следующем коде. Но я продолжаю получать «Длина данных для расшифровки недействительна». сообщение об ошибке, когда я пытаюсь расшифровать после шифрования. Может ли кто-нибудь пролить свет на то, что может быть не так.

       USAGE: (streamToEncrypt/streamToDecrypt are System.IO.Stream)

       using (var cryptoHelper = new AESHelper())
        {
            var encryptedBytes = cryptoHelper.Encrypt(AESHelper.StreamToByteArray(streamToEncrypt));

        }


using (var cryptoHelper = new AESHelper())
        {
            var decryptedBytes = cryptoHelper.Decrypt(AESHelper.StreamToByteArray(streamToDecrypt));                             
        }

 public class AESHelper : IDisposable
 {       
    public AesManaged AESManaged;
    internal ICryptoTransform Encryptor { get; set; }
    internal ICryptoTransform Decryptor { get; set; }
    private const string KEY = "2428GD19569F9B2C2341839416C8E87G";
    private static readonly byte[] Salt = Encoding.ASCII.GetBytes("?pt1$8f]l4g80");
    private const Int32 ITERATIONS = 1042;


    internal AESHelper()
    {
        AESManaged = new AesManaged();
        AESManaged.BlockSize = AESManaged.LegalBlockSizes[0].MaxSize;
        AESManaged.KeySize = AESManaged.LegalKeySizes[0].MaxSize;                    
        AESManaged.Mode= CipherMode.CBC;
    }
   public void KeyGenerator()
    {
        var key = new Rfc2898DeriveBytes(KEY, Salt, ITERATIONS);
        AESManaged.Key = key.GetBytes(AESManaged.KeySize / 8);           
    }
    public byte[] Encrypt(byte[] input)
    {
        KeyGenerator();
        var ms = new MemoryStream();
        //Random IV 
        Encryptor = AESManaged.CreateEncryptor(AESManaged.Key, AESManaged.IV);
        //Add the IV to the beginning of the memory stream
        ms.Write(BitConverter.GetBytes(AESManaged.IV.Length), 0, sizeof(int));
        ms.Write(AESManaged.IV, 0, AESManaged.IV.Length);
        var cs = new CryptoStream(ms,
          Encryptor, CryptoStreamMode.Write);
        cs.Write(input, 0, input.Length);
        cs.Close();
        return ms.ToArray();
    }
    public byte[] Decrypt(byte[] input)
    {
        KeyGenerator();

        // Get the initialization vector from the encrypted stream
        var ms = new MemoryStream(input);
        AESManaged.IV = ReadByteArray(ms);
        Decryptor = AESManaged.CreateDecryptor(AESManaged.Key, AESManaged.IV);
        var cs = new CryptoStream(ms,
         Decryptor, CryptoStreamMode.Write);
        cs.Write(input, 0, input.Length);
        cs.Close();//Error occurs here
        return ms.ToArray();
    }

    internal static byte[] ReadByteArray(Stream s)
    {
        var rawLength = new byte[sizeof(int)];
        if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
        {
            throw new SystemException("Stream did not contain properly formatted byte array");
        }
        var buffer = new byte[16];
        if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
        {
            throw new SystemException("Did not read byte array properly");
        }

        return buffer;
    }
     internal static byte[] StreamToByteArray(Stream inputStream)
    {
        if (!inputStream.CanRead)
        {
            throw new ArgumentException();
        }

        // This is optional
        if (inputStream.CanSeek)
        {
            inputStream.Seek(0, SeekOrigin.Begin);
        }

        var output = new byte[inputStream.Length];
        var bytesRead = inputStream.Read(output, 0, output.Length);
        Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
        return output;
    }
  public void Dispose()
    {
        if (AESManaged != null)
            ((IDisposable) AESManaged).Dispose();

    }}

Спасибо заранее


person Paul    schedule 01.03.2013    source источник


Ответы (1)


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

Ошибка возникает из-за наличия дополнительной информации в массиве input. В методе public byte[] Encrypt(byte[] input) вы пишете длину IV и IV до того, как зашифрованные данные будут записаны. Линии:

ms.Write(BitConverter.GetBytes(AESManaged.IV.Length), 0, sizeof(int));
ms.Write(AESManaged.IV, 0, AESManaged.IV.Length);

В методе public byte[] Decrypt(byte[] input) вы читаете эту информацию и используете чтение IV в качестве вектора инициализации для алгоритма AES. Все в порядке. Затем вы создаете CryptoStream с CryptoStreamMode.Write и передаете MemoryStream объект ms, который получает расшифрованные данные. Однако переданный массив input содержит не только зашифрованное сообщение, но и IV, который вы написали в процессе шифрования. Вот почему он не может расшифровать.

Что вам нужно сделать, чтобы преодолеть это, это либо извлечь только зашифрованные данные из массива input и передать их: cs.Write(cipherData, 0, cipherData.Length);, либо изменить режим на CryptoStreamMode.Read и использовать cs.Read(outputBuff, 0, outputBuff.Length);.

Также не используйте один и тот же объект MemoryStream для чтения и записи, потому что у вас будет мусор после того, как CryptoStream напишет в него.

person Robertas    schedule 29.05.2013
comment
Спасибо за помощь, но я решил это и сделал то, что вы предлагаете - person Paul; 30.05.2013