不确定如何将 C# 加密函数移植到 PHP


Not sure how to port a C# encryption function to PHP

>我在 C# 中有一个基本的加密函数,用于加密和存储游戏的保存文件,该函数使用游戏网站的用户名和密码。最近我意识到,如果用户要更改他们的密码,这将导致他们的保存变得无法访问,因为它是用他们的旧密码加密的。因此,我正在尝试构建一个PHP函数,以便在他们更新密码时"重新转换"他们的保存。不幸的是,问题在于 C# 使用字节数组来执行哈希,而 PHP 使用字符串,我不确定如何协调两者。以下是一般过程:

  • 哈希用户名(进入字节数组(
  • 哈希密码(进入字节数组(
  • 连接用户名 + 密码哈希(成两倍长的字节数组(
  • 用于获取密钥的哈希结果(返回到 256 位长度(
  • 带有密钥的逐字节
  • 或文件以获取加密文件

我不确定如何在 PHP 中完成此操作。我最初尝试使用unpack('C*', hash("sha256", $thing_to_be_hashed, false))但这似乎没有产生正确的字节数组。然后我试了这个:

$new_key = hash("sha256", hash("sha256", $username, false) . hash("sha256", $newpass, false), false);
$old_key = hash("sha256", hash("sha256", $username, false) . hash("sha256", $oldpass, false), false);
$conversion_key = array();
for($i = 0; $i < strlen($new_key); ++$i) {
    $conversion_key[] = $old_key[$i] ^ $new_key[$i]; 
    // this part with the array is a bit wonky, I know, but it didn't seem like
    // it would have worked anyway since I was xor'ing things like 'f' and '3'
    // instead of bytes like '23' and '57'.
}
$file_contents = file_get_contents("savefile.sav");
for($i = 0; $i < strlen($file_contents); ++$i) {
    $file_contents[$i] = $file_contents[$i] ^ $conversion_key[$i % count($conversion_key)]; // I read somewhere I can access $file_contents like this to get bytes
}

不幸的是,这两种方法在任何阶段都不起作用(以前的 unpack 方法甚至没有为哈希的第一阶段生成正确的字节数组,我也不确定我在第二阶段将它们正确地放回字符串中(。我将不胜感激我能得到的任何帮助。谢谢!

编辑:我突然想到unpack()不会给我正确的字节数组,因为它实际上是在解码字符串;所以我想我的主要问题首先是"我将如何将hash()返回的十六进制转换为字节数组?"其次是"我将如何对这些字节数组进行哈希处理?"(推论是"将字节数组转换回十六进制字符串并对其进行哈希处理就足够了吗?

字符串是编码的Unicode序列的.NET相反,PHP的字符串是字节的哑序列 - 所以本质上,它们已经字节数组。因此,在PHP端,您可以使用字符串完成所有需要的操作,并且根本不需要涉及数组,这反过来意味着不需要unpack

要处理的主要问题是 PHP 哈希函数默认返回十六进制编码而不是直接二进制输出。从一个转换为另一个非常容易:使用 hex2bin ,但仅将第三个(可选(参数作为 true 也容易得多。

因此,您可以使用以下方法获取所需的哈希值:

// for convenience
function sha256($data) {
    return hash("sha256", $data, true);
}
$new_key = sha256(sha256($username).sha256($newpass));
$old_key = sha256(sha256($username).sha256($oldpass));

然后,此函数将对两个键进行 XOR 运算:

function str_xor($str1, $str2) {
    if (strlen($str1) != strlen($str2)) {
        return false;
    }
    $len = strlen($str1);
    for($i=0; $i < $len; $i++) {
        $str1[$i] = $str1[$i] ^ $str2[$i];
    }
    return $str1;
}

因此,您可以使用现有循环将保存的数据从一个密钥"重新加密"到另一个密钥。