Click here to Skip to main content
15,860,861 members
Articles / Programming Languages / C++

A C++ SHA1 and MD5 Implementation with CryptoAPI

Rate me:
Please Sign up or sign in to vote.
5.00/5 (22 votes)
20 Sep 2012CPOL4 min read 92.4K   8.3K   49   14
This article proposes a C++ implementation for computing hashes (SHA1, MD5, MD4 and MD2) on Windows with the Microsoft CryptoAPI library.

Introduction

Cryptographic hash functions are widely used for securing communication, storing hash values of passwords in databases, verifying that a message or a file has been transmitted correctly between two entities and others. One of the most widely used algorithms is MD5 (Message Digest Five), which produces a 128-bit hash value, usually expressed as a 32 hex digits number. It is the successor of MD4 and MD2, all of them being developed by Ronald Rivest. Another hash algorithm, also based on MD4, is SHA-1, a cryptographically secure one-way hash algorithm that produces a 160-bit message digest (usually represented as a 40 hex digit number). This article proposes a C++ implementation for computing hashes (SHA1, MD5, MD4 and MD2) with the Microsoft CryptoAPI library. CryptoAPI requires minimum Windowx XP or Windows Server 2003.

Note: Both MD5 and SHA1 have been proved to have weaknesses. MD5 it is not collision resistant and has additional weaknesses, which makes it unsuitable for at least some security applications including SSL certificates. US-CERT has concluded that MD5 "should be considered cryptographically broken and unsuitable for further use". The US National Institute of Standards and Technology, the publisher of SHA1 is also currently looking for a replacement of SHA1.

A Few CryptoAPI Considerations

In order to generate a hash value with CyrptoAPI, one must follow these steps:

  • Initialize a context for cryptography operations
    • CryptAcquireContext: acquires a handle to a key container within a particular cryptographic service provider; this handle is used with the subsequent calls to cryptography APIs.
  • Create a hash object
    • CryptCreateHash: creates a hash object for hashing a stream of data; returns a handle that is used in subsequent calls to hash data or session keys.
  • Hash data
    • CryptHashData: adds data to a previously created hash object. It can be called multiple times to add more data to the hash object.
  • Retrieve the hash value
    • CryptGetHashValue: retrieves data from the hash object. To retrieve the hash value, one must first call this method with HP_HASHSIZE to determine the size of the hash value, allocate the memory for the hash value and then call it with HP_HASHVAL to get the hash value.
  • Clean up by destroying the hash object and releasing the cryptographic context
    • CryptDestroyHash: destroys a hash object previously created with CryptCreateHash.
    • CryptReleaseContext: releases the handle of a cryptographic service provider and a key container, previously acquired with a call to CryptAcquireContext.

Message Digest Implementation

My implementation consists of a couple of template C++ classes that provide: cryptohash_t is the class that provides hashing for streams of data, and cryptohash_helper_t is a helper class that provides simplified API for hashing tests and files. Both these classes are parameterized with the hash algorithm.

C++
template <ALG_ID algorithm>

class cryptohash_t;

template <ALG_ID algorithm>
class cryptohash_helper_t;

Several typedefs are provided for a simplified use of these template classes.

C++
typedef cryptohash_t<CALG_MD2> md2_t;
typedef cryptohash_t<CALG_MD4> md4_t;
typedef cryptohash_t<CALG_MD5> md5_t;
typedef cryptohash_t<CALG_SHA1> sha1_t;

typedef cryptohash_helper_t<CALG_MD2> md2_helper_t;
typedef cryptohash_helper_t<CALG_MD4> md4_helper_t;
typedef cryptohash_helper_t<CALG_MD5> md5_helper_t;
typedef cryptohash_helper_t<CALG_SHA1> sha1_helper_t;

cryptohash_t has the following public interfaces:

  • C++
    bool begin()
    Initializes the hashing routine, creating a hash object used for computing the hashing value of a stream of data. If the function fails, check the last error.
  • C++
    bool update(unsigned char* const buffer, size_t size)
    Adds more data to the current hash. If the function fails, check the last error.
  • C++
    bool finalize()
    Computes the hash value from the current hash object and destroys the hash object. If the function fails, check the last error.
  • C++
    hash_t digest() const
    Retrieves the computed hash value in a binary form.
  • C++
    std::string hexdigest(bool uppercase = false) const
    Retrieves the computed hash value as a string of hex digits.
  • C++
    errorinfo_t lasterror() const
    Returns the last error.

cryptohash_helper_t has the following public interfaces:

  • C++
    hash_t digesttext(std::string const& text)
    Computes and returns the hash value (in binary format) of a text.
  • C++
    std::string hexdigesttext(std::string const& text, bool uppercase = false)
    Computes and returns the hash value (as a string of hex digits) of a text.
  • C++
    hash_t digestfile(std::string const& filename)
    Computes and returns the hash value (in binary format) of a file.
  • C++
    std::string hexdigestfile(std::string const& filename, bool uppercase = false)
    Computes and returns the hash value (as a string of hex digits) of a file.
  • C++
    errorinfo_t lasterror() const
    Returns the last error for any of the above functions.

Examples

Note: In all the following examples, you can simply use any of the provided hash types (md5_t, md4_t, md2_t, sha1_t) or the helper types (md5_helper_t, md4_helper_t, md2_helper_t, sha1_helper_t), without any other change to the sample and get the appropriate results.

Compute SHA-1 for a String

C++
std::string text = "mariusbancila";
std::string digest;

sha1_t hasher;
if(hasher.begin())
{
  if(hasher.update((unsigned char*)(text.c_str()), text.length()))
  {
    if(hasher.finalize())
    {
      digest = hasher.hexdigest();
    }
  }
}

if(digest.empty())
  std::cout << "error code = " << hasher.lasterror().errorCode 
            << ", error message = " << hasher.lasterror().errorMessage
            << std::endl;
else
  std::cout << digest << std::endl;

Compute SHA-1 for Several Strings

C++
std::string text1 = "marius";
std::string text2 = "bancila";
std::string digest;

sha1_t hasher;
if(hasher.begin())
{
  if(hasher.update((unsigned char*)(text1.c_str()), text1.length()))
  {
    if(hasher.update((unsigned char*)(text2.c_str()), text2.length()))
    {
      if(hasher.finalize())
      {
        digest = hasher.hexdigest();
      }
    }
  }
}

if(digest.empty())
  std::cout << "error code = " << hasher.lasterror().errorCode 
            << ", error message = " << hasher.lasterror().errorMessage
            << std::endl;
else
  std::cout << digest << std::endl;

Compute MD5 for a String with a Helper Class

C++
md5_helper_t hhasher;
std::string digest = hhasher.hexdigesttext("mariusbancila");

if(digest.empty())
  std::cout << "error code = " << hhasher.lasterror().errorCode 
            << ", error message = " << hhasher.lasterror().errorMessage
            << std::endl;
else
  std::cout << digest << std::endl;

Compute MD5 for a File with a Helper Class

C++
md5_helper_t hhasher;
std::string digest = hhasher.hexdigestfile("c:\\temp\\sample.png");

if(digest.empty())
  std::cout << "error code = " << hhasher.lasterror().errorCode 
            << ", error message = " << hhasher.lasterror().errorMessage
            << std::endl;
else
  std::cout << digest << std::endl;

Demo Application

Attached to the project, you can find the sources and binaries of a demo application (written in Visual Studio 2008 SP1 with MFC) that uses these hashing template classes to generate hash values (SHA1, MD5, MD4 and MD2) for a text or a selected file. Using the application is straightforward and you can see a screen shot below.

Image 1

Additional Readings

History

  • 20th September, 2012: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Visma Software
Romania Romania
Marius Bancila is the author of Modern C++ Programming Cookbook and The Modern C++ Challenge. He has been a Microsoft MVP since 2006, initially for VC++ and nowadays for Development technologies. He works as a system architect for Visma, a Norwegian-based company. He works with various technologies, both managed and unmanaged, for desktop, cloud, and mobile, mainly developing with VC++ and VC#. He keeps a blog at http://www.mariusbancila.ro/blog, focused on Windows programming. You can follow Marius on Twitter at @mariusbancila.

Comments and Discussions

 
QuestionDefinition of update method -- error Pin
Felix Dombek18-Mar-14 9:26
Felix Dombek18-Mar-14 9:26 
Questionhi can u please help me to convert string in Unicode bytes? Pin
Le@rner21-Jan-14 20:20
Le@rner21-Jan-14 20:20 
AnswerRe: hi can u please help me to convert string in Unicode bytes? Pin
Marius Bancila21-Jan-14 20:42
professionalMarius Bancila21-Jan-14 20:42 
GeneralRe: hi can u please help me to convert string in Unicode bytes? Pin
Le@rner21-Jan-14 22:54
Le@rner21-Jan-14 22:54 
QuestionWIll it work on Linux? Pin
Mizan Rahman8-Jan-14 0:35
Mizan Rahman8-Jan-14 0:35 
AnswerRe: WIll it work on Linux? Pin
Marius Bancila8-Jan-14 0:47
professionalMarius Bancila8-Jan-14 0:47 
Questionhow to generate binary hash value for given string? Pin
Le@rner2-Jan-14 0:52
Le@rner2-Jan-14 0:52 
AnswerRe: how to generate binary hash value for given string? Pin
Marius Bancila2-Jan-14 11:32
professionalMarius Bancila2-Jan-14 11:32 
GeneralRe: how to generate binary hash value for given string? Pin
Le@rner2-Jan-14 18:08
Le@rner2-Jan-14 18:08 
GeneralRe: how to generate binary hash value for given string? Pin
Marius Bancila4-Jan-14 11:08
professionalMarius Bancila4-Jan-14 11:08 
GeneralRe: how to generate binary hash value for given string? Pin
Le@rner19-Jan-14 22:36
Le@rner19-Jan-14 22:36 
QuestionNice article Pin
WuRunZhe11-Dec-13 19:36
WuRunZhe11-Dec-13 19:36 
GeneralMy vote of 5 Pin
Volynsky Alex30-Aug-13 5:33
professionalVolynsky Alex30-Aug-13 5:33 
QuestionVery nice Pin
Fernando A. Gomez F.20-Sep-12 10:08
Fernando A. Gomez F.20-Sep-12 10:08 

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.