2012-04-25 10 views
13

OpenSSL kütüphanesini kullanarak C yazıyorum.C'deki büyük bir dosyanın MD5 karması nasıl hesaplanır?

Büyük bir dosyanın karma değerini md5 kullanarak nasıl hesaplayabilirim?

Bildiğim kadarıyla, RAM'e char dizisi olarak bir bütün dosya yüklemem ve karma işlevini çağırmam gerekiyor. Ancak dosya 4Gb uzunsa ne olur? Kötü bir fikir gibi geliyor.

SOLVED: askovpen sayesinde hata buldum. Ben

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

kullandım değil

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

Bunun gerekliliğini merak ediyorum. Eğer iplik güvenli değilse kötü bir fikir olabilir, çünkü programı uzun bir süre boyunca engelleyebilir ve P.O. – crockpotveggies

+5

Bir dosyanın şifrelenmesi, MD5 gibi bir karma işleviyle aynı şekilde ele alınmaz. Gerçekten hash mı demek istiyorsunuz yoksa dosyayı şifrelemek mi istiyorsunuz? – Oleksi

+7

MD5, akışa dayalıdır. 4GB’nın tamamını bir kerede belleğe yüklemeniz gerekmez - parçaları yığınlarda okursunuz. –

cevap

28

örnek

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

sonucu:

$ md5sum file.c 
25a904b0e512ee546b3f47574703d9fc file.c 
$ ./file 
25a904b0e512ee546b3f47574703d9fc file.c 
+0

may imzasız karakter verisi [1024]; süre (! (Bayt = fread (veriler, 1, 1024, infile)) = 0) işaretsiz bayt veri olabilir [4096]; süre ((bayt = fread (veri, 1, 4096, infile))! = 0) ? – user1031143

3

tek seferde bellekte tüm dosya yüklemek gerekmez. Karma üretmek için parçaları MD5_Init(), MD5_Update() and MD5_Final() işlevleriyle birlikte kullanabilirsiniz. Eğer "atomik" bir işlem yapmaktan endişe ediyorsanız, işlem sırasında başkasının değiştirmesini önlemek için dosyayı kilitlemek gerekebilir.

6

İlk olarak, MD5 bir karma algoritmadır. Hiçbir şeyi şifrelemez.

Neyse, dosyayı istediğiniz boyuttaki parçalar halinde okuyabilirsiniz. Bir kez MD5_Init numaralı telefonu arayın, ardından dosyadan okuduğunuz her bir veri ile birlikte MD5_Update numaralı telefonu arayın. İşiniz bittiğinde sonuca ulaşmak için MD5_Final numaralı telefonu arayın.

+0

Bunu denedim.Dosyayı 16 baytlık bloklara böldüm ve MD5_Update'e ilettim, ancak karma yanlıştı. – user1256821

+1

Yani karma yanlış olmasına yol açan kodda hata düzeltmek. (Ayrıca, 16 bayt blokları yavaş olacaktır Sen çok daha iyi kira 64KB bloklarını kullanarak yapardım..) –

1

üst cevabın doğru olduğunu, ancak bir şey söz etmedi: karma değeri her tampon için farklı olacaktır boyut kullanılır. Değer, kareler boyunca tutarlı olacaktır, bu nedenle aynı arabellek boyutu her seferinde aynı karmayı üretecektir, ancak bu karışma daha sonra aynı verinin bir karması ile karşılaştırılacaksa, her aramayla aynı tampon boyutu kullanılmalıdır. Eğer sizin doğru kod fonksiyonları sindirmek emin olun ve çevrimiçi karma web siteleri ile karma karşılaştırmak için çevrimiçi gitmek isterseniz ek olarak

, onlar Bu da ilginç bir düşünce getiriyor 1 bir tampon uzunluğu kullanmak görünür: Bu büyük bir dosya hash için 1 bir tampon uzunluğu kullanmak için mükemmel kabul edilebilir, sadece daha uzun sürecek (duh).

Başparmak kuralı yalnızca dahili kullanım için ise, daha sonra büyük bir dosya için arabellek uzunluğunu ayarlayabilirim, ancak diğer sistemlerle iyi oynamak zorundaysa, arabellek uzunluğunu 1 olarak ayarlayın ve anlaşma yapın. zaman sonucu ile.

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