2011-12-21 40 views
6

在我的代码中,我需要使用各种算法(包括CRC32)来散列文件。由于我还在Digest系列中使用其他加密散列函数,因此我认为为它们全部保持一致的界面会很好。Digest :: CRC32与Zlib

为了记录,我找到了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返回的整数来实现这个功能。

+0

什么Ruby平台是你的工作吗? – 2potatocakes 2011-12-21 21:33:15

+0

@ 2potatocakes,C Ruby 1.9.3。 – 2011-12-21 22:00:02

回答

6

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

你想要的东西像

[@crc32].pack('V') 

把这一整成表示该字节。请仔细阅读pack和它的各种格式说明符 - 有很多方法可以打包一个整数,具体取决于字节是否应该以native endian-ness,big-endian,little-endian等形式表示出来,以便找出哪些一个符合您的需求

+1

我用[@ crc32] .pack('N')来获取我的Digest :: CRC32.file(文件名)版本以按预期工作。 – 2012-09-17 00:35:26

3

很抱歉,这并没有真正回答你的问题,但它可能会帮助..

首先,读入文件时,请确保您通过“RB”参数。我可以看到你没有和窗户,但如果碰巧你的代码并最终得到运行在Windows机器上的代码将无法正常工作一样的,尤其是阅读红宝石文件时例:

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和消化在上面的例子中方法的工作,因为他们应该,虽然..

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" 

所以我猜ei那么.to_i.to_s(16)会抛弃您的预期结果,或者您的预期结果可能有误?不知道,但都是最好的

+0

你正在那里;我认为答案与此相反:消化为十六进制。我之前尝试过使用'unpack'来尝试强制使用base 16,但实际上我完全不知道我在做什么。我仍然不明白。 – 2011-12-21 23:33:49

+0

'digest'输出“正确的”校验和,因为它只返回'finish'方法返回的内容。实际上,它应该返回一个适合于'Digest.hexencode'的二进制字符串,它应该以十六进制对字节进行编码。所以是的,我的方法似乎都被打破了。 :) – 2011-12-21 23:40:16

3

它工作得很好,一定要始终使用网络字节顺序是这样的:

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