Дайджест :: CRC32 с Zlib - PullRequest
       16

Дайджест :: CRC32 с Zlib

6 голосов
/ 21 декабря 2011

В моем коде мне нужно хэшировать файлы, используя различные алгоритмы, включая CRC32.Поскольку я также использую другие криптографические хеш-функции в семействе Digest, я подумал, что было бы неплохо поддерживать согласованный интерфейс для них всех.

Для записи я нашел digest-crc, драгоценный камень, который делает именно то, что я хочу.Дело в том, что Zlib является частью стандартной библиотеки и имеет рабочую реализацию CRC32, которую я хотел бы использовать повторно.Кроме того, он написан на C, поэтому должен обеспечивать превосходную производительность по отношению к digest-crc, который является чисто рубиновой реализацией.

Реализация 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), , который работает со значениемДайджест на уровне байтов .Я не уверен, как эта функция работает, поэтому мне было интересно, возможно ли достичь этого только с помощью целого числа, возвращенного из Zlib.crc32.

Ответы [ 3 ]

6 голосов
/ 22 декабря 2011

Дайджест ожидает, что дайджест вернет необработанные байты, составляющие контрольную сумму, то есть в случае crc32 4 байта, которые составляют 32-битное целое число. Однако вместо этого вы возвращаете строку, которая содержит базовое представление 10 этого целого числа.

Вы хотите что-то вроде

[@crc32].pack('V')

чтобы превратить это целое число в байты, которые представляют это. Пойди и прочитай о пакете и его различных спецификаторах формата - есть много способов упаковки целого числа в зависимости от того, должны ли байты быть представлены в собственном порядке с прямым порядком байтов, с прямым порядком байтов, с прямым порядком байтов и т. Д., Так что ты должен выяснить, какие один соответствует вашим потребностям

3 голосов
/ 04 октября 2014

Работает просто отлично, всегда используйте сетевой порядок байтов, например:

def finish; [@crc32].pack('N'); end
3 голосов
/ 22 декабря 2011

Извините, это не совсем ответит на ваш вопрос, но это может помочь ..

Во-первых, при чтении в файле убедитесь, что вы передали параметр "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) отбрасывает ожидаемый результат, или ожидаемый результат может быть неправильным? Не уверен, но всего наилучшего

...