17

我正在使用 OpenSSL 库用 C 语言编写。

如何使用 md5 计算大文件的哈希?

据我所知,我需要将整个文件作为 char 数组加载到 RAM,然后调用哈希函数。但是如果文件大约 4Gb 长呢?听起来是个坏主意。

解决:感谢askovpen,我发现了我的错误。我用过

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

不是

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

4 回答 4

40

例子

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
于 2012-04-25T22:48:16.670 回答
6

首先,MD5 是一种散列算法。它不加密任何东西。

无论如何,您可以以任意大小的块读取文件。调用MD5_Init一次,然后使用从文件中读取的每个数据块调用MD5_Update 。完成后,调用MD5_Final获取结果。

于 2012-04-25T22:22:09.427 回答
4

您不必一次将整个文件加载到内存中。您可以使用函数 MD5_Init()、MD5_Update() 和 MD5_Final()将其分块处理以生成哈希。如果您担心使其成为“原子”操作,则可能需要锁定文件以防止其他人在操作期间对其进行更改。

于 2012-04-25T22:21:52.777 回答
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;
}
于 2016-09-12T13:34:51.383 回答