4

我正在使用两个不同的库来生成用于文件验证的 SHA-1 哈希 - Crypto++库的旧版本和由 Ruby 实现的 Digest::SHA1 类。虽然我见过其他由编码差异导致的哈希不匹配的实例,但这两个库输出的哈希几乎相同。

例如,通过每个进程传递一个文件会产生以下结果:

加密++ 01c15e4f46d8181b984fa2a2c740f8f67130acac

红宝石:eac15e4f46d8181b984fa2a2c740f8f67130acac

如您所见,只有哈希字符串的前两个字符不同,并且这种行为在许多文件中重复出现。我查看了每个实现的源代码,乍一看,我发现的唯一区别在于用于 160 位散列的数据十六进制。我不知道该十六进制是如何在算法中使用的,而且我认为如果有人以前遇到过这个问题,我可能会更快地提出这个问题。

我已经包含了来自下面各个库的数据。我还包括了来自 OpenSSL 的值,因为这三个库中的每一个都有略微不同的值。

加密++:

digest[0] = 0x67452301L;
digest[1] = 0xEFCDAB89L;
digest[2] = 0x98BADCFEL;
digest[3] = 0x10325476L;
digest[4] = 0xC3D2E1F0L;

红宝石:

context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;

OpenSSL:

#define INIT_DATA_h0 0x67452301UL
#define INIT_DATA_h1 0xefcdab89UL
#define INIT_DATA_h2 0x98badcfeUL
#define INIT_DATA_h3 0x10325476UL
#define INIT_DATA_h4 0xc3d2e1f0UL

顺便说一下,这里是用于在 Ruby 中生成哈希的代码。我无权访问 Crypto++ 实现的源代码。

File.class_eval do
    def self.hash_digest filename, options = {}
        opts = {:buffer_length => 1024, :method => :sha1}.update(options)
        hash_func = (opts[:method].to_s == 'sha1') ? Digest::SHA1.new : Digest::MD5.new
        open(filename, "r") do |f|
            while !f.eof
                b = f.read
                hash_func.update(b)
            end
        end
        hash_func.hexdigest
    end
end
4

2 回答 2

2

这没有多大意义。如果 SHA1 实现有问题,例如这些数字,它可能会产生与真正的 SHA1 哈希完全不同的哈希,而不是仅仅一个字节。即使您的文件读取循环出现问题,它会删除换行符或其他东西,您仍然会通过更改流中的一个字节来获得完全不同的哈希,它不会是真正的 SHA1 哈希的一个字节.

如果我在下面的程序中使用你的方法,我会得到正确的结果。

#!/usr/bin/env ruby
require 'digest/sha1'
require 'digest/md5'

File.class_eval do
  def self.hash_digest filename, options = {}
    opts = {:buffer_length => 1024, :method => :sha1}.update(options)
    hash_func = (opts[:method].to_s == 'sha1') ? Digest::SHA1.new : Digest::MD5.new
    open(filename, "r") do |f|
      while !f.eof
        b = f.read
        hash_func.update(b)
      end
    end
    hash_func.hexdigest
  end
end

puts File.hash_digest(ARGV[0])

并将其输出与 OpenSSL 的输出进行比较。

tmp$ dd if=/dev/urandom of=random.bin bs=1MB count=1
1+0 records in
1+0 records out
1000000 bytes (1.0 MB) copied, 0.287903 s, 3.5 MB/s
tmp$ ./digest.rb random.bin
a511d8153426ebea4e4694cde78db4e3a9e413d1
tmp$ openssl sha1 random.bin
SHA1(random.bin)= a511d8153426ebea4e4694cde78db4e3a9e413d1

所以你的散列方法没有问题。它的返回值和它被打印之间出现了问题。

于 2010-08-22T04:41:24.993 回答
2

我猜你在打印出 SHA-1 哈希值时差了一个字节。我们能看到打印它们的代码吗?如果没有,这里有几个可能有用的诊断:

  1. 制作一个非常短的文件(比如一个单词),并将其内容作为十六进制字符串放入http://www.fileformat.info/tool/hash.htm。不过,您需要确切地知道文件的十六进制内容。您可以在 Unix 上使用 xxd ,但您必须注意字节顺序问题。我不确定如何在其他操作系统上执行此操作。

  2. 通过相同的 SHA-1 实现多次运行相同的文件是否总是在第一个字节中打印出相同的值?如果是这样,当您更改文件时,该值是否会更改?

于 2010-08-19T01:11:57.290 回答