填充无效且无法删除 - AES 又一个 [英] Padding is invalid and cannot be removed - AES yet another

查看:42
本文介绍了填充无效且无法删除 - AES 又一个的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码是尝试为内部项目构建简单加密/解密实用程序的最新迭代.我希望这是一件非常愚蠢的事情,我只是在沟里看得太远了.

The code below is the latest iteration in an attempt to build a simple encryption/decryption utility for an in-house project. I'm hoping it's something very silly that I'm simply too far into a trench to see.

它在 .Net 4.7 中,我试图对其进行组织,以防止在此过程中意外出现不同的键或选项.代码应该在 Linqpad 上.

It's in .Net 4.7 and I've tried to organise it to make it impossible to accidentally have different keys or options occurring during the process. The code should on Linqpad.

我尝试过的一些事情列在 TODO 中,尽管我没有记录我今天发现的所有愚蠢的变化.

Some things I've tried are listed in the TODOs though I've not document all the daft variations I found today.

如果其他人可以让它在 Linqpad 或 Visual Studio 2017 上运行,我会非常渴望了解我在这里缺少的东西.

If anyone else can make it run on Linqpad or Visual studio 2017, I'd be very keen to learn what I am missing here.

感谢您的建议!

'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

推荐答案

以下是您的代码的更正版本.我不是 VB.Net 程序员,所以我不是说这是漂亮或最好的风格等,但它确实有效.您的问题与两件事有关.一,您正在清除加密函数中的 AesManaged 对象,然后尝试在解密函数中再次使用它.另一个问题是你如何解密.如果您回顾我的答案,您将我带到这里 :) 您会看到您的解密和我的解密之间的区别.在你的情况下,你假设解密的字节将等于加密字节的长度(这里的这行代码 Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}),但您需要做的是在循环中解密,读取一个字节块并将其附加到您的输出中,直到没有更多字节可供读取.

Below is a corrected version of your code. I am not a VB.Net programmer and so I am not saying this is pretty or best style, etc, but it is working. Your issue was related to two things. One, you are clearing the AesManaged object in your encrypt function and then trying to use it again in your Decrypt function. The other issue was how you did the decrypt. If you look back at my answer in which you lead me here :) you will see the difference between your decrypt and mine. In yours, you were assuming the decrypted bytes would be equal to the length of the encrypted bytes (this line of code here Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}), but what you need to do is decrypt in a loop, reading a block of bytes and appending it to your output until there are no more bytes to read.

编辑正如 Hans Passant 指出的(我忘了提到),您需要使用实际数据初始化解密流.

Edit And as Hans Passant pointed out (and I forgot to mention) you need to initialize the decryption stream with the actual data.

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

这篇关于填充无效且无法删除 - AES 又一个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆