2010-08-12 5 views
3

J'essaie d'obtenir un sha-1 pour un certain nombre de fichiers. Ce que je fais actuellement est le cycle des fichiers dans un chemin donné, ouvrir et lire chaque fichier séparément et charger le contenu dans un tampon, puis l'envoyer à la fonction SHA de openssl pour obtenir le hachage. Le code ressemble à ceci:Obtenir correctement sha-1 pour les fichiers en utilisant openssl

void ReadHashFile(LPCTSTR name) 
{ 
FILE * pFile; 
long lSize; 
char * buffer; 
size_t result; 

pFile = _tfopen (name , L"rb"); 
if (pFile==NULL) {fputs ("File error",stderr); return;} 

// obtain file size: 
fseek (pFile , 0 , SEEK_END); 
lSize = ftell (pFile); 
rewind (pFile); 

if(lSize == -1){fputs ("Read Error",stderr);return;} 

// allocate memory to contain the whole file: 
buffer = (char*) malloc (sizeof(char)*lSize); 
if (buffer == NULL) {fputs ("Memory error",stderr); return;} 

// copy the file into the buffer: 
result = fread (buffer,1,lSize,pFile); 
if (result != lSize) {fputs ("Reading error",stderr); return;} 

/* the whole file is now loaded in the memory buffer. */ 

// terminate 
fclose (pFile); 

//Do what ever with buffer 
unsigned char ibuf[] = "compute sha1"; 
unsigned char obuf[20]; 

SHA1((const unsigned char*)buffer, strlen((const char*)buffer), obuf); 
fwprintf(stderr, L"file %s\n", name); 
int i; 
for (i = 0; i < 20; i++) { 
    printf("%02x ", obuf[i]); 
} 
printf("\n"); 


free(buffer); 
} 

Certains fichiers semblent être illisibles, certains me donnent une taille -1 autres que je ne peux que lire les 2-3 premiers octets qui donne beaucoup de fichiers même sha même si ils sont différents.

J'apprécierais si quelqu'un peut m'aider avec ceci ou si n'importe qui a l'expérience dans le hachage de dossier. Oh, et s'il existe un moyen d'obtenir le fichier sha1 d'un fichier sans avoir à charger le fichier entier en mémoire en premier, je veux dire en considérant les fichiers volumineux, cette solution ne marchera pas.

Cordialement

Répondre

14

Si vous avez du mal à lire le contenu du fichier, avant d'invoquer le code de fonction de hachage, alors votre problème est pas lié à hachant. Vous devez utiliser la fonction standard fopen() plutôt que _tfopen(). En C, les choses qui commencent par un caractère de soulignement sont souvent mieux évitées. D'autant plus que _tfopen() semble correspondre à fopen() ou à _wfopen() spécifique à Windows selon que le "support unicode" est activé. Alternativement, dans une application purement Windows, vous pouvez compter sur les fonctions Win32 telles que CreateFile().

Lire tout le fichier en mémoire puis le hacher est brut. Il échouera à traiter les fichiers qui sont plus grands que la RAM disponible, par exemple. De plus, pour connaître la taille du fichier, il faut chercher, ce qui n'est pas fiable (il peut y avoir des pseudo-fichiers qui sont en fait des tuyaux dans un processus de génération de données pour lequel la recherche n'est pas possible). Les fonctions de hachage peuvent traiter les données par morceaux; vous devez utiliser un petit tampon (8 Ko est la taille traditionnelle) et utiliser les fonctions SHA1_Init(), SHA1_Update() et SHA1_Final().

fread() ne lit pas nécessairement autant de données que vous avez demandé. Et ce n'est pas une erreur.

Lorsque vous appelez SHA1(), vous utilisez strlen() sur votre tampon, ce qui est faux. strlen() renvoie la longueur d'une chaîne de caractères ; en termes simples, le nombre d'octets jusqu'à l'octet suivant de valeur zéro. Beaucoup de fichiers contiennent des octets de valeur 0. Et si le fichier ne l'est pas, il n'y a aucune garantie que votre tampon contienne un octet de valeur 0, de sorte que l'appel à strlen() peut finir par lire la mémoire en dehors du tampon alloué (mauvais). Puisque vous avez pris la peine d'obtenir la longueur du fichier et d'allouer un tampon de cette taille, vous devriez au moins utiliser cette longueur au lieu d'essayer de la recalculer avec une fonction qui ne le fait pas.

Pour résumer: votre code doit ressembler à ça (non testé):

/* 
* Hash a file, which name is given. Hash output is written out in 
* buffer "out[]". The hash output consists in exactly 20 bytes. 
* On success, 0 is returned; on error, returned value is -1 and 
* out[] is unaltered. 
*/ 
int 
do_sha1_file(char *name, unsigned char *out) 
{ 
    FILE *f; 
    unsigned char buf[8192]; 
    SHA_CTX sc; 
    int err; 

    f = fopen(name, "rb"); 
    if (f == NULL) { 
     /* do something smart here: the file could not be opened */ 
     return -1; 
    } 
    SHA1_Init(&sc); 
    for (;;) { 
     size_t len; 

     len = fread(buf, 1, sizeof buf, f); 
     if (len == 0) 
      break; 
     SHA1_Update(&sc, buf, len); 
    } 
    err = ferror(f); 
    fclose(f); 
    if (err) { 
     /* some I/O error was encountered; report the error */ 
     return -1; 
    } 
    SHA1_Final(out, &sc); 
    return 0; 
} 

Et ne pas oublier d'inclure les en-têtes de fichiers pertinents! (<stdio.h> et sha.h de OpenSSL)

+0

+1 pour l'explication analytique. –

Questions connexes