【问题标题】:How do I sha1 hash hex values correctly in PHP?如何在 PHP 中正确地对十六进制值进行 sha1 哈希处理?
【发布时间】:2010-10-11 12:55:09
【问题描述】:

我有一系列十六进制字节。理论上,最后 20 个字节是第一部分的 sha1 哈希:

3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00 BD 0D EA 71 BE 0B 25 75 E7 5C 58 20 31 57 F3 9A EF 69 1B FD

如果我像这样在 PHP 中对它们应用 sha1:

echo sha1("3FF4E525982052700163006800750079006900000074289610099DC9010074A0D7DB0B9DC9014D007900470072006F007500700000002F000000");

我回来了:

d68ca0839df6e5ac7069cc548d82f249752f3acb

但我正在寻找这个值:

bd0dea71be0b2575e75c58203157f39aef691bfd  

(BD 0D EA 71 BE 0B 25 75 E7 5C 58 20 31 57 F3 9A EF 69 1B FD)

是因为我将十六进制值视为字符串吗?我需要做什么?

编辑:

这是我工作的原始信息:

ticketBytes
{byte[0x0000003a]}
    [0x00000000]: 0x3f
    [0x00000001]: 0xf4
    [0x00000002]: 0xe5
    [0x00000003]: 0x25
    [0x00000004]: 0x98
    [0x00000005]: 0x20
    [0x00000006]: 0x52
    [0x00000007]: 0x70
    [0x00000008]: 0x01
    [0x00000009]: 0x63
    [0x0000000a]: 0x00
    [0x0000000b]: 0x68
    [0x0000000c]: 0x00
    [0x0000000d]: 0x75
    [0x0000000e]: 0x00
    [0x0000000f]: 0x79
    [0x00000010]: 0x00
    [0x00000011]: 0x69
    [0x00000012]: 0x00
    [0x00000013]: 0x00
    [0x00000014]: 0x00
    [0x00000015]: 0x74
    [0x00000016]: 0x28
    [0x00000017]: 0x96
    [0x00000018]: 0x10
    [0x00000019]: 0x09
    [0x0000001a]: 0x9d
    [0x0000001b]: 0xc9
    [0x0000001c]: 0x01
    [0x0000001d]: 0x00
    [0x0000001e]: 0x74
    [0x0000001f]: 0xa0
    [0x00000020]: 0xd7
    [0x00000021]: 0xdb
    [0x00000022]: 0x0b
    [0x00000023]: 0x9d
    [0x00000024]: 0xc9
    [0x00000025]: 0x01
    [0x00000026]: 0x4d
    [0x00000027]: 0x00
    [0x00000028]: 0x79
    [0x00000029]: 0x00
    [0x0000002a]: 0x47
    [0x0000002b]: 0x00
    [0x0000002c]: 0x72
    [0x0000002d]: 0x00
    [0x0000002e]: 0x6f
    [0x0000002f]: 0x00
    [0x00000030]: 0x75
    [0x00000031]: 0x00
    [0x00000032]: 0x70
    [0x00000033]: 0x00
    [0x00000034]: 0x00
    [0x00000035]: 0x00
    [0x00000036]: 0x2f
    [0x00000037]: 0x00
    [0x00000038]: 0x00
    [0x00000039]: 0x00

hashed
{byte[0x00000014]}
    [0x00000000]: 0xbd
    [0x00000001]: 0x0d
    [0x00000002]: 0xea
    [0x00000003]: 0x71
    [0x00000004]: 0xbe
    [0x00000005]: 0x0b
    [0x00000006]: 0x25
    [0x00000007]: 0x75
    [0x00000008]: 0xe7
    [0x00000009]: 0x5c
    [0x0000000a]: 0x58
    [0x0000000b]: 0x20
    [0x0000000c]: 0x31
    [0x0000000d]: 0x57
    [0x0000000e]: 0xf3
    [0x0000000f]: 0x9a
    [0x00000010]: 0xef
    [0x00000011]: 0x69
    [0x00000012]: 0x1b
    [0x00000013]: 0xfd

【问题讨论】:

  • 你确定使用的算法是SHA1吗?
  • 确认是sha1。如果不是,它将短于 20 个字节。
  • 好吧,如果它是 SHA1,那么这 58 个字节就不是。
  • 我要让我的 .NET 同事确认他可以从数据中获取散列。谢谢,我发现后会更新。
  • 啊,顺便说一句,为了避免所有这些繁琐的转换,最好将这些字节的格式设置为“\x3F\xF4\xE5\x25\x98....”

标签: php hash hex


【解决方案1】:

这里有些不对劲。 SHA1 digests are 160 bits,即20个十六进制数,用40个字符表示。您期望的值是 32 个字符,这意味着它不是 SHA1 摘要 - 或者缺少我还不理解的其他内容。

【讨论】:

  • 对错误信息表示抱歉,已编辑问题并带有正确的“预期”值。
【解决方案2】:

不幸的是,这也不能为您提供正确的值,但它可能会为您指明正确的方向。无论哪种方式,在散列之前将十六进制代码实际转换为二进制字符串是一个更好的主意。像这样:

$str = "3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00";

// Create an array where each entry represents a single byte in hex
$arr = explode(" ", $str);
// Convert the hex to decimal
$arr = array_map("hexdec", $arr);
// Convert the decimal number into the corresponding ASCII character
$arr = array_map("chr", $arr);

// Implode the array into a string, and hash the result
$result = sha1(implode($arr));

echo $result."\n";

结果是 fa3ebc158305d09443b4315d35c0eee5aa72daef,这也是 vartecs 代码产生的结果。我认为我们不知道如何计算正确参考的某些方面,因为根据我们所知道的事实,这里和 vartec 使用的方法绝对是最合乎逻辑的方法。

【讨论】:

    【解决方案3】:
    $hexes = "3F F4 E5 25 98 20 52 70 01 63 00 68 00 75 00 79 00 69 00 00 00 74 28 96 10 09 9D C9 01 00 74 A0 D7 DB 0B 9D C9 01 4D 00 79 00 47 00 72 00 6F 00 75 00 70 00 00 00 2F 00 00 00";
    $hexes = split(' ',$hexes);
    $hexes = array_map('hexdec',$hexes);
    $hexes = call_user_func_array('pack',array_merge(array('C*'),$hexes));
    echo sha1($hexes);
    

    顺便说一句。您可以通过以另一种格式传递它来实现相同的目的:

    $hexes = "\x3F\xF4\xE5\x25\x98\x20\x52\x70\x01\x63\x00\x68\x00\x75\x00\x79\x00\x69\x00\x00\x00\x74\x28\x96\x10\x09\x9D\xC9\x01\x00\x74\xA0\xD7\xDB\x0B\x9D\xC9\x01\x4D\x00\x79\x00\x47\x00\x72\x00\x6F\x00\x75\x00\x70\x00\x00\x00\x2F\x00\x00\x00";
    echo sha1($hexes);
    

    【讨论】:

      【解决方案4】:

      您可以使用pack function将十六进制字符串转换为二进制:

      $bin = pack('H*', preg_replace('/[^0-9a-fA-F]+/', '', $hex));
      

      【讨论】:

      • 这给了我与 emil 的建议相同的结果。
      【解决方案5】:

      使用chr()..将它们转换成字符串

      $string = "3f ........"
      $c = split(' ',$string);
      $string2 = '';
      foreach( $c as $char )
      {
       $string2 .= chr(hexdec($c));
      }
      
      echo sha1($string2);
      

      【讨论】:

        【解决方案6】:

        这行得通:

        function strToHex($string)
        {
            $hex='';
            for ($i=0; $i < strlen($string); $i++)
            {
                $hex .= dechex(ord($string[$i]));
            }
            return $hex;
        }
        echo sha1(strToHex("3FF4E525982052700163006800750079006900000074289610099DC9010074A0D7DB0B9DC9014D007900470072006F007500700000002F000000"));
        
        >> 5b102a482247fef726843f214f8a81b1627bb634
        

        【讨论】:

        • 我不确定这里,但您不想从示例代码中以相反的顺序迭代字符串吗?更像是: for ($i = strlen($string); $i> 0 ; $i++)
        • 不...无限循环。 i 将永远大于 0。
        • 我认为这个例子是所有建议中最奇怪的。在这种情况下, dechex(ord()) 似乎完全不合逻辑。 ord() 将每个十六进制字符转换为 ascii,然后再转换回十六进制。这到底有什么意义?
        • 每一个十六进制字符转换成ASCII码,也就是说。只是为了避免任何误解。
        【解决方案7】:

        原来我需要使用带有验证密钥的 hash_hmac() 而不是 sha1()。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-25
          • 1970-01-01
          • 2011-05-18
          • 2018-02-22
          • 2014-11-03
          • 2011-08-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多