【问题标题】:simple encrypting / decrypting in VB.NetVB.Net中的简单加密/解密
【发布时间】:2011-11-02 15:28:01
【问题描述】:

我正在尝试弄清楚如何在 VB.Net 中加密/解密字符串。

我按照here 给出的示例编写了以下代码(如下)。有一个文本框、一个“加密”按钮和一个“解密”按钮。想法是在文本框中输入一些内容(“like '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

【问题讨论】:

    标签: vb.net encryption rijndaelmanaged cryptostream


    【解决方案1】:

    最终我在这里找到了答案:

    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
    

    【讨论】:

      【解决方案2】:

      这是一个基于我的NextLevelEncryption 库的加密类示例。

      Public Class Encryption
      ''' <summary>
      ''' Encrypt text using AES Algorithm
      ''' </summary>
      ''' <param name="text">Text to encrypt</param>
      ''' <param name="password">Password with which to encrypt</param>
      ''' <returns>Returns encrypted text</returns>
      ''' <remarks></remarks>
      Public Shared Function Encrypt(text As String, password As String) As String
          Dim AES As New System.Security.Cryptography.RijndaelManaged
          Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
          Dim encrypted As String = ""
          Dim hash(31) As Byte
              Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(password))
              Array.Copy(temp, 0, hash, 0, 16)
              Array.Copy(temp, 0, hash, 15, 16)
              AES.Key = hash
              AES.Mode = Security.Cryptography.CipherMode.ECB
              Dim DESEncrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateEncryptor
              Dim Buffer As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(text)
              encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
              Return encrypted
      End Function
      
      ''' <summary>
      ''' Decrypt text using AES Algorithm
      ''' </summary>
      ''' <param name="text">Text to decrypt</param>
      ''' <param name="password">Password with which to decrypt</param>
      ''' <returns>Returns decrypted text</returns>
      ''' <remarks></remarks>
      Public Shared Function Decrypt(text As String, password As String) As String
          Dim AES As New System.Security.Cryptography.RijndaelManaged
          Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
          Dim decrypted As String = ""
          Dim hash(31) As Byte
              Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(password))
              Array.Copy(temp, 0, hash, 0, 16)
              Array.Copy(temp, 0, hash, 15, 16)
              AES.Key = hash
              AES.Mode = Security.Cryptography.CipherMode.ECB
              Dim DESDecrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateDecryptor
              Dim Buffer As Byte() = Convert.FromBase64String(text)
              decrypted = System.Text.ASCIIEncoding.ASCII.GetString(DESDecrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
          Return decrypted
      End Function
      End Class
      

      要使用它,您只需调用函数Encrypt("Your text to encrypt here","Your password")Decrypt(""Your text to encrypt here","Your password")

      欲了解更多信息,请前往https://nextlevelencryption.codeplex.com/

      【讨论】:

        【解决方案3】:

        我发现的问题是在您的加密代码中的这一行:

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

        问题在于,这假设您的字节数组已经是一个 UTF-8 字符串,只是被分割为一个字节数组,而实际上它应该是随机字节并且可能包含不可打印的字符。这不是有效的 utf-8 数据。

        您想要做的是使用Convert.ToBase64String() 函数对该字节数组进行base-64 编码。然后,您的解密需要使用 Convert.FromBase64String() 方法将该 base 64 字符串正确转换回字节数组。

        【讨论】:

        • 这很可能是个问题,但我认为它不能解决问题中的问题。现在我只是想对从键盘输入到 TextBox 的文本进行编码,这将是一个有效的 UTF-8 字符串。在“cs.FlushFinalBlock”处仍然出现“要加密的数据长度无效”的错误
        【解决方案4】:

        您的加密看起来基本正确,但我不确定加密对象上的 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
        

        一个小的区别是我们从调用者那里接受一个字符串键和初始化向量,并按如下方式清理它们。

        初始化向量清理:

        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)
        

        结束函数

        【讨论】:

        • 我尝试使用类似于您上面的内容进行加密。 Dim sw As StreamWriter = New StreamWriter(cs); sw.Write(Me.TextBox1.Text);将 aoBytes 调暗为 Byte() = ms.ToArray(); Me.TextBox1.Text = Convert.ToBase64String(aoBytes) 但结果是它使文本字段空白。 “aoBytes”的长度为 0。我确定我做错了什么,但部分问题在于所有这些流和作家四处飞来飞去,我几乎只是在黑暗中拍摄,没有太多知识这些东西实际上在做什么。
        • 问题可能出在您的密钥和初始化向量上。尝试将它们更改为字符串并使用我提供的可选代码来查看是否有效。如果需要,我可以修改答案以准确显示它们适合的位置。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 2010-11-19
        • 2014-06-28
        • 2017-12-20
        • 1970-01-01
        相关资源
        最近更新 更多