web-dev-qa-db-fra.com

Comment calculer le hachage MD5 d'un gros fichier en C?

J'écris en C en utilisant la bibliothèque OpenSSL.

Comment puis-je calculer le hachage d'un gros fichier en utilisant md5?

Comme je le sais, je dois charger un fichier entier dans RAM en tant que tableau de caractères, puis appeler la fonction de hachage. Mais que se passe-t-il si le fichier fait environ 4 Go de long? Cela semble une mauvaise idée.

[~ # ~] résolu [~ # ~] : Merci à askovpen , j'ai trouvé mon bogue. J'ai utilisé

while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5_Update (&mdContext, data, 1024);

ne pas

while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5_Update (&mdContext, data, bytes);
16
user1256821

exemple

gcc -g -Wall -o file file.c -lssl -lcrypto

#include <stdio.h>
#include <openssl/md5.h>

int main()
{
    unsigned char c[MD5_DIGEST_LENGTH];
    char *filename="file.c";
    int i;
    FILE *inFile = fopen (filename, "rb");
    MD5_CTX mdContext;
    int bytes;
    unsigned char data[1024];

    if (inFile == NULL) {
        printf ("%s can't be opened.\n", filename);
        return 0;
    }

    MD5_Init (&mdContext);
    while ((bytes = fread (data, 1, 1024, inFile)) != 0)
        MD5_Update (&mdContext, data, bytes);
    MD5_Final (c,&mdContext);
    for(i = 0; i < MD5_DIGEST_LENGTH; i++) printf("%02x", c[i]);
    printf (" %s\n", filename);
    fclose (inFile);
    return 0;
}

résultat:

$ md5sum file.c
25a904b0e512ee546b3f47574703d9fc  file.c
$ ./file
25a904b0e512ee546b3f47574703d9fc file.c
34
askovpen

Tout d'abord, MD5 est un algorithme de hachage. Il ne crypte rien.

Quoi qu'il en soit, vous pouvez lire le fichier en morceaux de la taille que vous souhaitez. Appelez MD5_Init une fois, puis appelez MD5_Update avec chaque bloc de données que vous lisez dans le fichier. Lorsque vous avez terminé, appelez MD5_Final pour obtenir le résultat.

6
David Schwartz

Vous n'avez pas besoin de charger le fichier entier en mémoire à la fois. Vous pouvez utiliser les fonctions MD5_Init (), MD5_Update () et MD5_Final () pour le traiter en morceaux pour produire le hachage. Si vous craignez d'en faire une opération "atomique", il peut être nécessaire de verrouiller le fichier pour empêcher quelqu'un d'autre de le modifier pendant l'opération.

4
Mark Wilkins

La première réponse est correcte, mais n'a pas mentionné quelque chose: la valeur du hachage sera différente pour chaque taille de tampon utilisée. La valeur sera cohérente à travers les hachages, donc la même taille de tampon produira le même hachage à chaque fois, cependant si ce hachage sera comparé à un hachage des mêmes données à un moment ultérieur, la même taille de tampon doit être utilisée pour chaque appel.

De plus, si vous voulez vous assurer que votre code de digestion fonctionne correctement et aller en ligne pour comparer votre hachage avec les sites de hachage en ligne, il semble qu'ils utilisent une longueur de tampon de 1. Cela amène également une pensée intéressante: il est parfaitement acceptable pour utilisez une longueur de tampon de 1 pour hacher un gros fichier, cela prendra juste plus de temps (duh).

Donc, ma règle générale est que si c'est uniquement pour un usage interne, je peux définir la longueur du tampon en conséquence pour un fichier volumineux, mais s'il doit jouer Nice avec d'autres systèmes, puis définir la longueur du tampon à 1 et gérer la conséquence de temps .

int hashTargetFile(FILE* fp, unsigned char** md_value, int *md_len) {

    #define FILE_BUFFER_LENGTH 1

    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    int diglen; //digest length
    int arrlen = sizeof(char)*EVP_MAX_MD_SIZE + 1;
    int arrlen2 = sizeof(char)*FILE_BUFFER_LENGTH + 1;
    unsigned char *digest_value = (char*)malloc(arrlen);
    char *data = (char*)malloc(arrlen2);
    size_t bytes; //# of bytes read from file

    mdctx = EVP_MD_CTX_new();
    md = EVP_sha512();

    if (!mdctx) {
        fprintf(stderr, "Error while creating digest context.\n");
        return 0;
    }

    if (!EVP_DigestInit_ex(mdctx, md, NULL)) {
        fprintf(stderr, "Error while initializing digest context.\n");
        return 0;
    }

    while (bytes = fread(data, 1, FILE_BUFFER_LENGTH, fp) != 0) {
        if (!EVP_DigestUpdate(mdctx, data, bytes)) {
            fprintf(stderr, "Error while digesting file.\n");
            return 0;
        }
    }

    if (!EVP_DigestFinal_ex(mdctx, digest_value, &diglen)) {
        fprintf(stderr, "Error while finalizing digest.\n");
        return 0;
    }

    *md_value = digest_value;
    *md_len = diglen;

    EVP_MD_CTX_free(mdctx);

    return 1;
}
1
MDMoore313