将C#AES 256解密移植到PHP [英] Porting C# AES 256 decryption to PHP

查看:120
本文介绍了将C#AES 256解密移植到PHP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将此C#代码移植到PHP:

I'm trying to port this C# code to PHP:

private static string DecryptString(string content, string password)
{
    Rijndael aes;
    byte[] retVal = null;
    byte[] contentBytes;
    byte[] passwordBytes;
    byte[] ivBytes;

    try {
        //Get the content as byte[]
        contentBytes = Convert.FromBase64String(content);

        //Create the password and initial vector bytes
        passwordBytes = new byte[32];
        ivBytes = new byte[16];

        Array.Copy(Encoding.Unicode.GetBytes(password), passwordBytes, Encoding.Unicode.GetBytes(password).Length);
        Array.Copy(passwordBytes, ivBytes, 16);

        //Create the cryptograpy object
        aes = Rijndael.Create();
        aes.Key = passwordBytes;
        aes.IV = ivBytes;
        aes.Padding = PaddingMode.PKCS7;

        string mode = aes.Mode.ToString();

        //Decrypt
        retVal = aes.CreateDecryptor().TransformFinalBlock(contentBytes, 0, contentBytes.Length);
    }
    catch {}

    return Encoding.Unicode.GetString(retVal);
}

content 参数是一个44个字符的长字符串,以64为基数编码,密码参数是一个6个字符的长字符串。

The content parameter is a 44 character long string, base 64 encoded, the password parameter is a 6 character long string.

此是我放在一起的PHP代码:

This is the PHP code I put together:

$content = "[44 char base 64 encoded string]";
$password = "[6 char password]";

$padding = 32 - (strlen($password) % 32);
$password .= str_repeat(chr($padding), $padding);

$iv = substr($password, 0, 16);

$data = base64_decode($content);

$decrypted  = openssl_decrypt($data, 'AES-256-CBC', $password, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);

C#代码的结果为10个字符长的数字。 PHP的结果是32个字符长的乱码-我猜是二进制数据。

The result of the C# code is a 10 character long number. The result from PHP is some 32 character long gibberish - I guess binary data.

有人可以帮助我修复该代码,或者有什么想法可以尝试吗? / p>

Can anybody help me to fix that code, or has an idea what I can try?

推荐答案

如zaph在评论中所述,此代码不被认为是安全的,我建议不要在生产环境中使用它。引用zaph的评论

As mentioned by zaph in the comments this code is not considered safe and i advise against using it in a production environment. Quoting zaph's comment:


基本上,代码是不安全的。应该使用具有密钥派生功能的密码(例如PBKDF2)来创建密钥。每次加密的IV应该是随机的,而不是密码/密钥。 IV可以并且通常是加密数据的前缀,它们不需要是秘密的。

Essentially the code is not secure. Keys should be created from a password with a key derivation function such as PBKDF2. IVs should be random for each encryption, never the password/key. The IV can be and generally are prepended to the encrypted data, they do not need to be secret.

话虽如此,这里是PHP等效的C#代码:

That being said, here is a PHP equivalent of your C# code:

function DecryptString($content, $password){
    $password = mb_convert_encoding($password, "utf-16le");
    $padding = 32 - (strlen($password) % 32);
    $password .= str_repeat("\0", $padding);
    $iv = substr($password, 0, 16);
    $decrypted = openssl_decrypt($content, "AES-256-CBC", $password, false, $iv);
    $decoded = mb_convert_encoding($decrypted, "utf-8", "utf-16le");
    return $decoded;
}

C#Unicode字符串是Little Endian UTF-16编码的。为了在PHP中正确解码它们,我们必须使用 mb_convert_encoding

C# Unicode strings are Little Endian UTF-16 encoded. In order to decode them properly in PHP we'll have to use mb_convert_encoding.

PHP测试:

$password = "012345";
$content = "EJWgZ/26wp+Cb5utbM1aMk8XfqPQide4dzjQzzzYfj8=";
echo DecryptString($content, $password);

//0123456789

C#测试:

string password = "012345";
string content = "EJWgZ/26wp+Cb5utbM1aMk8XfqPQide4dzjQzzzYfj8=";
Console.WriteLine(so.DecryptString(content, password));

//0123456789

一些提示:

PHP的 openssl_decrypt 默认情况下使用PKCS填充,并且可以处理base64编码的数据。我们可以通过将 options 参数设置为 false 来利用这些功能。

PHP's openssl_decrypt uses PKCS padding by default, and can handle base64 encoded data. We can take advantage of those features by setting the options parameter to false.

IV应该是随机字节。这很重要,因为使用静态IV会使您的加密容易受到攻击。您可以使用C $的 RNGCryptoServiceProvider 和PHP的 openssl_random_pseudo_bytes 创建安全的随机IV。

IVs should be random bytes. This is important because using a static IV makes your encryption vulnerable to attacks. You can create secure random IVs with RNGCryptoServiceProvider for C#, and openssl_random_pseudo_bytes for PHP.

密码应尽可能长且不可预测-123456不是一个好的密码!尽管您可以将密码用作密钥(如果密码大小合适),但最好使用由KDF创建的密钥。您可以对C#使用 Rfc2898DeriveBytes ,对于PHP使用 hash_pbkdf2

Passwords should be as long and unpredictable as possible - 123456 is not a good password! Although you could use your password as a key (if it has the right size), it's best to use a key created with a KDF. You can use Rfc2898DeriveBytes for C#, and hash_pbkdf2 for PHP.

如果您不检查邮件的真实性,则可能会更改您的数据,或者您的服务可能会受到填充oracle攻击的攻击。您可以使用MAC来验证您的消息(对于C#,为 HMACSHA256 ,对于PHP,为 hash_hmac ),也可以使用诸如GCM。

If you don't check the authenticity of the message, then your data could be altered, or your service could be vulnerable to padding oracle attacks. You can use a MAC to verify your message (HMACSHA256 for C#, hash_hmac for PHP) or use an authenticated mode like GCM.

这篇关于将C#AES 256解密移植到PHP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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