Как заставить работать режим Rijndael CBC в vb.net - PullRequest
1 голос
/ 24 февраля 2011

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

Я попытался инициализировать криптопоток только один раз, но затем мой код дал сбой, потому что свойство криптопотока canwrite становится ложным после первой записи в криптопоток.

Вот код, который у меня сейчас есть:


Sub Main()

        Dim rij As New RijndaelManaged
        Dim iv(15) As Byte
        Dim key(15) As Byte
        Dim secret() As Byte = {59, 60, 61}

        Dim cs As ICryptoTransform
        Dim cstream As CryptoStream

        Dim out() As Byte
        Dim NewRandom As New RNGCryptoServiceProvider()

        NewRandom.GetBytes(iv)
        NewRandom.GetBytes(key)

        rij = New RijndaelManaged()

        rij.KeySize = 128
        rij.Padding = PaddingMode.PKCS7

        rij.Mode = CipherMode.CBC

        rij.IV = iv
        rij.Key = key
        cs = rij.CreateEncryptor()

        Dim ms_in As New MemoryStream
        cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)


        Using cstream
            cstream.Write(secret, 0, 3)
        End Using

        out = ms_in.ToArray
        Console.WriteLine(ArrayToString(out, out.Length))
        Erase out

        ms_in = New MemoryStream
        cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)


        Using cstream
            cstream.Write(secret, 0, 3)
        End Using

        out = ms_in.ToArray
        Console.WriteLine(ArrayToString(out, out.Length))

    End Sub

и функция преобразования для преобразования массива в строку


 Public Function ArrayToString(ByVal bytes() As Byte, ByVal length As Integer) As String

        If bytes.Length = 0 Then Return String.Empty
        Dim sb As New System.Text.StringBuilder(length)

        Dim k As Integer = length - 1
        Dim i As Integer

        For i = 0 To k
            sb.Append(Chr(bytes(i)))
        Next


        Return sb.ToString()

    End Function

Это то, что мне нужно:

    cs = rij.CreateEncryptor()
    Dim ms_in As New MemoryStream
    cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)

    Using cstream
        cstream.Write(secret, 0, 3) 'encrypt
    End Using

    out = ms_in.ToArray
    Console.WriteLine(ArrayToString(out, out.Length)) 'see the encrypted message
    Erase out

    Using cstream
        cstream.Write(secret, 0, 3) 'encrypt, this will crash here and this is the problem I'm trying to solve
    End Using

    out = ms_in.ToArray
    Console.WriteLine(ArrayToString(out, out.Length)) 'see the encrypted message this should not be the same as the first one

1 Ответ

0 голосов
/ 26 февраля 2011

Попробуйте это:

Public Sub Run()
    Dim key() As Byte = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

    Dim plaintext1 As Byte() = {59, 60, 61}

    Dim plaintext2 As Byte() = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
                             0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
                             0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
                             0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 _
                             }

    Roundtrip(plaintext1, key)
    System.Console.WriteLine()
    Roundtrip(plaintext2, key)

End Sub


Public Sub Roundtrip(ByRef plaintext As Byte(), ByRef key As Byte())

    Dim rij As New RijndaelManaged
    Dim iv(15) As Byte

    Dim encryptor As ICryptoTransform
    Dim decryptor As ICryptoTransform

    Dim out() As Byte

    'Dim NewRandom As New RNGCryptoServiceProvider()
    'NewRandom.GetBytes(iv)
    'NewRandom.GetBytes(key)

    Console.WriteLine("Original:")
    Console.WriteLine(ArrayToString(plaintext))
    System.Console.WriteLine()

    rij = New RijndaelManaged()
    rij.KeySize = key.Length * 8  ' 16 byte key == 128 bits
    rij.Padding = PaddingMode.PKCS7
    rij.Mode = CipherMode.CBC
    rij.IV = iv
    rij.Key = key
    encryptor = rij.CreateEncryptor()

    Using msIn = New MemoryStream

        Using cstream = New CryptoStream(msIn, encryptor, CryptoStreamMode.Write)
            cstream.Write(plaintext, 0, plaintext.Length)
        End Using

        out = msIn.ToArray
        Console.WriteLine("Encrypted:")
        Console.WriteLine("{0}", ArrayToString(out))
        System.Console.WriteLine()

    End Using

    decryptor = rij.CreateDecryptor()
    Using msIn = New MemoryStream

        Using cstream = New CryptoStream(msIn, decryptor, CryptoStreamMode.Write)
            cstream.Write(out, 0, out.Length)
        End Using

        out = msIn.ToArray
        Console.WriteLine("Decrypted:  ")
        Console.WriteLine("{0}", ArrayToString(out))
        System.Console.WriteLine()

    End Using

End Sub


Public Shared Function ArrayToString(ByVal bytes As Byte()) As String

    Dim sb As New System.Text.StringBuilder()

    Dim i As Integer
    For i = 0 To bytes.Length-1
        if (i <> 0 AND i mod 16 = 0) Then
            sb.Append(Environment.NewLine)
        End If
        sb.Append(System.String.Format("{0:X2} ", bytes(i)))
    Next

    Return sb.ToString().Trim()

End Function

Я сделал следующие основные изменения, чтобы заставить его работать:

  • создать декриптор
  • правильно управляет буферами и потоками (см. Добавленные мной пункты Using)

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


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

        For i As Integer = 1 To 2
            Using ms = New MemoryStream
                Using cstream = New CryptoStream(ms, encryptor, CryptoStreamMode.Write)
                    For j As Integer = 1 To i
                        cstream.Write(plaintext, 0, plaintext.Length)
                    Next j
                End Using
                out = ms.ToArray
                Console.WriteLine("Encrypted (cycle {0}):", i)
                Console.WriteLine("{0}", ArrayToString(out))
                System.Console.WriteLine()

            End Using
        Next i
...