如何将C#Rijndael加密转换为PHP? [英] How do I convert this C# Rijndael encryption to PHP?

查看:113
本文介绍了如何将C#Rijndael加密转换为PHP?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在SO上已经有一些有用的问题:

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.

'尝试了各种方法,但最终得到错误IV参数必须与块大小一样长,或与生成的哈希不匹配的文本。

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.

这是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数据库。我打算加密密码,并将生成的哈希与存储在数据库中的哈希值进行比较,以进行验证。

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.

编辑:

我意识到在C#函数中, PasswordDeriveBytes 正在被调用并传递一个字节数组作为参数,我在PHP版本中没有模拟。我发现这源于 Codeproject示例,而且ASCII假设Ivan Medvedev中的字节数组,我认为是作者的例子。不幸的是我不能改变这个。

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.

推荐答案

我认为PHP版本实际上可以添加00h值字节到密钥和IV。它们都具有无效大小:每个字节为8个字节。对于AES-128,它们需要扩展到16个字节。在您的C#代码中,您使用32个字节的密钥,因此这将使用256位的密钥大小的AES。

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.

此外,您不要在 PasswordDeriveBytes 中指定迭代次数,因此您应该将其指定为类不指定默认迭代次数 - 根据您的意见,这将是100,让我们假设它是。

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.

哦,你使用错误的加密方法。 MCRYPT_RIJNDAEL_256使用256位的密码块指定Rijndael算法,而不是256位的密钥。可能的是,键的位数只是关键时间的字节数8。

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?

function Encrypt($pass, $salt)
{
     $derived = PBKDF1($pass, $salt, 100, 48);
     $key = bin2hex(substr($derived, 0, 32));
     $iv = bin2hex(substr($derived, 32, 16));
     return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $pass, MCRYPT_MODE_CBC, $iv);
}

最后,请检查生成的IV和密钥是否与PHP中的匹配在执行加密或解密之前。你确定那个PHP PBKDF1函数是否正确?

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?

更新:
这里是有关PasswordDeriveBytes中M $ PBKDF1例程的一些更多信息(包括可以尝试和转换的Java代码):

UPDATE: Here is some more information on the M$ PBKDF1 routines in PasswordDeriveBytes (including Java code which you may try and convert):


ha,我看到你的观点。

ha, I see your point.

有趣的是,使用.NET:结果不同当调用48
或调用32后跟16:

Interestingly, using .NET: the results are different when calling 48 or calling 32 followed by 16:

.NET GetBytes(32 +16):
04DD9D139DCB9DE889946D3662B319682159FF9C9B47FA15ED205C7CAF890922655D8DD89AE1CAAC60A8041FCD7E8DA4

.NET GetBytes( 32 +16 ): 04DD9D139DCB9DE889946D3662B319682159FF9C9B47FA15ED205C7CAF890922655D8DD89AE1CAAC60A8041FCD7E8DA4

.NET GetBytes(32)
04DD9D139DCB9DE889946D3662B319682159FF9C9B47FA15ED205C7CAF890922
随后GetBytes(16)89946D3662B3196860A8041FCD7E8DA4

.NET GetBytes( 32 ) 04DD9D139DCB9DE889946D3662B319682159FF9C9B47FA15ED205C7CAF890922 Followed by GetBytes( 16 ) 89946D3662B3196860A8041FCD7E8DA4

真正的Microsoft代码,它们不能更改它,因为它可能会破坏该领域的应用程序。请注意,当使用16,然后8字节或直接由24字节设计调用它们时,它们也将返回不同的结果。您最好升级到PBKDF2,并将PBKDF1限制在最多20个字节,如标准中所定义。

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.

这篇关于如何将C#Rijndael加密转换为PHP?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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