填充无效,无法删除 - AES又是另一种

时间:2017-11-24 16:54:52

标签: .net vb.net encryption

以下代码是尝试为内部项目构建简单加密/解密实用程序的最新版本。我希望这是一件非常愚蠢的事情,因为我只是太远而无法看到。

它在.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

1 个答案:

答案 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