【问题标题】:Digest::CRC32 with Zlib摘要::CRC32 与 Zlib
【发布时间】:2014-10-04 06:22:24
【问题描述】:

在我的代码中,我需要使用各种算法(包括 CRC32)对文件进行哈希处理。由于我还在使用Digest 系列中的其他加密哈希函数,我认为为它们维护一个一致的接口会很好。

作为记录,我确实找到了digest-crc,这是一个完全符合我要求的宝石。问题是,Zlib 是标准库的一部分,并且有一个我想重用的 CRC32 工作实现。此外,它是用 C 语言编写的,因此与 digest-crc(纯 ruby​​ 实现)相比,它应该提供更出色的性能。

实现Digest::CRC32 起初看起来很简单:

%w(digest zlib).each { |f| require f }

class Digest::CRC32 < Digest::Class
  include Digest::Instance

  def update(str)
    @crc32 = Zlib.crc32(str, @crc32)
  end

  def initialize; reset; end
  def reset; @crc32 = 0; end
  def finish; @crc32.to_s; end
end

一切正常:

crc32 = File.open('Rakefile') { |f| Zlib.crc32 f.read }
digest = Digest::CRC32.file('Rakefile').digest!.to_i
crc32 == digest
=> true

不幸的是,并非一切正常:

Digest::CRC32.file('Rakefile').hexdigest!
=> "313635393830353832"

# What I actually expected was:
Digest::CRC32.file('Rakefile').digest!.to_i.to_s(16)
=> "9e4a9a6"

hexdigest 基本上返回Digest.hexencode(digest)which works with the value of the digest at the byte level。我不确定该函数是如何工作的,所以我想知道是否可以仅使用从 Zlib.crc32 返回的整数来实现这一点。

【问题讨论】:

  • 你在哪个 ruby​​ 平台上工作?

标签: ruby digest


【解决方案1】:

Digest 期望摘要返回构成校验和的原始字节,即在 crc32 的情况下,构成该 32 位整数的 4 个字节。但是,您将返回一个包含该整数的以 10 为底的表示形式的字符串。

你想要类似的东西

[@crc32].pack('V')

将该整数转换为表示该整数的字节。一定要阅读 pack 及其各种格式说明符 - 有很多打包整数的方法取决于字节是否应该以本机字节序、大字节序、小字节序等形式呈现,所以你应该弄清楚哪个一个符合您的需求

【讨论】:

  • 我使用 [@crc32].pack('N') 让我的 Digest::CRC32.file(filename) 版本按预期工作。
【解决方案2】:

抱歉,这并不能真正回答您的问题,但它可能会有所帮助..

首先,在读取文件时,请确保传递“rb”参数。我可以看到您不在 Windows 上,但如果您的代码最终在 Windows 机器上运行,您的代码将无法正常工作,尤其是在读取 ruby​​ 文件时。示例:

crc32 = File.open('test.rb') { |f| Zlib.crc32 f.read }
#=> 189072290
digest = Digest::CRC32.file('test.rb').digest!.to_i
#=> 314435800
crc32 == digest
#=> false

crc32 = File.open('test.rb', "rb") { |f| Zlib.crc32 f.read }
#=> 314435800
digest = Digest::CRC32.file('test.rb').digest!.to_i
#=> 314435800
crc32 == digest
#=> true

以上内容适用于所有平台和所有红宝石..据我所知.. 但这不是你问的..

我很确定上述示例中的 hexdigest 和 digest 方法可以正常工作..

dig_file = Digest::CRC32.file('test.rb')

test1 = dig_file.hexdigest
#=> "333134343335383030"

test2 = dig_file.digest
#=> "314435800"

def hexdigest_to_digest(h)
  h.unpack('a2'*(h.size/2)).collect {|i| i.hex.chr }.join
end

test3 = hexdigest_to_digest(test1)
#=> "314435800"

所以我猜要么 .to_i.to_s(16) 正在抛出您的预期结果,或者您的预期结果可能是错误的?不确定,但一切顺利

【讨论】:

  • 你在那儿做事;我认为答案与此相反:从摘要到十六进制摘要。我之前尝试过使用unpack 来强制使用base 16,但我真的不知道我在做什么。我还是不明白。
  • digest 输出“正确”校验和,因为它只返回 finish 方法返回的内容。实际上,它应该返回一个适合Digest.hexencode 的二进制字符串,它应该将字节编码为十六进制。所以,是的,看来我的两种方法都坏了。 :)
【解决方案3】:

它工作得很好,确保始终使用网络字节顺序,如下所示:

def finish; [@crc32].pack('N'); end

【讨论】:

    猜你喜欢
    • 2015-03-18
    • 2015-03-19
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多