如何在C ++中获取文件的MD5哈希?[关闭]


75

我有文件路径。如何获得它的MD5哈希?


1
@silky -不是一个真正的有用的评论:)从头..implementing MD5是让接触到的加密算法和协议一个很好的方式,并且由于它的“已知”,可以即时验证您的代码是正确的VSmd5sum或类似
沃伦

1
@Noon Silk我认为在这里为文件md5做出唯一签名应该足够了。
bobobobo 2010年

@Noon Silk,经过长时间的递归检查,sha1太慢了!
Will03uk 2011年

Answers:


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。
克里斯·K

@ChrisKaminski,您可以在32位平台上滑动4GB的内存映射文件窗口。
专家

13
出色的答案,对我有极大的帮助。但是,您之后不会再调用munmap。对您而言,这不会造成内存泄漏,因为程序会立即结束,但是如果像我这样的家伙会复制代码并且未放入munmap,则会在程序中出现内存泄漏;)解决方案:munmap(file_buffer,file_size);
Bob Miller

9
对于我gcc md5.c -o md5 -lcrypto这个工作,而不是-lssl在Ubuntu 14.04
RajaRaviVarma

1
依靠openssl-一个庞大而粗糙的库-像MD5这样简单的东西对我来说似乎是个坏主意。
Timmmm

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 2010年

5
当涉及到与安全相关的内容时,如果网络上的内容足够,请不要编写自己的实现。而且MD4 / 5的每一个可能的实现都在那里,因此实际上没有理由编写自己的。
Mahmoud Al-Qudsi 2010年

1
@ MahmoudAl-Qudsi嗯,是的,我的教授不允许我窃代码。
b1nary.atr0phy 2013年

2
@ MahmoudAl-Qudsi当涉及到与安全相关的内容时,切勿使用MD5。MD5不是加密强度哈希。
uliwitness 2014年

1
@uliwitness md5不是我的主意。可以将MD5视为中等速度的非加密哈希,但是我同意它完全可以作为加密哈希来破解(非加密哈希在速度和哈希方面要好得多)。
Mahmoud Al-Qudsi 2014年

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
对于GB大小的文件不是很好:)
quick_now 2013年

8

我现在需要执行此操作,并且需要适用于c ++ 11,boost和openssl的跨平台解决方案。我以D'Nabre的解决方案为起点,并将其归结为以下几点:

#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


谢谢。if(!exists(boost :: filesystem :: path(path))){
Abdul Ahad

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

如果要读取char *数组而不是字符串来读取此页面上的问题,则必须稍微更改MD5类。

编辑:

显然,修改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);

那是一个字符串,而不是文件
Brock Hensley

2
答案已修改为包含文件
ALM865

1
您的某些链接已损坏
great_prime_is_463035818

2
您能否更新VC ++ 2010解决方案链接。
乔纳斯(Jonas)

1
链接已更新到Git
ALM865 '17


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; 

我需要非常类似的东西,因为我不能仅仅为了计算散列而读取数GB的文件。从理论上讲,我可以对它们进行内存映射,但是我必须支持32位平台-对于大型文件而言,这仍然是个问题。


6
-1,md5!= sha。
Abyx 2012年



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.hMD5_*对大文件也有非常有用的功能

#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 '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.