[英]Porting C# AES 256 decryption to PHP
I'm trying to port this C# code to PHP: 我正在尝试将此C#代码移植到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);
}
The content
parameter is a 44 character long string, base 64 encoded, the password
parameter is a 6 character long string. content
参数是一个44字符长的字符串,以64为基数编码, password
参数是一个6字符长的字符串。
This is the PHP code I put together: 这是我放在一起的PHP代码:
$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);
The result of the C# code is a 10 character long number. C#代码的结果是10个字符长的数字。 The result from PHP is some 32 character long gibberish - I guess binary data. PHP的结果是32个字符长的乱码-我猜是二进制数据。
Can anybody help me to fix that code, or has an idea what I can try? 有人可以帮助我修复该代码,或者对我可以尝试的方法有所了解吗?
As mentioned by zaph in the comments this code is not considered safe and i advise against using it in a production environment. 正如zaph在评论中所提到的,此代码不被认为是安全的,我建议不要在生产环境中使用它。 Quoting zaph's comment : 引用zaph的评论 :
Essentially the code is not secure. 本质上,代码是不安全的。 Keys should be created from a password with a key derivation function such as PBKDF2. 应该使用具有密钥派生功能的密码(例如PBKDF2)来创建密钥。 IVs should be random for each encryption, never the password/key. 每次加密的IV应该是随机的,而不是密码/密钥。 The IV can be and generally are prepended to the encrypted data, they do not need to be secret. IV可以并且通常是加密数据的前缀,它们不需要是秘密的。
That being said, here is a PHP equivalent of your C# code: 话虽如此,这是C#代码的PHP等效项:
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 strings are Little Endian UTF-16 encoded. C#Unicode字符串是Little Endian UTF-16编码的。 In order to decode them properly in PHP we'll have to use mb_convert_encoding
. 为了在PHP中正确解码它们,我们必须使用mb_convert_encoding
。
PHP test: PHP测试:
$password = "012345";
$content = "EJWgZ/26wp+Cb5utbM1aMk8XfqPQide4dzjQzzzYfj8=";
echo DecryptString($content, $password);
//0123456789
C# test: C#测试:
string password = "012345";
string content = "EJWgZ/26wp+Cb5utbM1aMk8XfqPQide4dzjQzzzYfj8=";
Console.WriteLine(so.DecryptString(content, password));
//0123456789
Some tips: 一些技巧:
PHP's openssl_decrypt
uses PKCS padding by default, and can handle base64 encoded data. PHP的openssl_decrypt
默认情况下使用PKCS填充,并且可以处理base64编码的数据。 We can take advantage of those features by setting the options
parameter to false
. 我们可以通过将options
参数设置为false
来利用这些功能。
IVs should be random bytes. IV应该是随机字节。 This is important because using a static IV makes your encryption vulnerable to attacks. 这很重要,因为使用静态IV会使您的加密容易受到攻击。 You can create secure random IVs with RNGCryptoServiceProvider
for C#, and openssl_random_pseudo_bytes
for PHP. 您可以使用C#的RNGCryptoServiceProvider
创建安全的随机IV,而使用PHP的则创建openssl_random_pseudo_bytes
。
Passwords should be as long and unpredictable as possible - 123456 is not a good password! 密码应尽可能长且不可预测-123456不是一个好的密码! 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. 尽管您可以将密码用作密钥(如果密码大小合适),但是最好使用由KDF创建的密钥。 You can use Rfc2898DeriveBytes
for C#, and hash_pbkdf2
for PHP. 您可以将Rfc2898DeriveBytes
用于C#,并将hash_pbkdf2
用于PHP。
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. 如果您不检查消息的真实性,那么您的数据可能会被更改,或者您的服务可能会受到填充oracle攻击的攻击。 You can use a MAC to verify your message ( HMACSHA256
for C#, hash_hmac
for PHP) or use an authenticated mode like GCM. 您可以使用MAC来验证您的邮件( HMACSHA256
为C#, hash_hmac
对于PHP),或者使用经过验证的模式,像GCM。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.