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を 1 回呼び出してから、ファイルから読み取ったデータの各チャンクでMD5_Updateを呼び出します。完了したら、 MD5_Finalを呼び出して結果を取得します。

于 2012-04-25T22:22:09.427 に答える
4

一度にファイル全体をメモリにロードする必要はありません。関数 MD5_Init()、MD5_Update()、MD5_Final()を使用してチャンクで処理し、ハッシュを生成できます。「アトミック」操作にすることに不安がある場合は、ファイルをロックして、操作中に他の人がファイルを変更できないようにする必要がある場合があります。

于 2012-04-25T22:21:52.777 に答える
1

一番上の答えは正しいですが、何も言及していませんでした: ハッシュの値は、使用されるバッファ サイズごとに異なります。値はハッシュ全体で一貫しているため、同じバッファ サイズは毎回同じハッシュを生成しますが、後でこのハッシュを同じデータのハッシュと比較する場合は、呼び出しごとに同じバッファ サイズを使用する必要があります。

さらに、ダイジェスト コードが正しく機能することを確認し、オンラインでハッシュをオンラインのハッシュ Web サイトと比較したい場合、それらはバッファ長 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 に答える