В VB.NET запись ключа AES и зашифрованных данных в один и тот же MemoryStream не работает - PullRequest
1 голос
/ 24 июня 2011

Я пытаюсь использовать симметричное шифрование для шифрования некоторых данных и хранить ключ, необходимый для дешифрования с данными, в MemoryStream.(Хотя я знаю, что одно это действительно глупо с точки зрения безопасности, я собираюсь использовать RSA для шифрования симметричного ключа. Однако сейчас я пытаюсь просто заставить эту часть работать.)

Я использую библиотеку FileHelpers для анализа данных для моего разделителя (точка с запятой, так как я не верю, что у меня когда-либо будет точка с запятой).К сожалению, в моей функции расшифровки, когда она анализируется, она возвращает только одну запись.И, если я покажу всю строку зашифрованных данных, созданных в конце этой функции, она не будет использовать несколько записей.

Мне интересно, если при создании нового криптопотока он по умолчаниюв начало потока памяти, поэтому, когда я записываю свои зашифрованные данные, он перезаписывает данные, которые я только что записал, в поток памяти.Как вы думаете, это правильно?

Спасибо за вашу помощь!

Private Function Encrypt(ByVal data As String) As String
    Dim utf8 As New UTF8Encoding
    ' Convert string data to byte array
    Dim inBytes() As Byte = utf8.GetBytes(data)
    ' Create memory stream for storing the data we've manipulated
    Dim ms As New MemoryStream()

    Dim aes As New RijndaelManaged()
    aes.KeySize = 256

    Dim cs As New CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)

    ' Write key to beginning of memory stream
    ms.Write(aes.Key, 0, aes.Key.Length)
    ' Add semicolon delimiter to memory stream
    ms.Write(utf8.GetBytes(";"), 0, utf8.GetBytes(";").Length)
    ' Write IV to memory stream
    ms.Write(aes.IV, 0, aes.IV.Length)
    ' Write semicolon delimiter to memory stream
    ms.Write(utf8.GetBytes(";"), 0, utf8.GetBytes(";").Length)
    ' Ensure that the data we've just written is in the memory stream, before
    ' we add the encrypted data
    ms.Flush()

    ' Write the encrypted data
    cs.Write(inBytes, 0, inBytes.Length) ' encrypt
    cs.FlushFinalBlock()

    ' Return encrypted data as string
    Return Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length)
End Function

Ответы [ 2 ]

1 голос
/ 24 июня 2011

Вот краткий пример того, как вы можете достичь этого. Я включил и Encrypt и Decrypt, потому что, очевидно, важно, чтобы вы следовали одному и тому же шаблону с обеих сторон. Я оставлю вам соответствующую проверку ошибок и т. Д.)

Imports System.Security.Cryptography
Imports System.IO
Imports System.Text

Module Module1

  Sub Main()
    Dim encrypted As String = Encrypt("Here is the data")
    Dim decrypted As String = Decrypt(encrypted)
    Console.WriteLine(decrypted)
    Console.ReadKey()
  End Sub

  Private Function Encrypt(clearText As String) As String
    Dim aes As New RijndaelManaged
    aes.KeySize = 256

    Using ms As New MemoryStream
      ms.WriteByte(aes.Key.Length)
      ms.Write(aes.Key, 0, aes.Key.Length)
      ms.WriteByte(aes.IV.Length)
      ms.Write(aes.IV, 0, aes.IV.Length)

      Using cs As New CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)
        Dim bytes() As Byte = Encoding.UTF8.GetBytes(clearText)
        cs.Write(bytes, 0, bytes.Length)
      End Using

      Return Convert.ToBase64String(ms.ToArray())
    End Using
  End Function

  Private Function Decrypt(cipherText As String) As String
    Dim ms As New MemoryStream(Convert.FromBase64String(cipherText))

    Dim keyLength As Byte = ms.ReadByte()
    Dim key(keyLength - 1) As Byte
    ms.Read(key, 0, keyLength)

    Dim ivLength As Byte = ms.ReadByte()
    Dim iv(ivLength - 1) As Byte
    ms.Read(iv, 0, ivLength)

    Dim dataOffset As Integer = ms.Position

    Dim aes As New RijndaelManaged()
    aes.Key = key
    aes.IV = iv

    Using cs As New CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read)
      Using sr As New StreamReader(cs, Encoding.UTF8)
        Return sr.ReadToEnd()
      End Using
    End Using
  End Function
End Module
1 голос
/ 24 июня 2011

Почему вы пишете поток памяти?Напишите непосредственно в поток Crypto, затем прочитайте зашифрованные данные обратно из потока памяти.Вот версия шифрования AES на C #.

aesEncryptor - это ваша aes.CreateEncryptor()

        private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data)
        {
            MemoryStream memStream = null; //stream to write encrypted data to
            CryptoStream cryptoStream = null; //crypto stream to encrypt data

            try
            {
                memStream = new MemoryStream(); 

                //initiate crypto stream telling it to write the encrypted data to the memory stream
                cryptoStream = new CryptoStream(memStream, aesEncryptor, CryptoStreamMode.Write);

                //write the data to the memory stream
                cryptoStream.Write(data, 0, data.Length);
            }
            catch (Exception ee)
            {
                //rethrow
                throw new Exception("Error while encrypting with AES: ", ee);
            }
            finally
            {
                //close 'em
                if (cryptoStream != null)
                    cryptoStream.Close();
                if (memStream != null)
                    memStream.Close();
            }

            //return the encrypted data
            return memStream.ToArray();
        }

, которую можно назвать так:

public byte[] doEncrypt(byte[] dataToEncrypt)
{
            RijndaelManaged aesAlg = new RijndaelManaged();
            aesAlg.KeySize = AES_KEY_SIZE;
            aesAlg.GenerateKey();
            aesAlg.GenerateIV();
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;

            byte[] aesKey = aesAlg.Key;
            byte[] aesIV = aesAlg.IV;

            byte[] encryptedData = encryptWithAes(aesAlg.CreateEncryptor(), dataToEncrypt);

            //store your aesKey, aesIV, and encryptedData together however you want
}

Вы не должныудаляйте двоичные данные любыми символами, потому что, когда вы снова начнете читать эти данные, вам придется кодировать весь буфер, включая ключ и IV, которые после кодирования могут иметь произвольный разделитель в любом месте.Вместо этого сохраните длину ключа в байтах, затем сохраните ключ после.Когда вы начнете читать данные обратно, вы можете прочитать первый байт (длину ключа) как целое число, а затем узнать, сколько нужно прочитать, чтобы получить ключ.Это имеет для вас смысл?

...