【问题标题】:Not sure how to port a C# encryption function to PHP不确定如何将 C# 加密函数移植到 PHP
【发布时间】:2013-10-15 02:06:35
【问题描述】:

我有一个 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() 返回的十六进制转换为字节数组?”其次“我将如何散列这些字节数组?” (推论“将字节数组转换回十六进制字符串并对它们进行散列就足够了吗?”)

【问题讨论】:

    标签: c# php encryption hash


    【解决方案1】:

    与 .NET 中字符串是编码为 Unicode 序列的字符串相比,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));
    

    然后这个函数将对两个键进行异或:

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

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

    【讨论】:

    • 所以,本质上,我应该在对它们做任何事情之前用hex2bin 包装我所有的hash 输出?那么,我可以用$string_that_is_secretly_just_bytes[$i]访问每个字节吗?
    • @AlexVanLiew:不需要,hash 上的第三个参数会自动执行此操作。是的,您可以直接将字符串视为数组。我仍在补充答案。
    • 我的印象是参数返回的字符串如“1000100100000100”,很高兴知道。我认为这行得通,让我检查一下。
    • 确实有效。我检查的时间太长了,因为我在加载文件和误读我的哈希过程(两次)时遇到了许多错误。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多