Вопрос по md5, c, hash – Как рассчитать MD5 хэш большого файла в C?

14

Я пишу на C, используя библиотеку OpenSSL.

Как я могу вычислить хэш большого файла, используя md5?

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

SOLVED: БлагодаряaskovpenЯ нашел свою ошибку. Я использовал

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

не

<code>while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5_Update (&mdContext, data, bytes);
</code>
MD5 является потоковым. Вам не нужно загружать все 4 ГБ в память одновременно - вы читаете их порциями. Charles Salvia
Шифрование файла - это не то же самое, что хеширование с помощью хэш-функции, такой как MD5. Вы действительно имеете в виду хэш или хотите зашифровать файл? Oleksi
Мне интересно знать, зачем это нужно? Конечно, это может быть плохой идеей, если она не является поточно-ориентированной, поскольку может блокировать программу на длительный период и P.O. Пользователь crockpotveggies
Извините, конечно, я имею в виду хеширование файла, а не шифрование. user1256821

Ваш Ответ

4   ответа
6

MD5 - это алгоритм хеширования. Это ничего не зашифровывает.

В любом случае, вы можете прочитать файл кусками любого размера, который вам нравится. ВызовMD5_Init один раз, затем позвонитеMD5_Update с каждой порцией данных, которые вы читаете из файла. Когда вы закончите, позвонитеMD5_Final чтобы получить результат.

Так что исправьте ошибку в вашем коде, из-за которой хеш был неверным. (Кроме того, 16-байтовые блоки будут работать медленнее. Вы бы намного лучше использовали блоки размером 64 КБ при аренде.)
Я попробовал это. Я разделил файл на 16-байтовые блоки и передал их MD5_Update, но хеш был неверным. user1256821
1

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

Кроме того, если вы хотите убедиться, что ваш дайджест-код работает правильно, и выходите в интернет, чтобы сравнить ваш хэш с веб-сайтами онлайн-хэширования, похоже, они используют длину буфера 1. Это также вызывает интересную мысль: это вполне приемлемо для используйте длину буфера 1 для хэширования большого файла, это займет больше времени (duh).

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

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;
}
3

ь функцииMD5_Init (), MD5_Update () и MD5_Final () обрабатывать его кусками, чтобы получить хеш. Если вы беспокоитесь о том, чтобы сделать его "атомным" операции, может потребоваться заблокировать файл, чтобы предотвратить его изменение во время операции.

30

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;
}

результат:

$ md5sum file.c
25a904b0e512ee546b3f47574703d9fc  file.c
$ ./file
25a904b0e512ee546b3f47574703d9fc file.c
может содержать данные без знака [1024]; while ((bytes = fread (data, 1, 1024, inFile))! = 0) быть данными без знака [4096]; while ((bytes = fread (data, 1, 4096, inFile))! = 0)?

Похожие вопросы