Skip navigation

Here’s an implementation of the MD5 algorithm in C++.

Simply copy and paste into a file “md5.h”. Only dependencies are on <string.h> and <stdio.h>.

Originally adapted from the C reference implementation on this page

Tested in Visual Studio 2010.
Sample use:

Main.cpp

#include "md5.h"

int main()
{
  MD5 md5 ;
  puts( md5.digestString( "HELLO THERE I AM MD5!" ) ) ;

  // print the digest for a binary file on disk.
  puts( md5.digestFile( "C:\\WINDOWS\\notepad.exe" ) ) ;

  return 0;
}

md5.h

(No .cpp file)

#ifndef MD5_H
#define MD5_H

// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
// rights reserved.

// License to copy and use this software is granted provided that it
// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
// Algorithm" in all material mentioning or referencing this software
// or this function.
//
// License is also granted to make and use derivative works provided
// that such works are identified as "derived from the RSA Data
// Security, Inc. MD5 Message-Digest Algorithm" in all material
// mentioning or referencing the derived work.
//
// RSA Data Security, Inc. makes no representations concerning either
// the merchantability of this software or the suitability of this
// software for any particular purpose. It is provided "as is"
// without express or implied warranty of any kind.
//
// These notices must be retained in any copies of any part of this
// documentation and/or software.



// The original md5 implementation avoids external libraries.
// This version has dependency on stdio.h for file input and
// string.h for memcpy.
#include <stdio.h>
#include <string.h>

#pragma region MD5 defines
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21






static unsigned char PADDING[64] = {
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

// F, G, H and I are basic MD5 functions.
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

// ROTATE_LEFT rotates x left n bits.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
#define FF(a, b, c, d, x, s, ac) { \
  (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }
#define GG(a, b, c, d, x, s, ac) { \
  (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }
#define HH(a, b, c, d, x, s, ac) { \
  (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }
#define II(a, b, c, d, x, s, ac) { \
  (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }
#pragma endregion

typedef unsigned char BYTE ;

// POINTER defines a generic pointer type
typedef unsigned char *POINTER;

// UINT2 defines a two byte word
typedef unsigned short int UINT2;

// UINT4 defines a four byte word
typedef unsigned long int UINT4;


// convenient object that wraps
// the C-functions for use in C++ only
class MD5
{
private:
  struct __context_t {
    UINT4 state[4];                                   /* state (ABCD) */
    UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
    unsigned char buffer[64];                         /* input buffer */
  } context ;

  #pragma region static helper functions
  // The core of the MD5 algorithm is here.
  // MD5 basic transformation. Transforms state based on block.
  static void MD5Transform( UINT4 state[4], unsigned char block[64] )
  {
    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

    Decode (x, block, 64);

    /* Round 1 */
    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

    /* Round 2 */
    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

    /* Round 3 */
    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

    /* Round 4 */
    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

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

    // Zeroize sensitive information.
    memset((POINTER)x, 0, sizeof (x));
  }

  // Encodes input (UINT4) into output (unsigned char). Assumes len is
  // a multiple of 4.
  static void Encode( unsigned char *output, UINT4 *input, unsigned int len )
  {
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4) {
      output[j] = (unsigned char)(input[i] & 0xff);
      output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
      output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
      output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
    }
  }

  // Decodes input (unsigned char) into output (UINT4). Assumes len is
  // a multiple of 4.
  static void Decode( UINT4 *output, unsigned char *input, unsigned int len )
  {
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4)
      output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
  }
  #pragma endregion


public:
  // MAIN FUNCTIONS
  MD5()
  {
    Init() ;
  }

  // MD5 initialization. Begins an MD5 operation, writing a new context.
  void Init()
  {
    context.count[0] = context.count[1] = 0;
  
    // Load magic initialization constants.
    context.state[0] = 0x67452301;
    context.state[1] = 0xefcdab89;
    context.state[2] = 0x98badcfe;
    context.state[3] = 0x10325476;
  }

  // MD5 block update operation. Continues an MD5 message-digest
  // operation, processing another message block, and updating the
  // context.
  void Update(
    unsigned char *input,   // input block
    unsigned int inputLen ) // length of input block
  {
    unsigned int i, index, partLen;

    // Compute number of bytes mod 64
    index = (unsigned int)((context.count[0] >> 3) & 0x3F);

    // Update number of bits
    if ((context.count[0] += ((UINT4)inputLen << 3))
      < ((UINT4)inputLen << 3))
      context.count[1]++;
    context.count[1] += ((UINT4)inputLen >> 29);

    partLen = 64 - index;

    // Transform as many times as possible.
    if (inputLen >= partLen) {
      memcpy((POINTER)&context.buffer[index], (POINTER)input, partLen);
      MD5Transform (context.state, context.buffer);

      for (i = partLen; i + 63 < inputLen; i += 64)
        MD5Transform (context.state, &input[i]);

      index = 0;
    }
    else
      i = 0;

    /* Buffer remaining input */
    memcpy((POINTER)&context.buffer[index], (POINTER)&input[i], inputLen-i);
  }

  // MD5 finalization. Ends an MD5 message-digest operation, writing the
  // the message digest and zeroizing the context.
  // Writes to digestRaw
  void Final()
  {
    unsigned char bits[8];
    unsigned int index, padLen;

    // Save number of bits
    Encode( bits, context.count, 8 );

    // Pad out to 56 mod 64.
    index = (unsigned int)((context.count[0] >> 3) & 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    Update( PADDING, padLen );

    // Append length (before padding)
    Update( bits, 8 );

    // Store state in digest
    Encode( digestRaw, context.state, 16);

    // Zeroize sensitive information.
    memset((POINTER)&context, 0, sizeof (context));

    writeToString() ;
  }

  /// Buffer must be 32+1 (nul) = 33 chars long at least 
  void writeToString()
  {
    int pos ;

    for( pos = 0 ; pos < 16 ; pos++ )
      sprintf( digestChars+(pos*2), "%02x", digestRaw[pos] ) ;
  }


public:
  // an MD5 digest is a 16-byte number (32 hex digits)
  BYTE digestRaw[ 16 ] ;

  // This version of the digest is actually
  // a "printf'd" version of the digest.
  char digestChars[ 33 ] ;

  /// Load a file from disk and digest it
  // Digests a file and returns the result.
  char* digestFile( char *filename )
  {
    Init() ;

    FILE *file;
    
    int len;
    unsigned char buffer[1024] ;

    if( (file = fopen (filename, "rb")) == NULL )
      printf( "%s can't be opened\n", filename ) ;
    else
    {
      while( len = fread( buffer, 1, 1024, file ) )
        Update( buffer, len ) ;
      Final();

      fclose( file );
    }

    return digestChars ;
  }

  /// Digests a byte-array already in memory
  char* digestMemory( BYTE *memchunk, int len )
  {
    Init() ;
    Update( memchunk, len ) ;
    Final() ;
    
    return digestChars ;
  }

  // Digests a string and prints the result.
  char* digestString( char *string )
  {
    Init() ;
    Update( (unsigned char*)string, strlen(string) ) ;
    Final() ;

    return digestChars ;
  }
} ;

#endif
About these ads

23 Comments

  1. Are you sute its right?

  2. I just tested with md5sum. Files: Notepad.exe (Version 6.1.7600.16385) has checksum
    f2c7bb8acc97f92e987a2d4087d021b1 (both code provided and md5sum)

    The text “HELLO THERE I AM MD5!” (without quotes) generates checksum 7f46e34f077fe20a8a4c3190f0bddbf0, in both md5sum and the text processor in the code above.

    The code above generates the exact same result as MD5Sum.
    If you are putting text in a text file, be sure you didn’t enter any extra newlines etc before EOF.

    • Yonathan
    • Posted February 1, 2011 at 12:32 pm
    • Permalink

    When I use this piece of code I do get a hash but it does not match with other programs I am using. For example, the hash obtained from the PHP function MD5_file() and this digest_file() is not the same.

    Any reason why the same algorithm would give different results ?

    • Yonathan
    • Posted February 1, 2011 at 12:47 pm
    • Permalink

    Nvm, it was me screwing up ;)

    Thanks for this snippet!

    • Pandora
    • Posted March 11, 2011 at 4:41 pm
    • Permalink

    char very slow

    std::string fast in Visual Studio and GC++

  3. @Pandora:

    1) Generally char* is faster than std::string on all machines and OS’s
    2) The underlying MD5 library is written in C, so it uses char arrays
    3) You can easily take the outputted string and wrap it up in a std::string.

    • Spica
    • Posted March 29, 2011 at 9:10 am
    • Permalink

    Thanks!
    I’m looking for cpp md5 code like this!
    Can I use it in my program?

  4. What about SHA-265 C++ implementation

    • Matt
    • Posted October 17, 2011 at 8:11 am
    • Permalink

    When trying to use this code
    char input;
    cin >> input;
    puts( md5.digestString(input) ) ;

    I get the following error:

    error C2664: ‘MD5::digestString’ : cannot convert parameter 1 from ‘char’ to ‘char *’

    I’ve tried googling and different types of input. I’m in need for some help, please.

  5. Matt, you will need to get a pointer to it. So doing this will make it work:

    char input;
    cin >> input;
    char* inputpointer = &input;
    puts( md5.digestString(inputpointer ) ) ;

    • Anonymous
    • Posted November 7, 2011 at 7:43 pm
    • Permalink

    @admin@0x3a.com – that code will most likely crash due to lack of null terminator (crash is not guaranteed though)

    char input[2];
    cin >> input[0];
    input[1]=0;
    puts( md5.digestString(input) ) ;

    • John
    • Posted November 18, 2011 at 3:33 pm
    • Permalink

    can anyone give me a hint as to where i can find a c++ source code for content defined chunking? it could be MD5 or rabin fingerprint

    • Fabrizio
    • Posted February 2, 2012 at 7:35 pm
    • Permalink

    Watch out guys: this implementation does not produce the correct MD5 value on Linux 64-bit (or other LP64 system).

    Linux 64-bit uses the LP64 model where an unsigned long is 64-bit, while on Windows (LLP64 system) an unsigned long is still 32-bit.
    See this page for more information: http://technet.microsoft.com/en-us/library/bb496995.aspx

    To make it work, you need to replace the definition of UINT4 from ‘unsigned long int’ to ‘unsigned int’. That will work on both architectures (Win 32, Win 64, Linux 32, Linux 64) and produce the same results.

    Fabrizio (fabriziobertocci-at-gmail.com)

  6. Interesting. Now is that an issue in the MD5 library, see http://stackoverflow.com/questions/697361/md5-hash-calculates-differently-on-server. When I get access to a Linux 64 bit system, I will make the changes and test it, for now LEAVING CODE AS IS (not changed).

    • NJ
    • Posted August 14, 2012 at 5:07 pm
    • Permalink

    its not working for me, getting only 4 character as the result

    • daniele
    • Posted August 30, 2012 at 9:38 am
    • Permalink

    Works perfectly for me. Thanks for sharing.
    D.

    • Stranger in the night
    • Posted September 9, 2012 at 11:28 pm
    • Permalink

    Bobobobo! I don’t know who you are and on this big wide web we may never see each other again but for this wonderful gift of a C++ MD5 implementation I *love* you! :-)

  7. My picture is in my avi. I’m Galvatron.

    I’m also on http://stackoverflow.com/users/111307/bobobobo

    • MHMN
    • Posted October 17, 2012 at 12:59 pm
    • Permalink

    hi guys while running this file i get this error
    make: Makefile: No such file or directory
    im new to c++, can anyone help me ?

    • troy
    • Posted December 14, 2013 at 4:46 am
    • Permalink

    hello
    can i use this md5.h in my own project on github?
    is it ok?

  8. @troy Yes, you definitely can.

  9. This is an absolute masterpiece of a find. Thank you. It outperformed my CRC fingerprint 7 to 1, saved me so much cycles.

    • K. Chris C.
    • Posted August 15, 2014 at 1:29 am
    • Permalink

    Hello,

    I am using the user input version that admin@0x3a.com suggested, but am getting incorrect results.

    If I input, say ‘h’, I get an incorrect reslut not ‘2510c39011c5be704182423e3a695e91′ as returned from other md5 algos on the Internet.

    The code:

    MD5 md5 ;
    char input;
    cin >> input;
    char* inputpointer = &input;
    puts( md5.digestString(inputpointer ) ) ;

    What is wrong?

    Thanks in advance.


2 Trackbacks/Pingbacks

  1. [...] checksum class: I used the implementation that I found here, I don't know how much we can trust that, but so far it do the trick, (mini note: I have just found [...]

  2. [...] contacted me about my MD5 C++ code which is simply the original MD5 functions wrapped in a C++ [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 42 other followers

%d bloggers like this: