2010-08-18 10 views
4

J'utilise deux bibliothèques différentes pour générer un hachage SHA-1 à utiliser dans la validation de fichier - une ancienne version de la bibliothèque Crypto++ et la classe Digest :: SHA1 implémentée par Ruby. Alors que j'ai vu d'autres instances de hachage incompatibles causées par des différences de codage, les deux bibliothèques produisent des hachages presque identiques identiques.Pourquoi Crypto ++ et Ruby génèrent des hachages SHA-1 légèrement différents?

Par exemple, le passage d'un fichier à travers chaque processus produit les résultats suivants:

Crypto ++ 01c15e4f46d8181b984fa2a2c740f8f67130acac

Ruby: eac15e4f46d8181b984fa2a2c740f8f67130acac

Comme vous pouvez le voir, seuls les deux premiers caractères du hachage chaîne sont différentes et ce comportement se répète sur plusieurs fichiers. J'ai jeté un coup d'œil sur le code source de chaque implémentation, et la seule différence que j'ai trouvée à première vue était dans l'hex de données utilisé pour le hachage 160 bits. Je n'ai aucune idée de la façon dont cet hexagone est utilisé dans l'algorithme, et j'ai pensé qu'il serait probablement plus rapide pour moi de poser la question au cas où quelqu'un aurait déjà rencontré ce problème.

J'ai inclus les données des bibliothèques respectives ci-dessous. J'ai également inclus les valeurs d'OpenSSL, car chacune des trois bibliothèques avait des valeurs légèrement différentes.

Crypto ++:

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

Ruby:

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 

Soit dit en passant, voici le code utilisé pour générer le hachage en Ruby. Je n'ai pas accès au code source de l'implémentation de 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 
+2

Toutes les valeurs sont identiques. –

+0

Ces ensembles de nombres sont exactement les mêmes. Je ne sais pas d'où vient la différence, mais ce ne sont pas ces ensembles de nombres. –

+0

Ouais, j'avais exclu essentiellement que cela ait quelque chose à voir avec la différence. Considérant que les trois bibliothèques sont largement utilisées, il ne serait pas logique pour chacune de générer un hachage différent basé sur des différences explicites dans les algorithmes. C'est principalement pourquoi je suis perdu. –

Répondre

2

Je suppose que vous êtes à côté d'un octet dans l'impression des hachages SHA-1. Pouvons-nous voir le code qui les imprime? Sinon, voici quelques diagnostics potentiellement utiles:

  1. Faire un fichier très court (disons, un mot), et mettre son contenu en tant que chaîne hexagonale à http://www.fileformat.info/tool/hash.htm. Cependant, vous auriez besoin de connaître exactement le contenu hexadécimal du fichier. Vous pouvez utiliser xxd sous Unix, mais vous devrez faire attention aux problèmes d'endianness. Je ne suis pas sûr de savoir comment le faire sur d'autres systèmes d'exploitation.

  2. L'exécution simultanée du même fichier via la même implémentation SHA-1 imprime-t-elle toujours la même valeur dans ce premier octet? Si oui, cette valeur change-t-elle lorsque vous changez de fichier?

2

Cela n'a pas beaucoup de sens. Si quelque chose n'allait pas avec l'implémentation de SHA1, comme avec ces nombres, cela produirait probablement des hachages complètement différents des hachages SHA1 réels, plutôt qu'un seul octet désactivé. Même s'il y avait un problème avec votre boucle de lecture de fichier, que cela ferait tomber une nouvelle ligne ou quelque chose, vous obtiendriez toujours un hachage complètement différent en changeant un octet dans le flux, ce ne serait pas un octet du vrai hachage SHA1 .

Si j'utilise votre méthode dans le programme suivant, j'obtiens les résultats corrects.

#!/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]) 

Et sa sortie comparée à celle d'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 

Donc, il n'y a rien de mal avec votre méthode de hachage. Quelque chose ne va pas entre sa valeur de retour et son impression.