2009-08-02 10 views
60

Mam ścieżkę pliku. Jak mogę uzyskać skrót MD5 tego?Jak uzyskać skrót MD5 pliku w C++?

+1

@silky - nie bardzo pomocne komentarz :) ..implementing MD5 od zera to naprawdę dobry sposób, aby uzyskać ekspozycję na algorytmów kryptograficznych i protokołów, a ponieważ jest to „znany” możesz natychmiast zweryfikować, czy twój kod jest prawidłowy w porównaniu z 'md5sum' lub podobnym – warren

+1

@Noon Silk Myślę, że w tym celu należy utworzyć unikalny podpis dla pliku md5, który powinien być odpowiedni. – bobobobo

+0

@ Silk Silk, z długimi rekurencyjnymi sprawdzeniami sha1 byłby zbyt wolny! – Will03uk

Odpowiedz

20

Możesz sam zaimplementować algorytm MD5 (przykłady są dostępne w całym Internecie) lub możesz połączyć się z bibliotekami OpenSSL i użyć funkcji skrótu OpenSSL. oto przykład, aby uzyskać MD5 z tablicy bajtów:

#include <openssl/md5.h> 
QByteArray AESWrapper::md5 (const QByteArray& data) { 
    unsigned char * tmp_hash; 
    tmp_hash = MD5((const unsigned char*)data.constData(), data.length(), NULL); 
    return QByteArray((const char*)tmp_hash, MD5_DIGEST_LENGTH); 
} 
+20

przy używaniu Qt (jak to robisz) wolałbym raczej zwracać QCryptographicHash :: hash (dane, QCryptographicHash :: Md5); 'jako ciało funkcji ... – akira

+5

Jeśli chodzi o rzeczy związane z bezpieczeństwem, nigdy nie piszcie własnej implementacji, jeśli rzeczy znajdujące się w sieci wystarczą. I każda możliwa implementacja MD4/5 jest już dostępna, więc naprawdę nie ma powodu, aby pisać własne. –

+1

@ MahmoudAl-Qudsi Um, tak jest, mój profesor nie pozwala mi na plagiat kodu. –

40

Oto prosta realizacja polecenia md5sum który oblicza i wyświetla MD5 pliku określonego w linii poleceń. Musi być połączony z biblioteką OpenSSL (gcc md5.c -o md5 -lssl) do pracy. To czysty C, ale powinieneś być w stanie łatwo dostosować go do swojej aplikacji C++.

#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/mman.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <openssl/md5.h> 

unsigned char result[MD5_DIGEST_LENGTH]; 

// Print the MD5 sum as hex-digits. 
void print_md5_sum(unsigned char* md) { 
    int i; 
    for(i=0; i <MD5_DIGEST_LENGTH; i++) { 
      printf("%02x",md[i]); 
    } 
} 

// Get the size of the file by its file descriptor 
unsigned long get_size_by_fd(int fd) { 
    struct stat statbuf; 
    if(fstat(fd, &statbuf) < 0) exit(-1); 
    return statbuf.st_size; 
} 

int main(int argc, char *argv[]) { 
    int file_descript; 
    unsigned long file_size; 
    char* file_buffer; 

    if(argc != 2) { 
      printf("Must specify the file\n"); 
      exit(-1); 
    } 
    printf("using file:\t%s\n", argv[1]); 

    file_descript = open(argv[1], O_RDONLY); 
    if(file_descript < 0) exit(-1); 

    file_size = get_size_by_fd(file_descript); 
    printf("file size:\t%lu\n", file_size); 

    file_buffer = mmap(0, file_size, PROT_READ, MAP_SHARED, file_descript, 0); 
    MD5((unsigned char*) file_buffer, file_size, result); 
    munmap(file_buffer, file_size); 

    print_md5_sum(result); 
    printf(" %s\n", argv[1]); 

    return 0; 
} 
+1

na platformach 32-bitowych, twój mmap ma ograniczenie co do wielkości pliku, chociaż jest to eleganckie rozwiązanie problemu. Na przykład w 32-bitowych systemach Windows nie można MD5 płyty DVD z tym kodem. –

+0

@ChrisKaminski można przesuwać okno 4GB pliku mapowanego w pamięci na 32-bitowej platformie. – expert

+9

Doskonała odpowiedź, pomogło mi to niezmiernie. Jednak nie wywołujesz później munmapy. Nie jest to przeciek pamięci, ponieważ program kończy się natychmiast po tym, ale jeśli jakiś bufon jak ja kopiuje kod i nie umieszcza go w munmapie, dostaniemy przeciek pamięci w naszym programie;) Rozwiązanie: munmap (file_buffer, file_size); –

3

Użyłem Botan do wykonania tej operacji i innych wcześniej. AraK wskazał Crypto ++. Sądzę, że obie biblioteki są całkowicie poprawne. Teraz to zależy od Ciebie :-).

1

Korzystanie Crypto ++, można wykonać następujące czynności:

#include <sha.h> 
#include <iostream> 

SHA256 sha; 
while (!f.eof()) { 
    char buff[4096]; 
    int numchars = f.read(...); 
    sha.Update(buff, numchars); 
} 
char hash[size]; 
sha.Final(hash); 
cout << hash <<endl; 

Mam potrzebę czegoś bardzo podobnego, bo nie mogę czytać w plikach wielogigabajtowych prostu obliczyć hash. Teoretycznie mógłbym je zmapować, ale muszę obsługiwać 32-bitowe platformy - to wciąż problematyczne dla dużych plików.

+3

-1, md5! = Sha. – Abyx

9
QFile file("bigimage.jpg"); 

if (file.open(QIODevice::ReadOnly)) 
{ 
    QByteArray fileData = file.readAll(); 

    QByteArray hashData = QCryptographicHash::hash(fileData,QCryptographicHash::Md5); // or QCryptographicHash::Sha1 
    qDebug() << hashData.toHex(); // 0e0c2180dfd784dd84423b00af86e2fc 

} 
+6

Nie tak dobre dla plików o rozmiarze GB :) –

4
+0

Powoduje zwrócenie skrótów innych niż inne implementacje MD5. Na przykład hashe opróżnia ciąg do e4c23762ed2823a27e62a64b95c024e7, kiedy powinno być d41d8cd98f00b204e9800998ecf8427e. Jest tam powiązane pytanie: http://stackoverflow.com/q/33989390/2436687 – user31389

7

Dla każdego przekierowanego z "https://stackoverflow.com/questions/4393017/md5-implementation-in-c", ponieważ została niepoprawnie oznaczona jako duplikat.

przykładzie znajduje się tutaj działa:

http://www.zedwood.com/article/cpp-md5-function

Jeśli kompilacji w VC++ 2010, a następnie trzeba będzie zmienić swoje main.cpp do tego:

#include <iostream> //for std::cout 
#include <string.h> //for std::string 
#include "MD5.h" 

using std::cout; using std::endl; 

int main(int argc, char *argv[]) 
{ 
    std::string Temp = md5("The quick brown fox jumps over the lazy dog"); 
    cout << Temp.c_str() << endl; 

    return 0; 
} 

Będziesz musicie nieznacznie zmienić klasę MD5, jeśli macie czytać w tablicy char * zamiast łańcucha, aby odpowiedzieć na pytanie na tej stronie tutaj.

EDIT:

Widocznie modyfikując bibliotekę MD5 nie jest jasne, dobrze rozwiązanie Pełna VC++ 2010 jest tutaj dla wygody zawierać char * 's:

https://github.com/alm4096/MD5-Hash-Example-VS

trochę wyjaśnienie jest tutaj:

#include <iostream> //for std::cout 
#include <string.h> //for std::string 
#include <fstream> 
#include "MD5.h" 

using std::cout; using std::endl; 

int main(int argc, char *argv[]) 
{ 
    //Start opening your file 
    ifstream inBigArrayfile; 
    inBigArrayfile.open ("Data.dat", std::ios::binary | std::ios::in); 

    //Find length of file 
    inBigArrayfile.seekg (0, std::ios::end); 
    long Length = inBigArrayfile.tellg(); 
    inBigArrayfile.seekg (0, std::ios::beg);  

    //read in the data from your file 
    char * InFileData = new char[Length]; 
    inBigArrayfile.read(InFileData,Length); 

    //Calculate MD5 hash 
    std::string Temp = md5(InFileData,Length); 
    cout << Temp.c_str() << endl; 

    //Clean up 
    delete [] InFileData; 

    return 0; 
} 

ja po prostu dodaje się następujące do biblioteki MD5:

MD5.CPP:

MD5::MD5(char * Input, long length) 
{ 
    init(); 
    update(Input, length); 
    finalize(); 
} 

MD5.h:

std::string md5(char * Input, long length); 
+0

To jest ciąg znaków, a nie plik * –

+2

Odpowiedź zmodyfikowana tak, aby zawierała plik – ALM865

+1

niektóre z twoich linków są zepsute – user463035818

1

przebudowa impementation przez @ D'Nabre C++. Nie zapomnij skompilować z -lcrypto na końcu: gcc md5.c -o md5 -lcrypto.

#include <iostream> 
#include <iomanip> 
#include <fstream> 
#include <string> 

#include <openssl/md5.h> 
using namespace std; 

unsigned char result[MD5_DIGEST_LENGTH]; 

// function to print MD5 correctly 
void printMD5(unsigned char* md, long size = MD5_DIGEST_LENGTH) { 
    for (int i=0; i<size; i++) { 
     cout<< hex << setw(2) << setfill('0') << (int) md[i]; 
    } 
} 

int main(int argc, char *argv[]) { 

if(argc != 2) { 
    cout << "Specify the file..." << endl; 
    return 0; 
} 

ifstream::pos_type fileSize; 
char * memBlock; 

ifstream file (argv[1], ios::ate); 

//check if opened 
if (file.is_open()) { cout<< "Using file\t"<< argv[1]<<endl; } 
else { 
    cout<< "Unnable to open\t"<< argv[1]<<endl; 
    return 0; 
} 

//get file size & copy file to memory 
//~ file.seekg(-1,ios::end); // exludes EOF 
fileSize = file.tellg(); 
cout << "File size \t"<< fileSize << endl; 
memBlock = new char[fileSize]; 
file.seekg(0,ios::beg); 
file.read(memBlock, fileSize); 
file.close(); 

//get md5 sum 
MD5((unsigned char*) memBlock, fileSize, result); 

//~ cout << "MD5_DIGEST_LENGTH = "<< MD5_DIGEST_LENGTH << endl; 
printMD5(result); 
cout<<endl; 

return 0; 
} 
3

Musiałem to zrobić właśnie teraz i wymagałem rozwiązania wieloplatformowego, które byłoby odpowiednie dla C++ 11, boost i openssl. Wziąłem D'Nabre's rozwiązanie jako punkt wyjścia i gotowano go na następujący:

#include <openssl/md5.h> 
#include <iomanip> 
#include <sstream> 
#include <boost/iostreams/device/mapped_file.hpp> 

const std::string md5_from_file(const std::string& path) 
{ 
    unsigned char result[MD5_DIGEST_LENGTH]; 
    boost::iostreams::mapped_file_source src(path); 
    MD5((unsigned char*)src.data(), src.size(), result); 

    std::ostringstream sout; 
    sout<<std::hex<<std::setfill('0'); 
    for(auto c: result) sout<<std::setw(2)<<(int)c; 

    return sout.str(); 
} 

Szybki test wykonywalny pokazuje:

#include <iostream> 

int main(int argc, char *argv[]) { 
    if(argc != 2) { 
     std::cerr<<"Must specify the file\n"; 
     exit(-1); 
    } 
    std::cout<<md5_from_file(argv[1])<<" "<<argv[1]<<std::endl; 
    return 0; 
} 

Niektóre łączące Uwagi: Linux: -lcrypto -lboost_iostreams Windows: -DBOOST_ALL_DYN_LINK libeay32.lib ssleay32.lib

+0

dziękuję. if (! exists (boost :: filesystem :: path (path))) { –

0

mają również funkcje MD5_* bardzo przydatne dla dużego pliku

#include <openssl/md5.h> 
#include <fstream> 
....... 

std::ifstream file(filename, std::ifstream::binary); 
MD5_CTX md5Context; 
MD5_Init(&md5Context); 
char buf[1024 * 16]; 
while (file.good()) { 
    file.read(buf, sizeof(buf)); 
    MD5_Update(&md5Context, buf, file.gcount()); 
} 
unsigned char result[MD5_DIGEST_LENGTH]; 
MD5_Final(result, &md5Context); 

Bardzo proste, prawda? Konwersja na łańcuch również bardzo prosta:

#include <sstream> 
#include <iomanip> 
....... 

std::stringstream md5string; 
md5string << std::hex << std::uppercase << std::setfill('0'); 
for (const auto &byte: result) 
    md5string << std::setw(2) << (int)byte; 

return md5string.str();