Як отримати хеш файлу MD5 у C ++? [зачинено]


75

У мене шлях до файлу. Як я можу отримати хеш MD5?


1
@silky - не дуже корисний коментар :) .. впровадження MD5 з нуля - це дійсно хороший спосіб отримати доступ до криптографічних алгоритмів та протоколів, і оскільки він "відомий", ви можете миттєво перевірити, чи правильний ваш код проти md5sumабо подібний
warren

1
@Noon Silk Я думаю, що для цілі створення унікального підпису для файлу md5 я повинен бути достатнім.
bobobobo

@Noon Silk, з довгими рекурсивними перевірками sha1 буде занадто повільним!
Will03uk

Відповіді:


50

Ось пряма реалізація md5sumкоманди, яка обчислює та відображає MD5 файлу, зазначеного в командному рядку. Для роботи його потрібно пов’язати з бібліотекою OpenSSL ( gcc md5.c -o md5 -lssl). Це чистий C, але ви зможете досить легко адаптувати його до свого додатку 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
на 32-бітових платформах ваша mmap має обмеження щодо розміру файлу, хоча це елегантне рішення проблеми. Наприклад, у 32-бітовій Windows ви не можете MD5 DVD з цим кодом.
Chris K

@ChrisKaminski ви можете пересунути вікно розміром 4 ГБ із відображеним у пам'яті файлом на 32-бітній платформі.
експерт

13
Відмінна відповідь, це мені надзвичайно допомогло. Однак після цього ви не викличете munmap. Це не витік пам’яті для вас, оскільки програма закінчується відразу після цього, але якщо якийсь скоморох, як я, копіює код і не вводить munmap, ми отримуємо витік пам’яті в нашій програмі;) Рішення: munmap (file_buffer, file_size);
Боб Міллер,

9
Для мене gcc md5.c -o md5 -lcryptoце працювало замість -lsslUbuntu 14.04
RajaRaviVarma

1
Залежно від openssl - величезної і чіткої бібліотеки - щось настільки просте, як MD5, мені здається поганою ідеєю.
Тімммм

22

Ви можете реалізувати алгоритм MD5 самостійно (приклади знаходяться в Інтернеті), або ви можете встановити посилання на бібліотеки OpenSSL і використовувати функції дайджесту OpenSSL. ось приклад отримання MD5 байтового масиву:

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

24
коли використовую Qt (як і ти), я волів би просто робити return QCryptographicHash::hash(data, QCryptographicHash::Md5);тело функції ...
akira

5
Якщо мова йде про речі, пов’язані з безпекою, ніколи не пишіть власну реалізацію, якщо матеріалів там, в мережі, буде достатньо. І існує кожна можлива реалізація MD4 / 5, тому насправді немає причин писати власну.
Махмуд Аль-Кудсі,

1
@ MahmoudAl-Qudsi Ум так, мій професор не дозволяє мені плагіатувати код.
b1nary.atr0phy

2
@ MahmoudAl-Qudsi Що стосується речей, пов’язаних із безпекою, ніколи не використовуйте MD5. MD5 не є криптосиловим хешем.
uliwitness

1
@uliwitness md5 не була моєю ідеєю. Це нормально розглядати MD5 як середньошвидкий некрипто-хеш, але я погоджуюсь, що він цілком зламаний як крипто-хеш (а для швидкості та хешування для некрипто-хешів є набагато кращі).
Махмуд Аль-Кудсі

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

}

10
Не дуже добре для файлів розміром Гб :)
швидко_наві

8

Мені потрібно було це зробити зараз, і мені знадобилося крос-платформне рішення, яке підходить для c ++ 11, boost та openssl. Я взяв рішення Д'Набре за вихідну точку і звів його до наступного:

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

Швидкий тестовий виконуваний файл демонструє:

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

Деякі примітки до посилань: Linux: -lcrypto -lboost_iostreams Windows:-DBOOST_ALL_DYN_LINK libeay32.lib ssleay32.lib


Дякую. якщо (! існує (boost :: filesystem :: path (path))) {
Абдул Ахад

8

Для всіх, кого переспрямовано з " /programming/4393017/md5-implementation-in-c ", оскільки він неправильно позначений як дублікат.

Приклад, розташований тут, працює:

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

Якщо ви компілюєте у VC ++ 2010, вам потрібно буде змінити його main.cpp на такий:

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

Вам доведеться трохи змінити клас MD5, якщо ви хочете читати масив char * замість рядка, щоб відповісти на запитання на цій сторінці тут.

РЕДАГУВАТИ:

Очевидно, модифікація бібліотеки MD5 незрозуміла, добре, тут є повне рішення VC ++ 2010 для вашої зручності, щоб включити символи char *:

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

Тут є трохи пояснень:

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

Я просто додав у бібліотеку MD5 наступне:

MD5.cpp:

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

MD5.h:

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

Це для рядка, а не для файлу
Брок Хенслі

2
Відповідь змінено, щоб включити файл
ALM865

1
деякі з ваших посилань порушені
greatest_prime_is_463035818

2
Чи можете ви оновити посилання на рішення VC ++ 2010?
Йонас,

1
посилання оновлено до Git
ALM865

4

Я використовую цей файл http://people.csail.mit.edu/rivest/Md5.c


Він повертає хеші, що відрізняються від інших реалізацій MD5. Наприклад, він хешує порожній рядок до e4c23762ed2823a27e62a64b95c024e7, коли він повинен бути d41d8cd98f00b204e9800998ecf8427e. Там є пов'язаний з цим питання є: stackoverflow.com/q/33989390/2436687
user31389

4

Я використовував Botan для проведення цієї операції та інших раніше. AraK вказав на Crypto ++. Думаю, обидві бібліотеки є цілком дійсними. Тепер це залежить від вас :-).


2

Використовуючи Crypto ++, ви можете зробити наступне:

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

Мені потрібно щось дуже подібне, тому що я не можу читати в мультигігабайтних файлах лише для обчислення хешу. Теоретично я міг би зіставити їх із пам'яттю, але я повинен підтримувати 32-бітні платформи - це все ще проблематично для великих файлів.


6
-1, md5! = Ша.
Abyx



1

Переробка імплементації @ D'Nabre для C ++. Не забудьте компілювати з -lcrypto в кінці: 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;
}

1

md5.hтакож мають MD5_*функції, дуже корисні для великих файлів

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

Дуже просто, чи не так? Перетворення в рядок також дуже просте:

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

працював у мене чудово!
Maggnetix
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.