Click here to Skip to main content
15,895,746 members
Articles / Desktop Programming / MFC
Article

Use Windows Crypto API to calculate a MD5 string.

Rate me:
Please Sign up or sign in to vote.
3.49/5 (29 votes)
29 Aug 2002 211.9K   6K   57   24
Use Windows Crypto API to calculate a MD5 string.

Introduction

The source code demonstrates how to invoke the Windows Crypto API to calculate a MD5 string.

The MD5 Message-Digest Algorithm is described in Internet RFC 132.

The sample uses the class Cmd5Capi, a very simple MFC class to wrap the standard win api necesary calls.

Includes required

#include <wincrypt.h> // Cryptographic API Prototypes and Definitions

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Spain Spain
Now, I works for Aurigae S.A a spanish services enterprise, specialized on information technologies for critical mission applications, mainly in the areas of payment system management, stock trading and telecommunications.

Comments and Discussions

 
GeneralThanks Pin
Asaf G6-May-08 0:05
Asaf G6-May-08 0:05 
QuestionHow to decrypt data? Pin
ivax4-Oct-05 0:49
ivax4-Oct-05 0:49 
AnswerRe: How to decrypt data? Pin
andyj11526-Oct-05 0:06
andyj11526-Oct-05 0:06 
GeneralA better solution : here is the code Pin
Elmue22-Apr-04 10:43
Elmue22-Apr-04 10:43 
Hello

Your code has one big problem :
It takes only a string as input.
No more compiler errors !
(And your code is written in MFC and is not usable without modifications in a project (e.g. bad error handling))

But if you need the MD5 of a file and the file is 3 Gigabyte of size you will not be able to load the file into a string !
For that you need an algorithm that is capable to calculate from multiple smaller blocks of the file.


I attach a reusable C++ class (without MFC) which performs this task with highest speed !

After you are ready destroy the MD5 class or call FreeBuffer();

Header :
___________________________________________________________


// cMD5.h: interface for the cMD5 class.

#if !defined(AFX_CMD5_H__6C2F7C61_93D8_11D8_A8BA_000AE637F271__INCLUDED_)
#define AFX_CMD5_H__6C2F7C61_93D8_11D8_A8BA_000AE637F271__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define _ReadBufSize 1000000

class cMD5  
{
public:
    char* CalcMD5FromString(const char *s8_Input);
    char* CalcMD5FromFile  (const char *s8_Path);

    void FreeBuffer();
    cMD5();
    virtual ~cMD5();

private:
    struct MD5Context 
    {
        unsigned long buf[4];
        unsigned long bits[2];
        unsigned char in[64];
    };

    void MD5Init();
    void MD5Update(unsigned char *buf, unsigned len);
    void MD5Final (unsigned char digest[16]);
    
    void MD5Transform(unsigned long buf[4], unsigned long in[16]);
    char* MD5FinalToString();
    
    void byteReverse (unsigned char *buf, unsigned longs);

    char *mp_s8ReadBuffer;
    MD5Context ctx;
    char   ms8_MD5[40]; // Output buffer
};

#endif // !defined(AFX_CMD5_H__6C2F7C61_93D8_11D8_A8BA_000AE637F271__INCLUDED_)


_______________________________________________________

and the cpp file :

________________________________________________________

#include "cMD5.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


cMD5::cMD5()
{
    // don't alloc buffer here, only on request
    mp_s8ReadBuffer = 0;
}

cMD5::~cMD5()
{
    FreeBuffer();
}

void cMD5::FreeBuffer()
{
    if (mp_s8ReadBuffer) delete mp_s8ReadBuffer;
}

/*********************************************************************
//
//         calculate MD5 from a file of any size (also size = 0)
//         returns "" on file error
//
/********************************************************************/

char* cMD5::CalcMD5FromFile(const char *s8_Path)
{
    if (!mp_s8ReadBuffer) mp_s8ReadBuffer = new char[_ReadBufSize];

    MD5Init();

    // ++++++++++++ Read file block by block +++++++++++

    HANDLE h_File = CreateFile(s8_Path, GENERIC_READ, FILE_SHARE_READ, 0, 
                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        
    if (h_File == INVALID_HANDLE_VALUE)
        return "";

    int s32_Size = GetFileSize(h_File, 0);

    while (s32_Size > 0)
    {
        unsigned long u32_Read = 0;
        if (!ReadFile(h_File, mp_s8ReadBuffer, _ReadBufSize, &u32_Read, 0))
        {
            CloseHandle(h_File);
            return "";
        }

        MD5Update((unsigned char*)mp_s8ReadBuffer, u32_Read);

        s32_Size -= u32_Read;
    };

    CloseHandle(h_File);

    // ++++++++++++ Signature --> String +++++++++++

    return MD5FinalToString();
}


/*********************************************************************
//
//                calculate MD5 from a string
//
/********************************************************************/


char* cMD5::CalcMD5FromString(const char *s8_Input)
{
    MD5Init();
    MD5Update((unsigned char*)s8_Input, strlen(s8_Input));

    return MD5FinalToString();
}


/*********************************************************************
//
//                           Calculation functions
//
/*********************************************************************
/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
void cMD5::MD5Init()
{
    ctx.buf[0] = 0x67452301;
    ctx.buf[1] = 0xefcdab89;
    ctx.buf[2] = 0x98badcfe;
    ctx.buf[3] = 0x10325476;

    ctx.bits[0] = 0;
    ctx.bits[1] = 0;
}

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
void cMD5::MD5Update(unsigned char *buf, unsigned len)
{
    unsigned long t;

    /* Update bitcount */

    t = ctx.bits[0];
    if ((ctx.bits[0] = t + ((unsigned long) len << 3)) < t)
    ctx.bits[1]++;  /* Carry from low to high */
    ctx.bits[1] += len >> 29;

    t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */

    /* Handle any leading odd-sized chunks */

    if (t) {
    unsigned char *p = (unsigned char *) ctx.in + t;

    t = 64 - t;
    if (len < t) {
        memcpy(p, buf, len);
        return;
    }
    memcpy(p, buf, t);
    cMD5::byteReverse(ctx.in, 16);
    MD5Transform(ctx.buf, (unsigned long *) ctx.in);
    buf += t;
    len -= t;
    }
    /* Process data in 64-byte chunks */

    while (len >= 64) {
    memcpy(ctx.in, buf, 64);
    cMD5::byteReverse(ctx.in, 16);
    MD5Transform(ctx.buf, (unsigned long *) ctx.in);
    buf += 64;
    len -= 64;
    }

    /* Handle any remaining bytes of data. */

    memcpy(ctx.in, buf, len);
}


/*
 * Convert signature to CString
 */
char* cMD5::MD5FinalToString()
{
    unsigned char signature[16];
    MD5Final(signature);

    ms8_MD5[0] = 0;
    char s8_Temp[5];
    for (int i=0; i<16; i++) 
    {
        sprintf(s8_Temp, "%02X", signature[i]);
        strcat(ms8_MD5, s8_Temp);
    }

    return ms8_MD5;
}


/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern 
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
void cMD5::MD5Final(unsigned char digest[16])
{
    unsigned count;
    unsigned char *p;

    /* Compute number of bytes mod 64 */
    count = (ctx.bits[0] >> 3) & 0x3F;

    /* Set the first char of padding to 0x80.  This is safe since there is
       always at least one byte free */
    p = ctx.in + count;
    *p++ = 0x80;

    /* Bytes of padding needed to make 64 bytes */
    count = 64 - 1 - count;

    /* Pad out to 56 mod 64 */
    if (count < 8) {
    /* Two lots of padding:  Pad the first block to 64 bytes */
    memset(p, 0, count);
    cMD5::byteReverse(ctx.in, 16);
    MD5Transform(ctx.buf, (unsigned long *) ctx.in);

    /* Now fill the next block with 56 bytes */
    memset(ctx.in, 0, 56);
    } else {
    /* Pad block to 56 bytes */
    memset(p, 0, count - 8);
    }
    cMD5::byteReverse(ctx.in, 14);

    /* Append length in bits and transform */
    ((unsigned long *) ctx.in)[14] = ctx.bits[0];
    ((unsigned long *) ctx.in)[15] = ctx.bits[1];

    MD5Transform(ctx.buf, (unsigned long *) ctx.in);
    cMD5::byteReverse((unsigned char *) ctx.buf, 4);
    memcpy(digest, ctx.buf, 16);
    memset(&ctx, 0, sizeof(MD5Context));        /* In case it's sensitive */
}


/* The four core functions - F1 is optimized somewhat */

/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
    ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
void cMD5::MD5Transform(unsigned long buf[4], unsigned long in[16])
{
    register unsigned long a, b, c, d;

    a = buf[0];
    b = buf[1];
    c = buf[2];
    d = buf[3];

    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);

    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);

    buf[0] += a;
    buf[1] += b;
    buf[2] += c;
    buf[3] += d;
}

#ifdef sgi
#define HIGHFIRST
#endif

#ifdef sun
#define HIGHFIRST
#endif


#ifndef HIGHFIRST
    void cMD5::byteReverse(unsigned char *buf, unsigned longs)  
    {
        // Nothing
    }
#else
    // Note: this code is harmless on little-endian machines.
    void cMD5::byteReverse(unsigned char *buf, unsigned longs)
    {
        unsigned long t;
        do {
        t = (unsigned long) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
            ((unsigned) buf[1] << 8 | buf[0]);
        *(unsigned long *) buf = t;
        buf += 4;
        } while (--longs);
    }
#endif

GeneralRe: A better solution : here is the code Pin
HughJampton25-Apr-05 6:11
HughJampton25-Apr-05 6:11 
GeneralRe: A better solution : here is the code Pin
Anonymous25-Apr-05 12:32
Anonymous25-Apr-05 12:32 
GeneralRe: A better solution : here is the code Pin
HughJampton25-Apr-05 15:00
HughJampton25-Apr-05 15:00 
GeneralExcellent code - one simple modification Pin
Douglas R. Keesler5-Jun-05 15:41
Douglas R. Keesler5-Jun-05 15:41 
GeneralRe: A better solution : here is the code Pin
pscholl6-Jun-08 6:01
pscholl6-Jun-08 6:01 
GeneralRe: A better solution : here is the code Pin
Elmue6-Jun-08 14:40
Elmue6-Jun-08 14:40 
GeneralProblem with this constructor. Pin
Prakash Nadar20-Jan-04 16:28
Prakash Nadar20-Jan-04 16:28 
GeneralCompile Error ! Pin
freedem2-Dec-03 15:00
freedem2-Dec-03 15:00 
GeneralRe: Compile Error ! Pin
Victor M. Valenzuela2-Dec-03 21:28
Victor M. Valenzuela2-Dec-03 21:28 
GeneralRe: Compile Error ! Pin
Ștefan-Mihai MOGA29-Mar-06 20:44
professionalȘtefan-Mihai MOGA29-Mar-06 20:44 
GeneralRe: Compile Error ! Pin
bahram_cho6-Apr-07 20:42
bahram_cho6-Apr-07 20:42 
Generalcompilation Errors Pin
Rohit Gadagkar24-Sep-03 7:40
Rohit Gadagkar24-Sep-03 7:40 
GeneralRe: compilation Errors Pin
Vinayak16-Jun-04 9:54
Vinayak16-Jun-04 9:54 
GeneralRe: compilation Errors Pin
Scott B.21-Mar-06 18:59
Scott B.21-Mar-06 18:59 
GeneralDifferent Output Pin
tunafish245-Aug-03 16:42
tunafish245-Aug-03 16:42 
GeneralRe: Different Output Pin
qihongbo28-Sep-03 22:04
qihongbo28-Sep-03 22:04 
GeneralThanks Pin
Paul Hooper25-Apr-03 14:40
Paul Hooper25-Apr-03 14:40 
GeneralCrypto.h Pin
Anonymous4-Nov-02 3:15
Anonymous4-Nov-02 3:15 
GeneralRe: Crypto.h Pin
Ștefan-Mihai MOGA27-Jun-05 0:49
professionalȘtefan-Mihai MOGA27-Jun-05 0:49 
GeneralNeeds improvements Pin
Vagif Abilov30-Aug-02 2:46
professionalVagif Abilov30-Aug-02 2:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.