PHP中的perl替代hash_hmac('ripemd160',$ data,$ key)

时间:2013-04-18 20:36:34

标签: perl hmac

我需要在hash_hmac('ripemd160', $data, $key)在PHP中生成的Perl中生成相同的结果

管理将其追溯到两个perl模块,只是不能让它们一起工作......

摘要:: HMAC和Crypt :: RIPEMD160

use Crypt::RIPEMD160;

use Digest::HMAC;
$hmac = Digest::HMAC->new('bar', 'Crypt::RIPEMD160');

$hmac->add('foo');
$digest = $hmac->digest;

任何人都有任何想法我做错了什么?

如果我使用上面的代码,我会收到以下错误: 无法在/usr/lib64/perl5/vendor_perl/5.12.4/Digest/HMAC.pm第28行调用未定义值的方法“添加”。

由于我无法在上面的代码中传递哈希函数引用,在查看hmac函数的HMAC模块后,我认为我可以直接在我的代码中编写它:

my $data = 'bar';
my $key = 'foo';
$block_size = 160;
$block_size ||= 64;
$key = Crypt::RIPEMD160->hash($key) if length($key) > $block_size;
my $k_ipad = $key ^ (chr(0x36) x $block_size);
my $k_opad = $key ^ (chr(0x5c) x $block_size);
my $digest =  Crypt::RIPEMD160->hash($k_opad, Crypt::RIPEMD160->hash($k_ipad, $data));

这确实会产生哈希但仍然是错误的

PHP生成的哈希:isceebbf5cd5e34c888b493cf7f7c39a7b181b65a3

perl hash:hash21a2fa2bf39fd99d4c9cdf147added69c32d45f9e

说实话我不关心它是如何完成的以及使用了什么模块只要我得到与php函数产生相同的哈希...在这一点上我很想写一个我从perl调用的php脚本只是为了得到哈希... :(因为我的想法已经耗尽......

3 个答案:

答案 0 :(得分:3)

Digest::HMAC仅包含Digest::HMAC_MD5Digest::HMAC_SHA1。但是,我看了Digest::HMAC_MD5的Perl代码。整个过程大约有20行代码。它基本上创建了两个方法

sub hmac_md5 {
    hmac($_[0], $_[1], \&md5, 64);
}

sub hmac_md5_hex {
    unpack("H*", &hmac_md5);
}

这几乎就是整个计划。

如果您忘记了包的面向对象样式,并使用功能样式,看起来这可能对您有用:

hmac($data, $key, \&ripemd160, 160);

或者只是:

hmac($data, $key \&ripemd160);

事实上,这已在CPAN Digest::HMAC页面上记录。

答案 1 :(得分:2)

我在讨论中可能有点迟,但在谈到Crypt::Digest::RIPEMD160时(我是本模块的作者:),您可以轻松地从同一系列模块中创建带有Crypt::Mac::HMAC的HMAC。< / p>

这很简单:

use Crypt::Mac::HMAC 'hmac';
$hmac_raw = hmac('RIPEMD160', $key, $data);

答案 2 :(得分:1)

您的代码不起作用的原因是,虽然Crypt::RIPEMD160提供的界面看起来与标准Digest界面类似,但它并不完全兼容:特别是reset() Crypt :: RIPEMD160的方法显然不会返回对它所调用的对象的引用,而Digest::HMAC中的代码恰好依赖于该细节。

通过稍微调整任一模块来修复这种不兼容性是一件微不足道的事情,要么将缺少的返回值添加到Crypt :: RIPEMD5,要么使Digest :: HMAC更少依赖于不必要的方法链接。后者就像改变线一样简单:

$self->{hasher}->reset->add($self->{k_opad}, $inner_digest);
in Digest :: HMAC to:

$self->{hasher}->reset;
$self->{hasher}->add($self->{k_opad}, $inner_digest);

(当然,我并不是建议您自己这样做,尽管可以向这些模块的维护者报告此问题。)

然而,对于目前的两个模块,它只是不起作用。我建议的解决方案是使用非OO接口,如David W.建议的那样,或者尝试更新的Crypt::Digest::RIPEMD160模块,它可以正确实现Digest接口,并且应该与Digest :: HMAC一起玩得更好。


修改 实际上,David W.的建议不会像给定的那样工作,因为Crypt :: RIPEMD160不会导出非OO ripemd160()函数。但是,您可以轻松创建一个:

use Crypt::RIPEMD160;
sub ripemd160 {
    return Crypt::RIPEMD160->hash( join "", @_ );
}

然后像这样使用它:

use Digest::HMAC qw( hmac );
sub hmac_ripemd160 {
    return hmac( @_[0, 1], \&ripemd160, 64 );
}

(是的,64字节是HMAC-RIPEMD160的正确块大小,因为RIPEMD160的输入块长度是16个32位字,等于512位或64字节。实际上,使用错误的输入块大小是当然,除了互操作性之外,不太可能引起任何问题,但是为了简单起见,HMAC结构的安全性证明假设密钥被填充为恰好一个输入块长。因此,为了确保所有实现对于相同的密钥和消息,HMAC-RIPEMD160产生相同的输出,最好坚持这个规则。)


编辑2:好的,我尝试针对HMAC-RIPEMD160 test vectors from RFC 2286测试我上面发布的代码,但无法得到匹配的结果。我最终意识到的是两件事:

  1. Digest :: HMAC导出的非OO hmac()函数假定传递给它的自定义散列函数将接受多个参数并将它们连接起来。我上面的ripemd160()包装器的原始实现没有(但我现在修复了它)。这可以说是Digest :: HMAC中的一个错误,或至少在其文档中。

  2. Crypt :: RIPEMD160模块附带了子模块Crypt::RIPEMD160::MAC,它已经实现了HMAC-RIPEMD160,即使出于某些不正当的原因,文档实际上并没有使用名称HMAC 。但是,如果您查看代码,或者只是将输出与官方测试向量进行比较,那确实就是它的作用。