Hash MD5 del archivo en C++

8 minutos de lectura

avatar de usuario de user145586
usuario145586

¿Cómo obtener el hash MD5 de un archivo en C++?

  • @silky: no es realmente un comentario útil 🙂 … implementar MD5 desde cero es una muy buena manera de exponerse a algoritmos y protocolos criptográficos, y dado que es “conocido”, puede verificar instantáneamente que su código es correcto vs. md5sum o similar

    – madriguera

    10 de octubre de 2009 a las 2:18

  • @Noon Silk Creo que para el propósito aquí de hacer una firma única para un archivo md5 debería ser adecuado.

    – bobobobo

    17 de octubre de 2010 a las 18:14

  • @Noon Silk, ¡con verificaciones recursivas largas, sha1 sería demasiado lento!

    – Will03uk

    26 de julio de 2011 a las 10:27

Avatar de usuario de D'Nabre
D’Nabre

Aquí hay una implementación directa de la md5sum comando que calcula y muestra el MD5 del archivo especificado en la línea de comandos. Debe vincularse con la biblioteca OpenSSL (gcc md5.c -o md5 -lssl) trabajar. Es C puro, pero debería poder adaptarlo a su aplicación C++ con bastante facilidad.

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

  • en plataformas de 32 bits, su mmap tiene un límite en cuanto al tamaño que puede tener el archivo, aunque es una solución elegante al problema. En Windows de 32 bits, por ejemplo, no podría MD5 un DVD con este código.

    – Chris K.

    12 de abril de 2010 a las 20:38

  • @ChrisKaminski puede deslizar una ventana de 4 GB de un archivo asignado en memoria en una plataforma de 32 bits.

    – experto

    15 de noviembre de 2012 a las 0:48

  • Excelente respuesta, me ha ayudado inmensamente. Sin embargo, no llamas a munmap después. No es una fuga de memoria para ti porque el programa finaliza inmediatamente después, pero si algún bufón como yo copia el código y no pone munmap, tenemos una fuga de memoria en nuestro programa 😉 La solución: munmap(file_buffer, file_size);

    – Bob Molinero

    3 de abril de 2013 a las 7:37

  • Para mí gcc md5.c -o md5 -lcrypto esto funcionó en lugar de -lssl en Ubuntu 14.04

    – RajaRavi Varma

    21 de agosto de 2014 a las 19:04

  • Dependiendo de openssl, una biblioteca enorme y retorcida, para algo tan simple como MD5 me parece una mala idea.

    – Timmmmm

    31 de marzo de 2017 a las 13:09

Avatar de usuario de OneOfOne
Uno de uno

Puede implementar el algoritmo MD5 usted mismo (los ejemplos están en toda la web), o puede vincular las librerías de OpenSSL y usar las funciones de resumen de OpenSSL. aquí hay un ejemplo para obtener el MD5 de una matriz de bytes:

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

  • cuando uso Qt (como lo haces tú), prefiero simplemente hacer return QCryptographicHash::hash(data, QCryptographicHash::Md5); como el cuerpo de la función…

    – akira

    10 de marzo de 2010 a las 9:02

  • Cuando se trata de cosas relacionadas con la seguridad, nunca escriba su propia implementación si las cosas que hay en la red son suficientes. Y todas las implementaciones posibles de MD4/5 están disponibles, por lo que realmente no hay razón para escribir la suya propia.

    – Mahmud Al-Qudsi

    12 de abril de 2010 a las 20:37

  • @ MahmoudAl-Qudsi Um, sí, mi profesor no me deja plagiar el código.

    – Arkon

    8 de abril de 2013 a las 4:11

  • @MahmoudAl-Qudsi Cuando se trata de cosas relacionadas con la seguridad, nunca utiliza MD5. MD5 no es un hash criptográfico.

    – ulitestigo

    21 de agosto de 2014 a las 19:26

  • @uliwitness md5 no fue idea mía. Está bien tratar a MD5 como un hash no criptográfico medio rápido, pero estoy de acuerdo en que está completamente roto como un hash criptográfico (y hay mucho mejores en términos de velocidad y hash para hash no criptográficos).

    – Mahmud Al-Qudsi

    23 de agosto de 2014 a las 22:53

Avatar de usuario de ALM865
ALM865

Para cualquier persona redirigida desde “https://stackoverflow.com/questions/4393017/md5-implementation-in-c” porque se ha etiquetado incorrectamente como duplicado.

El ejemplo que se encuentra aquí funciona:

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

Si está compilando en VC ++ 2010, deberá cambiar su main.cpp a esto:

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

Tendrá que cambiar ligeramente la clase MD5 si va a leer en una matriz char * en lugar de una cadena para responder la pregunta en esta página aquí.

EDITAR:

Aparentemente, la modificación de la biblioteca MD5 no está clara, bueno, una solución completa de VC ++ 2010 está aquí para su conveniencia para incluir caracteres *:

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

Un poco de una explicación está aquí:

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

Simplemente agregué lo siguiente a la biblioteca MD5:

MD5.cpp:

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

MD5.h:

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

  • Eso es para una cadena, no para un archivo

    –Brock Hensley

    02/09/2015 a las 22:00

  • Respuesta modificada para incluir un archivo

    – ALM865

    3 sep 2015 a las 23:08

  • algunos de tus enlaces estan rotos

    – 463035818_no_es_un_número

    16 de agosto de 2017 a las 8:53

  • ¿Puede actualizar el enlace de la solución VC++ 2010?

    – Jonás

    31/10/2017 a las 20:47

  • enlaces actualizados a un Git

    – ALM865

    7 noviembre 2017 a las 23:00

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

}

Avatar de usuario de Benedict
Benedicto

Necesitaba hacer esto justo ahora y necesitaba una solución multiplataforma que fuera adecuada para c++11, boost y openssl. Tomé la solución de D’Nabre como punto de partida y la reduje a lo siguiente:

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

Un ejecutable de prueba rápida demuestra:

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

Algunas notas de enlace: Linux: -lcrypto -lboost_iostreams
Ventanas: -DBOOST_ALL_DYN_LINK libeay32.lib ssleay32.lib

  • gracias. if(!exists(boost::filesystem::ruta(ruta))) {

    – Abdul Ahad

    15 de noviembre de 2017 a las 14:45

avatar de usuario de mr NAE
Sr. NAE

md5.h también tienen MD5_* funciones muy útiles para archivos grandes

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

Muy simple, ¿no? La conversión a cadena también es muy simple:

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

  • gracias. if(!exists(boost::filesystem::ruta(ruta))) {

    – Abdul Ahad

    15 de noviembre de 2017 a las 14:45

Avatar de usuario de Chris K
cris k

Usando Crypto ++, puede hacer lo siguiente:

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

Necesito algo muy similar, porque no puedo leer archivos de varios gigabytes solo para calcular un hash. En teoría, podría mapearlos en la memoria, pero tengo que admitir plataformas de 32 bits; eso sigue siendo problemático para archivos grandes.

  • Solo para tener en cuenta: sha256 != md5

    – c00000fd

    15 abr a las 11:16

¿Ha sido útil esta solución?