drngnh708353 2012-01-25 22:55
浏览 103
已采纳

如何将此C#Rijndael加密转换为PHP?

There are already some helpful questions on SO:

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.

  • 写回答

3条回答 默认 最新

  • dpafea04148 2012-01-26 00:53
    关注

    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?

    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);
    }
    

    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):

    ha, I see your point.

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

    .NET GetBytes( 32 +16 ): 04DD9D139DCB9DE889946D3662B319682159FF9C9B47FA15ED205C7CAF890922655D8DD89AE1CAAC60A8041FCD7E8DA4

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

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?
  • ¥15 ubuntu系统下挂载磁盘上执行./提示权限不够
  • ¥15 Arcgis相交分析无法绘制一个或多个图形
  • ¥15 关于#r语言#的问题:差异分析前数据准备,报错Error in data[, sampleName1] : subscript out of bounds请问怎么解决呀以下是全部代码:
  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型