如何将此 C# Rijndael 加密转换为 PHP?
SO 上已经有一些有用的问题:
但是我仍然遇到困难就我的具体情况而言。
我尝试了各种方法,但最终收到错误“IV 参数必须与块大小一样长”或与生成的哈希值不匹配的文本。
我对加密的了解还不足以弄清楚我做错了什么。
这是 php 版本:
$pass = 'hello';
$salt = 'application-salt';
echo Encrypt('hello', 'application-salt');
function Encrypt($pass, $salt)
{
$derived = PBKDF1($pass, $salt, 100, 16);
$key = bin2hex(substr($derived, 0, 8));
$iv = bin2hex(substr($derived, 8, 8));
return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $pass, MCRYPT_MODE_CBC, $iv);
}
function PBKDF1($pass, $salt, $count, $dklen)
{
$t = $pass.$salt;
$t = sha1($t, true);
for($i=2; $i <= $count; $i++)
{
$t = sha1($t, true);
}
$t = substr($t,0,$dklen-1);
return $t;
}
和 C# 版本:
Console.WriteLine(Encrypt("hello", "application-salt"));
// output: "Hk4he+qKGsO5BcL2HDtbkA=="
public static string Encrypt(string clearText, string Password)
{
byte[] clearData = System.Text.Encoding.Unicode.GetBytes(clearText);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
MemoryStream ms = new MemoryStream();
Rijndael alg = Rijndael.Create();
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.Close();
byte[] encryptedData = ms.ToArray();
return Convert.ToBase64String(encryptedData);
}
我希望能够在基于 php 的新应用程序中验证用户登录,该应用程序将与现有 C# 应用程序相同的 MySQL 数据库进行通信。我打算加密密码,并将生成的哈希值与数据库中存储的哈希值进行比较以进行身份验证。
任何指示将不胜感激。
编辑:
我意识到在 C# 函数中,正在调用 PasswordDeriveBytes
并传递一个字节数组作为参数,而在 PHP 版本中我没有类似的参数。我发现这源自 Codeproject 示例 ASCII 中的字节数组拼写为“Ivan Medvedev”,我认为他是示例作者。不幸的是我无法改变这一点。
There are already some helpful questions on SO:
- Rijndael 256 Encrypt/decrypt between c# and php?
- Rewrite Rijndael 256 C# Encryption Code in PHP
- Rijndael/AES decryption C# to PHP conversion
However I am still having difficulties with my particular case.
I've tried various methods but end up getting the error "The IV parameter must be as long as the blocksize"
or text that doesn't match the resulting hash.
I don't understand encryption enough to work out what I'm doing wrong.
Here is the php version:
$pass = 'hello';
$salt = 'application-salt';
echo Encrypt('hello', 'application-salt');
function Encrypt($pass, $salt)
{
$derived = PBKDF1($pass, $salt, 100, 16);
$key = bin2hex(substr($derived, 0, 8));
$iv = bin2hex(substr($derived, 8, 8));
return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $pass, MCRYPT_MODE_CBC, $iv);
}
function PBKDF1($pass, $salt, $count, $dklen)
{
$t = $pass.$salt;
$t = sha1($t, true);
for($i=2; $i <= $count; $i++)
{
$t = sha1($t, true);
}
$t = substr($t,0,$dklen-1);
return $t;
}
And the C# version:
Console.WriteLine(Encrypt("hello", "application-salt"));
// output: "Hk4he+qKGsO5BcL2HDtbkA=="
public static string Encrypt(string clearText, string Password)
{
byte[] clearData = System.Text.Encoding.Unicode.GetBytes(clearText);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
MemoryStream ms = new MemoryStream();
Rijndael alg = Rijndael.Create();
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.Close();
byte[] encryptedData = ms.ToArray();
return Convert.ToBase64String(encryptedData);
}
I want to be able to validate user logins in a new php-based application which will communicate to the same MySQL database as an existing C# application. I intend to encrypt the password and compare the resulting hash to the one stored in the database to authenticate.
Any pointers would be most appreciated.
Edit:
I realize that in the C# function, the PasswordDeriveBytes
is being called and passed a byte array as an argument for which I don't have an analog in the PHP version. I discovered that this originates from a Codeproject example and that the byte array in ASCII spells "Ivan Medvedev" whom I assume to be the example author. Unfortunately I cannot change this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于正在寻找从 C# 到 PHP 的精确转换的人,下面的代码片段可能会有所帮助
Below snippet may be helpful who are looking for exact conversion from C# to PHP
我认为 PHP 版本实际上可能会向 key 和 IV 添加 00h 值字节。它们的大小都无效:每个都是 8 字节。对于 AES-128,它们需要扩展至 16 个字节。在您的 C# 代码中,您使用 32 字节作为密钥,因此将使用密钥大小为 256 位的 AES。
此外,您没有在
PasswordDeriveBytes
中指定迭代次数,您应该指定它,因为该类没有指定默认的迭代次数 - 根据您的注释,这将是 100,让我们假设它是。哦,你使用了不正确的加密方法。 MCRYPT_RIJNDAEL_256 指定使用 256 位的块大小的 Rijndael 算法,而不是 256 位的密钥。据推测,密钥的位大小就是密钥的字节数乘以 8。
您可以用它替换您的 Encrypt 函数并重试吗?
最后,在进行加密或解密之前,请检查生成的IV和密钥与PHP中的IV和密钥是否匹配。您确定 PHP PBKDF1 函数正确吗?
更新:
这里是有关 M$ PBKDF1 例程的更多信息在PasswordDeriveBytes中(包括您可以尝试并转换的Java代码):
真正的 Microsoft 代码,他们无法更改它,因为它可能会破坏现场应用程序。请注意,当使用 16 个字节然后使用 8 个字节或按设计直接使用 24 个字节调用时,它们也会返回不同的结果。您最好升级到 PBKDF2,并将 PBKDF1 按照标准中的定义限制为最大 20 个字节。
I think that the PHP version may actually add 00h valued bytes to the key and IV. They both have an invalid size : 8 bytes for each. They need to be extended to 16 bytes for AES-128. In your C# code you use 32 bytes for the key, which will therefore use AES with a key size of 256 bits.
Futhermore, you don't specify the number of iterations in
PasswordDeriveBytes
, you should specify it as the class does not specify the default number of iterations - according to your comments, this would be 100, lets assume it is.Oh, and you use the incorrect encryption method. MCRYPT_RIJNDAEL_256 specifies the Rijndael algorithm using a blocksize of 256 bits, not keys of 256 bits. Presumably, the bitsize of the keys is simply the number of bytes of the key times 8.
Could you replace your Encrypt function with this and try again?
Finally, please check if the generated IV and key match with the ones in PHP before performing encryption or decryption. Are you sure that that PHP PBKDF1 function is correct?
UPDATE:
Here is some more information on the M$ PBKDF1 routines in PasswordDeriveBytes (including Java code which you may try and convert):
True Microsoft code, and they cannot change it because it could break applications in the field. Note that they also would return different results when calling it with 16 and then 8 bytes or directly by 24 bytes by design. You'd better upgrade to PBKDF2, and keep PBKDF1 limited to 20 bytes max, as defined in the standards.
PHP 已将此功能内置到其 Mcrypt 模块中。
试试这个:http://www.php.net/manual/en/book。 mcrypt.php
PHP already has this capability built into its Mcrypt module.
Try this: http://www.php.net/manual/en/book.mcrypt.php