使用 VB.net 解密 AES256 加密字符串



我想通过openssl_encrypt函数解密在 PHP 中加密 VB.net 字符串:

$encrypted_string = openssl_encrypt(
    $string,
    'AES256',
    'secret_password',
    0,
    'initialization_vector'
);

我尝试了这个类:

Public Class Aes256Encrypter
    Public Function Encrypt(ByVal plainText As String, ByVal secretKey As String) As Byte()
        Dim encryptedPassword As Byte()
        Using outputStream As MemoryStream = New MemoryStream()
            Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
            Using cryptoStream As CryptoStream = New CryptoStream(outputStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write)
                Dim inputBuffer() As Byte = Encoding.Unicode.GetBytes(plainText)
                cryptoStream.Write(inputBuffer, 0, inputBuffer.Length)
                cryptoStream.FlushFinalBlock()
                encryptedPassword = outputStream.ToArray()
            End Using
        End Using
        Return encryptedPassword
    End Function
    Public Function Decrypt(ByVal encryptedBytes As Byte(), ByVal secretKey As String) As String
        Dim plainText As String = Nothing
        Using inputStream As MemoryStream = New MemoryStream(encryptedBytes)
            Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
            Using cryptoStream As CryptoStream = New    CryptoStream(inputStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read)
                Dim outputBuffer(0 To CType(inputStream.Length - 1, Integer)) As Byte
                Dim readBytes As Integer = cryptoStream.Read(outputBuffer, 0, CType(inputStream.Length, Integer))
                plainText = Encoding.Unicode.GetString(outputBuffer, 0, readBytes)
            End Using
        End Using
        Return plainText
    End Function
    Private Function getAlgorithm(ByVal secretKey As String) As RijndaelManaged
        Const salt As String = "put your salt here"
        Const keySize As Integer = 256
        Dim keyBuilder As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(secretKey, Encoding.Unicode.GetBytes(salt))
        Dim algorithm As RijndaelManaged = New RijndaelManaged()
        algorithm.KeySize = keySize
        algorithm.IV = keyBuilder.GetBytes(CType(algorithm.BlockSize / 8, Integer))
        algorithm.Key = keyBuilder.GetBytes(CType(algorithm.KeySize / 8, Integer))
        algorithm.Padding = PaddingMode.PKCS7
        Return algorithm
    End Function
End Class

我使用 IV "initialization_vector" 作为盐字符串,但在运行时抛出一个错误:mscorlib.dll 中的"System.Security.Cryptography.CryptographicException"。发生错误:填充无效,无法删除。

我哪里做错了?

好的,所以这是一个 C# 答案,我不喜欢它; 但是我制作了一个与php的openssl_encrypt相同的答案的东西。

  • PHP 像传递字节一样传递字符串,所以Encoding.ASCII(实际上不确定它如何处理非 ASCII 数据)
  • PHP/OpenSSL 静默截断长密钥(因此您的 60 个字符的密码是 32 个字符的密码)
  • 在 ASCII 字符串和十六进制字节中处理相同的数据是一件很痛苦的事情。

法典:

private static byte[] php_encode(string php_string, int expectedLength)
{
    byte[] temp = Encoding.ASCII.GetBytes(php_string);
    if (temp.Length == expectedLength)
    {
        return temp;
    }
    byte[] ret = new byte[expectedLength];
    Buffer.BlockCopy(temp, 0, ret, 0, Math.Min(temp.Length, expectedLength));
    return ret;
}
private static string php_encrypt_aes256(string php_data, string php_password, string php_iv)
{
    byte[] key = php_encode(php_password, 32);
    byte[] iv = php_encode(php_iv, 16);
    byte[] data = Encoding.ASCII.GetBytes(php_data);
    using (Aes aes = Aes.Create())
    using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
    {
        return Convert.ToBase64String(encryptor.TransformFinalBlock(data, 0, data.Length));
    }
}

测试输入:

.PHP:

$ /usr/bin/php -r "print(openssl_encrypt('potato', 'AES256', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 0, '0123456789ABCDEF') . "n");"
wiZGvfABfairN4gKcnqD2Q==
$ /usr/bin/php -r "print(openssl_encrypt('potato', 'AES256', '0123456789abcdefghijklmnopqrstuv', 0, '0123456789ABCDEF') . "n");"
wiZGvfABfairN4gKcnqD2Q==
$ /usr/bin/php -r "print(openssl_encrypt('potato', 'AES256', '0123456789abcdefghijklmnopqrstu', 0, '0123456789ABCDEF') . "n");"
XUkYwaomkIXYstlOQlNoBQ==
$ /usr/bin/php -r "print(openssl_encrypt('potato', 'AES256', '0123456789abcdefghijklmnopqrstuv', 0, '0123456789ABCDE') . "n");"
PHP Warning:  openssl_encrypt(): IV passed is only 15 bytes long, cipher expects an IV of precisely 16 bytes, padding with  in Command line code on line 1
ah+yXvQEocgLNES2nh2kXA==

Openssl enc

$ openssl enc -aes-256-cbc -K 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576 -in enc.data -a -iv 30313233343536373839414243444546
wiZGvfABfairN4gKcnqD2Q==
$ openssl enc -aes-256-cbc -K 303132333435363738396162636465666768696a6b6c6d6e6f70717273747500 -in enc.data -a -iv 30313233343536373839414243444546
XUkYwaomkIXYstlOQlNoBQ==
$ openssl enc -aes-256-cbc -K 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576 -in enc.data -a -iv 30313233343536373839414243444500
ah+yXvQEocgLNES2nh2kXA==

我的代码

Console.WriteLine(php_encrypt_aes256("potato", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789ABCDEF"));
Console.WriteLine(php_encrypt_aes256("potato", "0123456789abcdefghijklmnopqrstuv", "0123456789ABCDEF"));
Console.WriteLine(php_encrypt_aes256("potato", "0123456789abcdefghijklmnopqrstu", "0123456789ABCDEF"));
Console.WriteLine(php_encrypt_aes256("potato", "0123456789abcdefghijklmnopqrstuv", "0123456789ABCDE"));

输出:

wiZGvfABfairN4gKcnqD2Q==
wiZGvfABfairN4gKcnqD2Q==
XUkYwaomkIXYstlOQlNoBQ==
ah+yXvQEocgLNES2nh2kXA==

我稍微修改了它,但如果有人需要它,我可以在 VB.net 中解密。

Private Shared Function php_decrypt_aes256(ByVal php_password As String, ByVal php_iv As String, ByVal php_data As String) As String
    Dim key As Byte() = php_encode(php_password, 32)
    Dim iv As Byte() = php_encode(php_iv, 16)
    Dim buff As Byte() = Encoding.ASCII.GetBytes(php_data)
    Using aes As Aes = Aes.Create()
        Using decryptor As ICryptoTransform = aes.CreateDecryptor(key, iv)
            buff = Convert.FromBase64String(php_data)
            Return ASCIIEncoding.ASCII.GetString(decryptor.TransformFinalBlock(buff, 0, buff.Length))
        End Using
    End Using
End Function

最新更新