Wie bekomme ich den MD5-Hash einer Datei in C ++? [geschlossen]

74

Ich habe den Dateipfad. Wie kann ich den MD5-Hash davon bekommen?

user145586
quelle
1
@silky - kein wirklich hilfreicher Kommentar :) ..Die Implementierung von MD5 von Grund auf ist ein guter Weg, um sich mit kryptografischen Algorithmen und Protokollen vertraut zu machen. Da es "bekannt" ist, können Sie sofort überprüfen, ob Ihr Code richtig ist md5sumoder ähnlich
warren
1
@Noon Silk Ich denke, um hier eine eindeutige Signatur für eine Datei md5 zu erstellen, sollte dies angemessen sein.
Bobobobo
@Noon Silk, mit langen rekursiven Prüfungen wäre sha1 zu langsam!
Will03uk

Antworten:

48

Hier ist eine einfache Implementierung des md5sumBefehls, der die MD5 der in der Befehlszeile angegebenen Datei berechnet und anzeigt. Es muss mit der OpenSSL-Bibliothek ( gcc md5.c -o md5 -lssl) verknüpft sein , damit es funktioniert. Es ist reines C, aber Sie sollten es leicht genug an Ihre C ++ - Anwendung anpassen können.

#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;
}
D'Nabre
quelle
1
Auf 32-Bit-Plattformen kann Ihre mmap die Größe der Datei einschränken, obwohl dies eine elegante Lösung für das Problem darstellt. Unter 32-Bit-Windows konnten Sie beispielsweise keine DVD mit diesem Code auf MD5 erstellen.
Chris K
@ ChrisKaminski Sie können 4 GB Fenster der Speicherzuordnungsdatei auf 32-Bit-Plattform schieben.
Experte
12
Ausgezeichnete Antwort, es hat mir sehr geholfen. Sie rufen danach jedoch keine Munmap mehr auf. Es ist kein Speicherverlust für Sie, da das Programm unmittelbar danach endet, aber wenn ein Trottel wie ich den Code kopiert und keine Munmap einfügt, erhalten wir einen Speicherverlust in unserem Programm;) Die Lösung: munmap (file_buffer, file_size);
Bob Miller
8
Für mich gcc md5.c -o md5 -lcryptofunktionierte dies anstelle von -lsslUbuntu 14.04
RajaRaviVarma
1
Abhängig von openssl - einer riesigen und knorrigen Bibliothek - scheint mir etwas so Einfaches wie MD5 eine schlechte Idee zu sein.
Timmmm
22

Sie können den MD5-Algorithmus selbst implementieren (Beispiele finden Sie im gesamten Web), oder Sie können eine Verknüpfung mit den OpenSSL-Bibliotheken herstellen und die Digest-Funktionen von OpenSSL verwenden. Hier ist ein Beispiel, um die MD5 eines Byte-Arrays zu erhalten:

#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);
}
OneOfOne
quelle
23
Wenn ich Qt benutze (wie Sie), würde ich es lieber nur return QCryptographicHash::hash(data, QCryptographicHash::Md5);als Hauptteil der Funktion tun ...
Akira
5
Wenn es um sicherheitsrelevante Dinge geht, schreiben Sie niemals Ihre eigene Implementierung, wenn die Dinge im Internet ausreichen. Und jede mögliche Implementierung von MD4 / 5 ist da draußen, also gibt es wirklich keinen Grund, eine eigene zu schreiben.
Mahmoud Al-Qudsi
1
@ MahmoudAl-Qudsi Ähm ja, mein Professor lässt mich keinen Code plagiieren.
b1nary.atr0phy
2
@ MahmoudAl-Qudsi Verwenden Sie niemals MD5, wenn es um sicherheitsrelevante Dinge geht . MD5 ist kein Hash mit Kryptostärke.
uliwitness
1
@uliwitness md5 war nicht meine Idee. Es ist in Ordnung, MD5 als mittelschnellen Nicht-Krypto-Hash zu behandeln, aber ich stimme zu, dass es als Krypto-Hash völlig kaputt ist (und es gibt weitaus bessere Geschwindigkeit und Hashing für Nicht-Krypto-Hashes).
Mahmoud Al-Qudsi
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

}
iyiy
quelle
10
Nicht so gut für Dateien mit einer Größe von GB :)
schnell_now
8

Ich musste dies gerade tun und benötigte eine plattformübergreifende Lösung, die für C ++ 11, Boost und OpenSSL geeignet war. Ich nahm die Lösung von D'Nabre als Ausgangspunkt und brachte sie auf Folgendes:

#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();
}

Eine ausführbare Testdatei zeigt:

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

Einige Verknüpfungshinweise: Linux: -lcrypto -lboost_iostreams Windows:-DBOOST_ALL_DYN_LINK libeay32.lib ssleay32.lib

Benedikt
quelle
Vielen Dank. if (! existiert (boost :: filesystem :: path (path))) {
Abdul Ahad
8

Für alle, die von " /programming/4393017/md5-implementation-in-c " umgeleitet wurden, weil es fälschlicherweise als Duplikat gekennzeichnet wurde.

Das hier gezeigte Beispiel funktioniert:

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

Wenn Sie in VC ++ 2010 kompilieren, müssen Sie seine main.cpp folgendermaßen ändern:

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

Sie müssen die MD5-Klasse geringfügig ändern, wenn Sie ein char * -Array anstelle einer Zeichenfolge einlesen möchten, um die Frage auf dieser Seite hier zu beantworten.

BEARBEITEN:

Anscheinend ist das Ändern der MD5-Bibliothek nicht klar. Nun, eine vollständige VC ++ 2010-Lösung ist für Sie da, um char * 's einzuschließen:

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

Eine kleine Erklärung finden Sie hier:

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

Ich habe der MD5-Bibliothek einfach Folgendes hinzugefügt:

MD5.cpp:

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

MD5.h:

std::string md5(char * Input, long length);
ALM865
quelle
Das ist für eine Zeichenfolge, keine Datei
Brock Hensley
2
Antwort geändert, um eine Datei
einzuschließen
1
Einige Ihrer Links sind defekt
idclev 463035818
2
Können Sie bitte den VC ++ 2010-Lösungslink aktualisieren?
Jonas
1
Links aktualisiert zu einem Git
ALM865
4

Ich benutze diese Datei http://people.csail.mit.edu/rivest/Md5.c

Hintergedanke
quelle
Es werden andere Hashes als bei anderen MD5-Implementierungen zurückgegeben. Beispielsweise wird eine leere Zeichenfolge an e4c23762ed2823a27e62a64b95c024e7 gehasht, wenn sie d41d8cd98f00b204e9800998ecf8427e sein soll. Es gibt dort eine verwandte Frage: stackoverflow.com/q/33989390/2436687
user31389
3

Ich habe Botan verwendet , um diese und andere Operationen durchzuführen. AraK hat auf Crypto ++ hingewiesen. Ich denke, beide Bibliotheken sind vollkommen gültig. Jetzt liegt es an dir :-).

javier-sanz
quelle
2

Mit Crypto ++ können Sie Folgendes tun:

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

Ich brauche etwas sehr Ähnliches, weil ich keine Multi-Gigabyte-Dateien einlesen kann, nur um einen Hash zu berechnen. Theoretisch könnte ich sie speichern, aber ich muss 32-Bit-Plattformen unterstützen - das ist immer noch problematisch für große Dateien.

Chris K.
quelle
6
-1, md5! = Sha.
Abyx
2

Unter http://256stuff.com/sources/md5/ gibt es eine hübsche Bibliothek mit Anwendungsbeispielen. Dies ist die einfachste Bibliothek für MD5.

user176443
quelle
1

Eine Überarbeitung der Implementierung von @ D'Nabre für C ++. Vergessen Sie nicht, am Ende mit -lcrypto zu kompilieren : 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;
}
Herr. Y.
quelle
1

md5.hhaben auch MD5_*Funktionen sehr nützlich für große Dateien

#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);

Sehr einfach, nicht wahr? Konvertierung in String auch sehr einfach:

#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();
Herr NAE
quelle
hat gut funktioniert für mich!
Maggnetix