2012-04-25 26 views
13

私はOpenSSLライブラリを使ってC言語で書いています。Cで大きなファイルのMD5ハッシュを計算するには?

md5を使用して大きなファイルのハッシュを計算するにはどうすればよいですか?

私が知っているように、ファイル全体をchar配列としてRAMにロードしてから、ハッシュ関数を呼び出す必要があります。しかし、ファイルの長さが約4Gbの場合はどうなりますか?悪い考えのように聞こえる。

SOLVEDaskovpenのおかげで、私はバグを発見しました。私は、あなたが一度にメモリ内のファイル全体をロードする必要はありません

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); 
+0

私はそれの必要性を知りたいのですか?長期間プログラムをブロックする可能性があるため、スレッドセーフではない場合は、確かに悪い考えかもしれません。ユーザー – crockpotveggies

+5

ファイルを暗号化することは、MD5のようなハッシュ関数を使用してハッシュすることと同じではありません。あなたは本当にハッシュを意味しますか、またはファイルを暗号化しますか? – Oleksi

+7

MD5はストリームベースです。一度に4GB全体をメモリにロードする必要はありません。チャンクで読み込んでください。 –

答えて

28

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 
+0

may unsigned char data [1024]; while((bytes = fread(data、1、1024、inFile))!= 0) be unsigned char data [4096]; while((bytes = fread(data、1、4096、inFile))!= 0) ? – user1031143

3

を使用しました。 MD5_Init(), MD5_Update() and MD5_Final()関数を使用して、チャンクで処理してハッシュを生成することができます。それを「アトミック」操作にすることを心配している場合は、操作中に他の誰かがファイルを変更しないようにファイルをロックする必要があります。

6

まず、MD5はハッシュアルゴリズムです。何も暗号化しません。

とにかく、好きなサイズのチャンクでファイルを読むことができます。 MD5_Initを一度呼び出してから、ファイルから読み取ったデータの各塊でMD5_Updateを呼び出してください。完了したら、MD5_Finalに電話して結果を入手してください。

+0

私はそれを試みました。私はファイルを16バイトのブロックに分割してMD5_Updateに渡しましたが、ハッシュは間違っていました。 – user1256821

+1

ハッシュが間違っている原因となったコードのバグを修正してください。 (また、16バイトのブロックは遅くなります。リース時には64KBのブロックを使用する方がずっと良いでしょう) –

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; 
} 
関連する問題