问题
I'm trying to figure out how to encrypt / decrypt a string in VB.Net.
I followed the example given here and wrote the following code (below). There's a text box, an "encrypt" button, and a "decrypt" button. The idea is to type something into the text box ("like 'hello world'"), click "encrypt", and see the encrypted version appear in the text box. Clicking "decrypt" should then take you back to the original string.
But when I try to encrypt I get an error when I try to "FlushFinalBlock". The error is: "Length of the data to encrypt is invalid".
The "decrypt" part is a total shot in the dark, as the example quoted above only deals with encryption, not decryption. I'm sure it's wrong, but since I can't get "encrypt" to work I haven't tested it yet.
Can anyone tell me why this doesn't work?
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
回答1:
Ultimately I found the answer here:
http://www.obviex.com/samples/Encryption.aspx
His example seems a little over-complicated. I'm sure it represents a more general and flexible case, but I was able to do away with the "saltPhrase", the "initVector", and the use of "PasswordDeriveBytes", which apparently is deprecated anyway, but I also avoided its nastily named replacement: Rfc2898DeriveBytes.
The following lets you enter a string of any length, encrypt it, and re-decrypt it.
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:
The issue I spotted is on this line in your encryption code:
Me.TextBox1.Text = Me.enc.GetString(ms.ToArray())
The problem is that this assumes your byte array already is a UTF-8 string, just carved up as a byte array, when in fact it should be random bytes and likely includes unprintable characters. It's not valid utf-8 data. What you want to do instead is base-64 encode that byte array using the Convert.ToBase64String() function.
Then, your decryption needs to correctly convert that base 64 string back to a byte array, using the Convert.FromBase64String() method.
回答3:
Here is an example of an Encryption class based on my NextLevelEncryption library.
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
To use it all you have to do is call the function Encrypt("Your text to encrypt here","Your password")
and Decrypt(""Your text to encrypt here","Your password")
.
For more information head over to https://nextlevelencryption.codeplex.com/
回答4:
Your encryption looks mostly correct, but I am not sure if the UTF8 encoding or other settings on the encryption object is throwing you off. Here is the heart of the encryption method that we use, tailored slightly to your code:
' 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
And the decryption is:
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
One minor difference is that we accept a string key and intializaton vector from the caller and clean them up as follows.
InitializationVector cleanup:
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)
Encryption key cleanup:
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)
End Function
来源:https://stackoverflow.com/questions/7982933/simple-encrypting-decrypting-in-vb-net