Perl hmac sha256与PHP的使用包不同

时间:2014-06-25 02:55:25

标签: perl hmac sha256 digest

我必须使用SHA256 HMAC在Perl中创建一个哈希,就像这个PHP示例:

<?php
$key = pack('H*','THIS_IS_KEY');
$str ='THIS IS DE ENCODED STRING';
echo strtoupper(hash_hmac('sha256',$str, $key));
?>

我得到: 601B7C81389A37FC83C05275138280E8788CF9108528BC75D5C09CEA75904D5E

但是如果我在Perl脚本中做同样的事情:

use Digest::SHA qw(hmac_sha256_hex);
my $key = pack('H*','THIS_IS_KEY');
my $str ='THIS IS DE ENCODED STRING';
print uc(hmac_sha256_hex($str, $key));
exit;

我得到: C683FD81DEFB7CDA3C031F5280682E80851FDC246310DB8C44057BC6364454E0

如果我没有打包密钥既不是Perl也不是PHP我得到相同的结果,不幸的是我必须生成与使用PHP“pack”的示例完全相同的结果。

如果有人能帮我找到解决方案,我将不胜感激。

提前致谢

韦尔奇

1 个答案:

答案 0 :(得分:1)

代码无法理解pack()函数的实际工作方式。关键是PHP和Perl脚本之间有什么不同,所以让我们把它简化为那个计算。这是一个更简单的PHP程序:

<?php
  $key = pack('H*', 'THIS_IS_KEY');
  echo $key;
?>

如果我们将其反映到php | hexdump,我们会得到:

00000000 0000 0000 000e

这是一个类似的Perl程序:

my $key = pack('H*', 'THIS_IS_KEY');
print $key;

如果我们回复perl | hexdump,我们得到:

0000000 2cd1 cff2 204e

这是两个显着不同的键。在这两种情况下,pack()调用都使用H*格式,这意味着pack()期望接收无界的十六进制字符串(包含十六进制字符0-9A-F的字符串)。问题是'THIS_IS_KEY'不是十六进制值序列(“E”除外)。如果您通过php二进制文件本身运行测试代码,您还会看到以下这些行:

PHP Warning:  pack(): Type H: illegal hex digit T in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit H in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit I in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit S in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit _ in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit I in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit S in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit _ in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit K in - on line 2
PHP Warning:  pack(): Type H: illegal hex digit Y in - on line 2

请注意,除了'E'之外的每个字符都会抛出错误,请注意,在十六进制输出中,每个字符都会转换为空字符,除了之外的'E'。 Perl实际上试图制作一些无意义的字符并将它们转换为它可以使用的某种表示形式(例如'K'变为4,哪种有意义,因为它是F之后的第5个字符,对应于十六进制中的14)。无论如何,它未定义应该传递一个与格式不匹配的字符串的行为。

那么,你的解决方案是什么?

好吧,如果你真的需要保留'THIS_IS_KEY'作为密钥,那么等效的Perl密钥就是'000000000E0'。如果示例键仅是键值的表示,通常在Perl脚本中将PHP键中的非十六进制字符替换为“0”。 PHP似乎将十六进制字符串中的非十六进制字符视为“0”。

对于真正的解决方案,要么将字符串键转换为十六进制表示形式,要么在传递给pack()之前使用直接十六进制值作为键。我不知道关键选择的细节或者为什么要打包“钥匙”。代码的SHA256部分只需要一个字节串作为密钥。就它而言,它可以是一个直的ASCII密钥,只要两个脚本使用相同的字节序列。