为什么HMAC SHA-1会使用相同的输入返回不同的摘要?

时间:2008-12-12 10:50:35

标签: perl encryption hmac digest sha1

我正在尝试为Amazon S3 Web服务构建一个有效的加密签名,使用Objective C编写连接库。

我已经遇到了使用ObjC代码的HMAC SHA-1摘要问题,因此我将它放在一边,查看现有的,正在运行的Perl代码,以尝试解决摘要创建问题。

我正在测试s3ls包的Net::Amazon::S3命令的HMAC SHA-1摘要输出,并将其与我提取的_encode子例程进行比较,并将其放入自己的perl脚本中:

#!/usr/bin/perl -w                                                                                                                                                                                    

use MIME::Base64 qw(encode_base64);
use Digest::HMAC_SHA1;
use String::Escape qw( printable unprintable );

sub _ascii_to_hex {
    (my $str = shift) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;
    return $str;
}

sub _encode {
    my ( $aws_secret_access_key, $str ) = @_;
    print "secret key hex: "._ascii_to_hex($aws_secret_access_key)."\n";
    my $hmac = Digest::HMAC_SHA1->new($aws_secret_access_key);
    $hmac->add($str);
    my $digest = $hmac->digest;
    print "cleartext hex: "._ascii_to_hex($str)."\n";
    print "digest hex: "._ascii_to_hex($digest)."\n";
    my $b64 = encode_base64( $digest, '' );
    print "encoded: ".$b64."\n";
}

my $secret = "abcd1234";
my $cleartext = "GET\n\n\nFri, 12 Dec 2008 10:08:51 GMT+00:00\n/";
_encode($secret, $cleartext);

以下是此脚本的示例输出:

$ ./testhmac.pl 
secret key hex: 6162636431323334
cleartext hex: 4745540a0a0a4672692c2031322044656320323030382031303a30383a353120474d542b30303a30300a2f
digest hex: 63308f9b8a198440d6d8685a3f3f70d0aab02f68
encoded: YzCPm4oZhEDW2GhaPz9w0KqwL2g=

我测试的是,如果我将相同的密钥和明文输入到_encode包的相同Net::Amazon::S3函数中,我应该看到完全相同的密钥,明文和摘要字节。

实际上,我获得了密钥和明文的相同字节。

但是我得到了一些不同的摘要(当然还有base64编码),例如:

$ s3ls --access-key=foobar --secret-key=abcd1234
...
secret key hex: 6162636431323334
cleartext hex: 4745540a0a0a4672692c2031322044656320323030382031303a30383a353120474d542b30303a30300a2f
digest hex: c0da50050c451847de7ed055c5286de584527a22
encoded: wNpQBQxFGEfeftBVxSht5YRSeiI=

我已经验证了密钥和明文是两个脚本的相同输入。编码子例程在两个脚本中几乎完全相同(除了传递给子例程的未使用的参数,我从我的自定义版本中删除)。

如果输入字节和_encode子例程相同,会导致HMAC SHA-1摘要在两种情况下的计算方式不同?

(我还在RFC 2201验证了针对测试用例的两个脚本。)

4 个答案:

答案 0 :(得分:3)

我发现比较中哈希的主要问题是:

  1. 确保两个比较中的数据和密钥相同
  2. 确保数据和密钥在两次比较中使用相同的字符编码
  3. 确保密钥和文本在两个脚本中都是相同的,即哪一个是密钥,哪一个是文本(这已经抓住了我多次)。
  4. 尝试使用Digest :: SHA模块为您创建哈希并将结果与​​之比较。

    use Digest::SHA qw(hmac_sha1_hex);
    my $hash = hmac_sha1_hex($data, $key);
    

    请参阅http://perldoc.perl.org/Digest/SHA.pdf

    上的文档

答案 1 :(得分:2)

  

两个脚本中的编码子例程实际上是相同的(除了传递给子例程的未使用的参数,我从自定义版本中删除了它。)

由于您没有比较摘要本身,而是比较摘要的Base-64编码版本,我建议先备份一步并自行检查摘要。 Base-64编码例程可能不正确。

如果你无法比较摘要本身,那么在两个程序中使用相同的编码例程,看看你得到了什么。

答案 2 :(得分:1)

我恐怕在这里帮不了多少,但你发布的内容肯定有问题。您的示例脚本为我生成了不同的输出,您发布的输出实际上不正确。

怎么可能呢

secret key hex: abcd...1234

永远是

的结果
_ascii_to_hex("blahblahblah")

当然,整个ascii_to_hex事情与你的问题完全无关,但它表明你应该仔细检查你的结果。

答案 3 :(得分:1)

分而治之?

RFC中的测试向量是最佳起点。他们在两个案件中都通过了吗?你尝试过哪些?如果某些工作和其他工作没有,最可能的问题是两个API中的一个不正确地编组键输入(签名与无符号数组,字符集转换等等)

另外,当你的例子是无稽之谈时,它很难帮助你。正如其他人所提到的,blah blah的十六进制表示不是abc..123。让我想知道你的例子中还有什么是不准确的?