以下代码是尝试为内部项目构建简单加密/解密实用程序的最新版本。我希望这是一件非常愚蠢的事情,因为我只是太远而无法看到。
它在.Net 4.7中,我试图组织它以使得在此过程中不可能意外地出现不同的键或选项。代码应该在Linqpad上。
我试过的一些东西列在了TODO中,虽然我没有记录我今天发现的所有愚蠢变化。
如果有其他人可以在Linqpad或Visual Studio 2017上运行它,我会非常渴望了解我在这里缺少的东西。
感谢您的任何建议!
'Linqpad version - should offer to import System.Security.Cryptography
'I'm on .net 4.7 in my main project hence the Tuple setup below.
Dim Testphrase = "Whatever is happening, nothing I google works!"
Sub Main
Dim encrypted = EncryptString(Testphrase, "Password")
Dim Decrypted = DecryptString(encrypted, "Password")
Decrypted.Dump
End Sub
Private Shared AesManaged As AesManaged
Private Shared password As Rfc2898DeriveBytes
'''Makes sure that I use the same parameters both sides of the equation
Private Shared Function GetCryptBits(passphrase As String) As (passwords As Rfc2898DeriveBytes, AesManaged As AesManaged)
If AesManaged Isnot Nothing Then Return (password, AesManaged) 'TODO: Don't rebuild this if you've already got it.
password = New Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes("SaltBytes"))
AesManaged = New AesManaged() With {.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.BlockSize = 128, .KeySize = 256} 'TODO: I've tried all the padding choices here.TODO: Have tried RijndaelManaged
AesManaged.IV = password.GetBytes(AesManaged.BlockSize / 8)
AesManaged.Key = password.GetBytes(AesManaged.KeySize / 8)
Return (password, AesManaged)
End Function
'Encrypt
Public Shared Function EncryptString(plainText As String, passPhrase As String) As String
Dim B = GetCryptBits(passPhrase)
With B
Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText) 'TODO: Where you see UTF8 I've also tried with Unicode
Dim encryptor As ICryptoTransform = B.AesManaged.CreateEncryptor(B.AesManaged.Key, B.AesManaged.IV)
Using MemoryStream As New MemoryStream()
Using CryptoStream As New CryptoStream(MemoryStream, encryptor, CryptoStreamMode.Write)
CryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
CryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = MemoryStream.ToArray()
AesManaged.clear
Return Convert.ToBase64String(cipherTextBytes)
MemoryStream.Close()
CryptoStream.Close()
End Using
End Using
End With
End Function
'Decrypt
Public Shared Function DecryptString(cipherText As String, passPhrase As String) As String
Dim B = GetCryptBits(passPhrase)
With B
Dim cipherTextBytes As Byte() = Convert.FromBase64String(cipherText)
Dim decryptor As ICryptoTransform = B.AesManaged.CreateDecryptor(B.AesManaged.Key, B.AesManaged.IV)
Using MemoryStream As New MemoryStream
Using CryptoStream As New CryptoStream(MemoryStream, decryptor, CryptoStreamMode.Read)
Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}
Dim decryptedByteCount As Integer = CryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length) 'TODO: Here I'm getting "Padding is invalid and cannot be removed."
Return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount)
End Using
End Using
End With
End Function
答案 0 :(得分:3)
以下是您的代码的更正版本。我不是VB.Net程序员,所以我不是说这是漂亮或最好的风格等,但它是有效的。你的问题与两件事有关。一,您正在清除加密函数中的AesManaged
对象,然后尝试在Decrypt函数中再次使用它。另一个问题是你如何解密。如果你回头看看我带领我的answer :),你会发现你的解密与我的区别。在你的,你假设解密的字节将等于加密字节的长度(这里的代码行Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}
),但你需要做的是在循环中解密,读取一个字节块和将它附加到输出,直到没有更多的字节要读取。
修改强> 正如Hans Passant指出的那样(我忘了提及)你需要用实际数据初始化解密流。
Dim Testphrase = "Whatever is happening, nothing I google works!"
Sub Main
Dim encrypted = EncryptString(Testphrase, "Password")
encrypted.Dump
Dim Decrypted = DecryptString(encrypted, "Password")
Decrypted.Dump
End Sub
Private Shared AesManaged As AesManaged
Private Shared password As Rfc2898DeriveBytes
'''Makes sure that I use the same parameters both sides of the equation
Private Shared Function GetCryptBits(passphrase As String) As (passwords As Rfc2898DeriveBytes, AesManaged As AesManaged)
If AesManaged Isnot Nothing Then Return (password, AesManaged) 'TODO: Don't rebuild this if you've already got it.
password = New Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes("SaltBytes"))
AesManaged = New AesManaged() With {.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.KeySize = 256} 'TODO: I've tried all the padding choices here.TODO: Have tried RijndaelManaged
Dim iv As Byte() = password.GetBytes(AesManaged.BlockSize / 8)
Dim key As Byte() = password.GetBytes(AesManaged.KeySize / 8)
AesManaged.IV = iv
AesManaged.Key = key
Return (password, AesManaged)
End Function
'Encrypt
Public Shared Function EncryptString(plainText As String, passPhrase As String) As String
Dim B = GetCryptBits(passPhrase)
With B
Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText) 'TODO: Where you see UTF8 I've also tried with Unicode
Dim encryptor As ICryptoTransform = B.AesManaged.CreateEncryptor(B.AesManaged.Key, B.AesManaged.IV)
Using MemoryStream As New MemoryStream()
Using CryptoStream As New CryptoStream(MemoryStream, encryptor, CryptoStreamMode.Write)
CryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
CryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = MemoryStream.ToArray()
Return Convert.ToBase64String(cipherTextBytes)
MemoryStream.Close()
CryptoStream.Close()
End Using
End Using
End With
End Function
'Decrypt
Public Shared Function DecryptString(cipherText As String, passPhrase As String) As String
Dim B = GetCryptBits(passPhrase)
With B
Dim cipherTextBytes As Byte() = Convert.FromBase64String(cipherText)
Dim decryptor As ICryptoTransform = B.AesManaged.CreateDecryptor(B.AesManaged.Key, B.AesManaged.IV)
Using MemoryStream As New MemoryStream(cipherTextBytes)
Using OutputStream As New MemoryStream()
Using CryptoStream As New CryptoStream(MemoryStream, decryptor, CryptoStreamMode.Read)
Dim plainTextBytes As Byte() = New Byte(1024) {}
Dim read As Integer = CryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
While read > 0
OutputStream.Write(plainTextBytes,0, read)
read = CryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
End While
Return Encoding.UTF8.GetString(OutputStream.ToArray())
End Using
End Using
End Using
End With
End Function