2011-12-21 30 views
6

Trong mã của tôi, tôi cần tệp băm bằng nhiều thuật toán, bao gồm CRC32. Vì tôi cũng đang sử dụng các hàm băm mật mã khác trong gia đình Digest, tôi nghĩ sẽ tốt hơn nếu duy trì giao diện nhất quán cho tất cả chúng.Thông báo :: CRC32 với Zlib

Để ghi lại, tôi đã tìm thấy digest-crc, một viên đá quý thực hiện chính xác những gì tôi muốn. Vấn đề là, Zlib là một phần của thư viện chuẩn và có triển khai thực hiện CRC32 mà tôi muốn sử dụng lại. Ngoài ra, nó được viết bằng C vì vậy nó sẽ cung cấp hiệu suất cao hơn liên quan đến digest-crc, đó là một thực hiện ruby ​​tinh khiết.

Thực hiện Digest::CRC32 thực sự trông khá đơn giản lúc đầu:

%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 

Tất cả mọi thứ có vẻ đúng:

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

Thật không may, không phải tất cả mọi thứ hoạt động:

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

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

hexdigest cơ bản trả Digest.hexencode(digest), 012.330.. Tôi không chắc chắn làm thế nào mà chức năng hoạt động, vì vậy tôi đã tự hỏi nếu nó có thể đạt được điều này chỉ với số nguyên trở về từ Zlib.crc32.

+0

gì nền tảng ruby ​​được bạn làm việc trên? – 2potatocakes

+0

@ 2potatocakes, C Ruby 1.9.3. –

Trả lời

6

Thông báo mong đợi thông báo trả lại các byte thô tạo nên tổng kiểm tra, ví dụ: trong trường hợp crc32 là 4 byte trang điểm với số nguyên 32 bit. Tuy nhiên, bạn thay vào đó trả về một chuỗi có chứa biểu diễn cơ sở 10 của số nguyên đó.

Bạn muốn một cái gì đó giống như

[@crc32].pack('V') 

để biến số nguyên đó vào byte đại diện đó.Làm đi và đọc lên trên gói và định dạng khác nhau của nó specifiers - có rất nhiều cách để đóng gói một số nguyên tùy thuộc vào việc các byte nên được trình bày trong native endian-ness, big-endian, little-endian vv vì vậy bạn nên tìm ra một phù hợp với nhu cầu của bạn

+1

Tôi đã sử dụng [@ crc32] .pack ('N') để lấy phiên bản Digest :: CRC32.file (tên tệp) của tôi để hoạt động như mong đợi. –

3

Xin lỗi này không thực sự trả lời câu hỏi của bạn, nhưng nó có thể giúp ..

Thứ nhất, khi đọc trong một tập tin, hãy chắc chắn bạn vượt qua "rb" tham số. Tôi có thể thấy bạn không phải trên cửa sổ nhưng nếu tình cờ mã của bạn không kết thúc việc chạy trên một máy cửa sổ mã của bạn sẽ không hoạt động như nhau, đặc biệt là khi đọc file ruby ​​trong Ví dụ:.

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 

Các ở trên sẽ hoạt động trên tất cả các nền tảng và tất cả các hồng ngọc .. mà tôi biết về .. Nhưng đó không phải là những gì bạn đã hỏi ..

Tôi chắc chắn rằng các phương pháp hexdigest và digest trong ví dụ trên của bạn đang hoạt động như chúng nên ..

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" 

Vì vậy, tôi đoán ei có .to_i.to_s (16) là ném ra kết quả mong đợi của bạn hoặc kết quả dự kiến ​​của bạn có thể có thể sai? Không chắc chắn, nhưng tất cả các tốt nhất

+0

Bạn đang lên một cái gì đó ở đó; Tôi nghĩ rằng câu trả lời là ngược lại của điều đó: tiêu hóa để hexdigest. Tôi đã thử một cái gì đó với 'giải nén 'trước khi cố gắng để buộc cơ sở 16 nhưng thực sự tôi không có ý tưởng những gì tôi đã làm. Tôi vẫn không hiểu. –

+0

'digest' đưa ra kết quả kiểm tra" chính xác "vì nó chỉ trả về phương thức' kết thúc' trả về. Trong thực tế, nó sẽ trả về một chuỗi nhị phân phù hợp với 'Digest.hexencode', nên mã hóa các byte theo hệ thập lục phân. Vâng, có vẻ như cả hai phương pháp của tôi đều bị hỏng. :) –

3

Nó hoạt động tốt, đảm bảo luôn luôn sử dụng thứ tự byte mạng, như thế này:

def finish; [@crc32].pack('N'); end 
Các vấn đề liên quan