【问题标题】:How to get the MD5 hash of a file in C++? [closed]如何在 C++ 中获取文件的 MD5 哈希? [关闭]
【发布时间】:2010-11-16 05:50:42
【问题描述】:

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

【问题讨论】:

  • @silky - 不是一个真正有用的评论 :) ..从头开始实现 MD5 是接触加密算法和协议的一个非常好的方法,并且由于它是“已知的”,您可以立即验证您的代码是正确的 vs md5sum 或类似
  • @Noon Silk 我认为在这里为文件 md5 制作唯一签名就足够了。
  • @Noon Silk,使用长递归检查 sha1 会太慢!

标签: c++ hash md5


【解决方案1】:

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

【讨论】:

  • 在 32 位平台上,您的 mmap 对文件的大小有限制,尽管它是解决问题的一个优雅的解决方案。例如,在 32 位 Windows 上,您无法使用此代码对 DVD 进行 MD5。
  • @ChrisKaminski 您可以在 32 位平台上滑动 4GB 内存映射文件窗口。
  • 很好的答案,对我帮助很大。但是,您之后不会调用 munmap 。这对你来说没有内存泄漏,因为程序立即结束,但是如果像我这样的小丑复制代码并且没有放入 munmap,我们的程序中就会出现内存泄漏;) 解决方案: munmap(file_buffer, file_size);
  • 对我来说 gcc md5.c -o md5 -lcrypto 这在 Ubuntu 14.04 上有效,而不是 -lssl
  • 依赖于 openssl - 一个庞大而粗糙的库 - 对于像 MD5 这样简单的东西对我来说似乎是个坏主意。
【解决方案2】:

您可以自己实现 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);
}

【讨论】:

  • 在使用 Qt 时(如您所愿),我宁愿将 return QCryptographicHash::hash(data, QCryptographicHash::Md5); 作为函数的主体......
  • 当涉及到与安全相关的东西时,如果网上的东西足够的话,永远不要编写自己的实现。 MD4/5 的每一个可能的实现都已经存在,所以真的没有理由自己编写。
  • @MahmoudAl-Qudsi 嗯,是的,我的教授不让我抄袭代码。
  • @MahmoudAl-Qudsi 在涉及安全相关的内容时,从不使用 MD5。 MD5 不是加密强度哈希。
  • @uliwitness md5 不是我的主意。可以将 MD5 视为中等速度的非加密散列,但我同意它完全被视为加密散列(并且非加密散列在速度和散列方面要好得多)。
【解决方案3】:

对于从“https://stackoverflow.com/questions/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 *'s:

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

【讨论】:

  • 这是一个字符串,而不是一个文件
  • 答案已修改为包含文件
  • 您的某些链接已损坏
  • 能否请您更新VC++2010解决方案链接。
  • 链接更新到 Git
【解决方案4】:
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

}

【讨论】:

  • 不太适合 GB 大小的文件 :)
【解决方案5】:

我刚才需要做这个,需要一个适合c++11、boost和openssl的跨平台解决方案。我以D'Nabre's 解决方案为起点,将其归结为以下内容:

#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 窗口:-DBOOST_ALL_DYN_LINK libeay32.lib ssleay32.lib

【讨论】:

  • 谢谢。 if(!exists(boost::filesystem::path(path))) {
【解决方案6】:

【讨论】:

  • 它返回的哈希值与其他 MD5 实现不同。例如,当它应该是 d41d8cd98f00b204e9800998ecf8427e 时,它​​将空字符串散列到 e4c23762ed2823a27e62a64b95c024e7。那里有一个相关的问题:stackoverflow.com/q/33989390/2436687
【解决方案7】:

我之前使用过Botan 执行此操作和其他操作。 AraK 指出了 Crypto++。我猜这两个库都是完全有效的。现在由你决定:-)。

【讨论】:

    【解决方案8】:

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

    【讨论】:

    • 对我来说效果很好!
    【解决方案9】:

    使用 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 位平台——这对于大文件来说仍然是个问题。

    【讨论】:

    • -1, md5 != sha.
    【解决方案10】:

    【讨论】:

      【解决方案11】:

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

      【讨论】:

        【解决方案12】:

        http://256stuff.com/sources/md5/ 有一个漂亮的库,带有使用示例。这是 MD5 最简单的库。

        【讨论】:

          猜你喜欢
          • 2019-12-20
          • 2014-03-13
          • 1970-01-01
          • 2010-11-11
          • 1970-01-01
          • 2021-01-18
          • 1970-01-01
          • 1970-01-01
          • 2012-05-06
          相关资源
          最近更新 更多