我正在试图弄清楚如何在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
答案 0 :(得分:9)
最终我找到了答案:
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
答案 1 :(得分:2)
我发现的问题出在加密代码的这一行:
Me.TextBox1.Text = Me.enc.GetString(ms.ToArray())
问题在于,假设你的字节数组已经是一个UTF-8字符串,只是被划分为一个字节数组,实际上它应该是随机字节,可能包含不可打印的字符。它不是有效的utf-8数据。您要做的是使用Convert.ToBase64String()函数对base-64编码该字节数组。
然后,您的解密需要使用Convert.FromBase64String()方法将该base 64字符串正确地转换回字节数组。
答案 2 :(得分:2)
这是基于我的NextLevelEncryption库的Encryption类的示例。
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")
。
答案 3 :(得分:1)
您的加密看起来大致正确,但我不确定加密对象上的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
一个小的区别是我们接受来自调用者的字符串键和intializaton向量并按如下方式清理它们。
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)
结束功能