7

VB.Net で文字列を暗号化/復号化する方法を見つけようとしています。

hereの例に従って、次のコードを記述しました(以下)。テキスト ボックス、「暗号化」ボタン、および「復号化」ボタンがあります。テキスト ボックスに何かを入力し (「hello world」など)、[暗号化] をクリックすると、暗号化されたバージョンがテキスト ボックスに表示されます。「復号化」をクリックすると、元の文字列に戻ります。

しかし、暗号化しようとすると、「FlushFinalBlock」を実行しようとするとエラーが発生します。エラーは「暗号化するデータの長さが無効です」です。

上記の例は暗号化のみを扱っており、復号化は扱っていないため、「復号化」の部分は暗闇での完全なショットです。間違っていると確信していますが、「暗号化」を機能させることができないため、まだテストしていません。

なぜこれがうまくいかないのか誰か教えてもらえますか?

Imports System.Data.SqlClient
Imports System.IO
Imports System.Security.Cryptography

Public Class Form1

  Private cryptObj As RijndaelManaged
  Private KEY_128 As Byte() = {42, 1, 52, 67, 231, 13, 94, 101, 123, 6, 0, 12, 32, 91, 4, 111, 31, 70, 21, 141, 123, 142, 234, 82, 95, 129, 187, 162, 12, 55, 98, 23}
  Private IV_128 As Byte() = {234, 12, 52, 44, 214, 222, 200, 109, 2, 98, 45, 76, 88, 53, 23, 78}
  Private enc As System.Text.UTF8Encoding = New System.Text.UTF8Encoding()

  Private Sub btnEncrypt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEncrypt.Click
    Dim sPlainText As String = Me.TextBox1.Text
    If Not String.IsNullOrEmpty(sPlainText) Then
      Dim bPlainText As Byte() = Me.enc.GetBytes(Me.TextBox1.Text)
      Dim ms As MemoryStream = New MemoryStream()
      Dim cs As CryptoStream = New CryptoStream(ms, cryptObj.CreateEncryptor(), CryptoStreamMode.Write)
      cs.Write(bPlainText, 0, sPlainText.Length)
      cs.FlushFinalBlock()
      Me.TextBox1.Text = Me.enc.GetString(ms.ToArray())
    End If
  End Sub

  Private Sub btnDecrypt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDecrypt.Click
    Dim sCipherText = Me.TextBox1.Text
    Dim ms As MemoryStream = New MemoryStream()
    Dim cs As CryptoStream = New CryptoStream(ms, cryptObj.CreateDecryptor(), CryptoStreamMode.Read)
    cs.Read(Me.enc.GetBytes(sCipherText), 0, sCipherText.Length)
    Me.TextBox1.Text = Me.enc.GetString(ms.ToArray())
  End Sub

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Me.cryptObj = New RijndaelManaged()
    Me.cryptObj.BlockSize = 128
    Me.cryptObj.KeySize = 128
    Me.cryptObj.Mode = CipherMode.ECB
    Me.cryptObj.Padding = PaddingMode.None
    Me.cryptObj.Key = KEY_128
    Me.cryptObj.IV = IV_128
  End Sub

End Class
4

4 に答える 4

13

最終的に私はここで答えを見つけました:

http://www.obviex.com/samples/Encryption.aspx

彼の例は少し複雑すぎるようです。それはより一般的で柔軟なケースを表していると確信していますが、「saltPhrase」、「initVector」、および「PasswordDeriveBytes」の使用を廃止することができました。厄介な名前の置換: Rfc2898DeriveBytes。

以下では、任意の長さの文字列を入力し、暗号化し、再復号化できます。

Imports System.Data.SqlClient
Imports System.IO
Imports System.Security.Cryptography

Public Class Form1

  Private enc As System.Text.UTF8Encoding
  Private encryptor As ICryptoTransform
  Private decryptor As ICryptoTransform

  Private Sub btnEncrypt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEncrypt.Click
    Dim sPlainText As String = Me.TextBox1.Text
    If Not String.IsNullOrEmpty(sPlainText) Then
      Dim memoryStream As MemoryStream = New MemoryStream()
      Dim cryptoStream As CryptoStream = New CryptoStream(memoryStream, Me.encryptor, CryptoStreamMode.Write)
      cryptoStream.Write(Me.enc.GetBytes(sPlainText), 0, sPlainText.Length)
      cryptoStream.FlushFinalBlock()
      Me.TextBox1.Text = Convert.ToBase64String(memoryStream.ToArray())
      memoryStream.Close()
      cryptoStream.Close()
    End If
  End Sub

  Private Sub btnDecrypt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDecrypt.Click
    Dim cypherTextBytes As Byte() = Convert.FromBase64String(Me.TextBox1.Text)
    Dim memoryStream As MemoryStream = New MemoryStream(cypherTextBytes)
    Dim cryptoStream As CryptoStream = New CryptoStream(memoryStream, Me.decryptor, CryptoStreamMode.Read)
    Dim plainTextBytes(cypherTextBytes.Length) As Byte
    Dim decryptedByteCount As Integer = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
    memoryStream.Close()
    cryptoStream.Close()
    Me.TextBox1.Text = Me.enc.GetString(plainTextBytes, 0, decryptedByteCount)
  End Sub

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim KEY_128 As Byte() = {42, 1, 52, 67, 231, 13, 94, 101, 123, 6, 0, 12, 32, 91, 4, 111, 31, 70, 21, 141, 123, 142, 234, 82, 95, 129, 187, 162, 12, 55, 98, 23}
    Dim IV_128 As Byte() = {234, 12, 52, 44, 214, 222, 200, 109, 2, 98, 45, 76, 88, 53, 23, 78}
    Dim symmetricKey As RijndaelManaged = New RijndaelManaged()
    symmetricKey.Mode = CipherMode.CBC

    Me.enc = New System.Text.UTF8Encoding
    Me.encryptor = symmetricKey.CreateEncryptor(KEY_128, IV_128)
    Me.decryptor = symmetricKey.CreateDecryptor(KEY_128, IV_128)
  End Sub

End Class
于 2011-11-04T18:13:41.857 に答える
3

私が見つけた問題は、暗号化コードの次の行にあります。

Me.TextBox1.Text = Me.enc.GetString(ms.ToArray())

問題は、バイト配列が既にUTF-8 文字列であり、バイト配列として切り分けられていると想定していることです。実際には、ランダムなバイトである必要があり、印刷できない文字が含まれている可能性があります。有効な utf-8 データではありません。

代わりに、 Convert.ToBase64String()関数を使用してそのバイト配列を base-64 エンコードします。次に、復号化では、 Convert.FromBase64String()メソッドを使用して、その Base 64 文字列をバイト配列に正しく変換する必要があります。

于 2011-11-02T17:15:01.760 に答える
2

あなたの暗号化はほとんど正しいように見えますが、暗号化オブジェクトの UTF8 エンコーディングまたはその他の設定が問題を引き起こしているかどうかはわかりません。以下は、私たちが使用する暗号化方法の核心であり、コードに合わせてわずかに調整されています。

' Return the encrypted bytes from the memory stream.
Dim aoBytes As Byte() = Nothing

' Declare the RijndaelManaged object used to encrypt the data.
Using oEncryptor As New RijndaelManaged
    Try
        ' Initialize the encryptor with the specified key and initialization vector
        oEncryptor.Key = KEY_128
        oEncryptor.IV = IV_128

        ' Declare the streams used to encrypt to an in memory array of bytes.
        Using msEncrypt As New MemoryStream
            ' Create the streams used for encryption.
            Using csEncrypt As New CryptoStream(msEncrypt, oEncryptor.CreateEncryptor(), CryptoStreamMode.Write)
                Using swEncrypt As New StreamWriter(csEncrypt)
                    ' Write all data to the stream.
                    swEncrypt.Write(Me.TextBox1.Text)
                End Using

                ' Retrieve the bytes
                aoBytes = msEncrypt.ToArray()
            End Using

        End Using
    Finally
        ' Clear the RijndaelManaged object.
        If oEncryptor IsNot Nothing Then
            oEncryptor.Clear()
        End If
    End Try
End Using

If aoBytes IsNot Nothing Then
    Me.TextBox1.Text = System.Convert.ToBase64String(aoBytes)
Else
    Me.TextBox1.Text = String.Empty
End If

そして、復号化は次のとおりです。

Dim sDecryptedValue As String = ""

' Declare the RijndaelManaged object used to encrypt the data.
Using oDecryptor As New RijndaelManaged
    Try
        ' Initialize the encryptor with the specified key and a default initialization vector
        oDecryptor.Key = KEY_128
        oDecryptor.IV = IV_128

        Using msDecrypt As New MemoryStream(System.Convert.FromBase64String(Me.TextBox1.Text))
            ' Create the streams used for encryption.
            Using csDecrypt As New CryptoStream(msDecrypt, oDecryptor.CreateDecryptor(), CryptoStreamMode.Read)
                Using srDecrypt As New StreamReader(csDecrypt)
                    ' Write all data to the stream.
                    sDecryptedValue = srDecrypt.ReadToEnd()
                End Using
            End Using
        End Using
    Finally
        ' Clear the RijndaelManaged object.
        If oDecryptor IsNot Nothing Then
            oDecryptor.Clear()
        End If
    End Try
End Using

Me.TextBox1.Text = sDecryptedValue

小さな違いの 1 つは、呼び出し元から文字列キーと初期化ベクトルを受け取り、次のようにクリーンアップすることです。

InitializationVector のクリーンアップ:

If sInitializationVector.Length > 16 Then
    ' Trim the IV if it is too long
    sInitializationVector = sInitializationVector.Substring(0, 16)
ElseIf sInitializationVector.Length < 16 Then
    ' Pad the IV if it is too short
    sInitializationVector = sInitializationVector.PadRight(16)
End If

oDecryptor.IV = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(sInitializationVector)

暗号化キーのクリーンアップ:

oDecryptor.Key = GetLegalEncryptionKey(sKey, oDecryptor)

Public Function GetLegalEncryptionKey(ByVal sKey As String, ByVal oEncryptor As RijndaelManaged) As Byte()

Dim sTemp As String

If oEncryptor.LegalKeySizes.Length > 0 Then
    Dim wSize As Integer
    ' key sizes are in bits

    With oEncryptor.LegalKeySizes(0)
        wSize = .MinSize
        Do While sKey.Length * 8 > wSize AndAlso .SkipSize > 0 AndAlso wSize < .MaxSize
            wSize += oEncryptor.LegalKeySizes(0).SkipSize
        Loop
    End With
    Dim wTotalChars As Integer

    wTotalChars = CInt(wSize / 8)
    If sKey.Length > wTotalChars Then
        sTemp = sKey.Substring(0, wTotalChars)
    Else
        sTemp = sKey.PadRight(wTotalChars, " "c)
    End If
Else
    sTemp = sKey
End If

' convert the secret key to byte array
Return System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(sTemp)

終了機能

于 2011-11-02T17:02:52.387 に答える