How to compute and compare hash values by using Visual C++ .NET or Visual C++ 2005 (815656)



The information in this article applies to:

  • Microsoft Visual C++ 2005 Express Edition
  • Microsoft Visual C++ .NET (2003)
  • Microsoft Visual C++ .NET (2002)
  • Microsoft .NET Framework 1.1
  • Microsoft .NET Framework 1.0

For a Microsoft Visual C# .NET version of this article, see 307020.
For a Microsoft Visual Basic .NET version of this article, see 301053.
This article refers to the following Microsoft .NET Framework Class Library namespaces:
  • System.Security.Cryptography
  • System.Text

IN THIS TASK

SUMMARY

This step-by-step article describes how to obtain a hash value and how to compare two hash values to check whether they are identical.

back to the top

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
  • Microsoft Windows 2000, Windows XP Professional or Windows Server 2003
  • Microsoft Visual C++ .NET or Microsoft Visual C++ 2005
back to the top

Compute a hash value

It is easy to generate and compare hash values by using the cryptographic resources that are contained in the System.Security.Cryptography namespace. Because all hash functions take input of type Byte[], you might have to convert the source into a byte array before it is hashed. To create a hash for a string value, follow these steps:
  1. Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.
  3. In Visual Studio .NET 2002, click Visual C++ Projects under Project Types, and then click Managed C++ Application under Templates.

    In Visual C++ .NET 2003, click Visual C++ Projects under Project Types, and then click Console Application (.NET) under Templates.

    In Visual C++ 2005, click Visual C++ under Project Types, and then click CLR Console Application under Templates.
  4. Name the project Q815656. Visual Studio .NET or Visual Studio 2005 creates a public class with a _tmain function.
  5. Use the using directive on the System, System.Security, System.Security.Cryptographic, and System.Text namespaces so that you do not have to qualify declarations from these namespaces later in your code. To do this, add the following lines at the top of Q815656.cpp.
    using namespace System;
    using namespace System::Security::Cryptography; 
    using namespace System::Text; 
    
  6. At the beginning of the _main function, declare a string variable to hold your source data, and two byte arrays (of undefined size) to hold the source bytes and the resulting hash value.
    String* sSourceData;
    Byte tmpSource[];
    Byte tmpHash[];
  7. Use the GetBytes method to convert your source string into an array of bytes (required as input to the hashing function). The GetBytes method is a member of the System.Text.ASCIIEncoding class.
    ASCIIEncoding* ascii = new ASCIIEncoding();
    sSourceData = "MySourceData";
    //Create a byte array from source data.
    tmpSource = ascii->GetBytes(sSourceData);
  8. Compute the MD5 hash for your source data by calling the ComputeHash method on an instance of the MD5CryptoServiceProvider class. Note To compute another hash value, create another instance of the class.
    //Compute hash based on source data.
    tmpHash = (new MD5CryptoServiceProvider())->ComputeHash(tmpSource);
  9. The tmpHash byte array now holds the computed hash value (128-bit value=16 bytes) for your source data. It is frequently useful to display or store a value like this as a hexadecimal string. Use the following code to do this.
    Console::WriteLine(ByteArrayToString(tmpHash));
  10. Add the following ByteArrayToString function definition below the _tmain function.
    String* ByteArrayToString(Byte arrInput[])
    {
    	int i;
    	StringBuilder* sOutput = new StringBuilder(arrInput->Length);
    	for (i=0;i < arrInput->Length -1; i++) 
    	{
    		sOutput->Append(arrInput[i].ToString("X2"));
    	}
    	return sOutput->ToString();
    }
    Note You must add the following function declaration before the _tmain function.
    String* ByteArrayToString(Byte arrInput[]);
    Otherwise, you receive the C3861 and C2365 errors in Visual C++ .NET 2003, or you receive the C2365 and C2365 errors in Visual C++ .NET 2002
  11. Press CTRL+F5 to save and run your code. You see output that is similar to the following:8FD2486D263C1EE4FCF7FA70742F23
back to the top

Compare two hash values

When you create a hash from source data, you can see if data has changed over time, or you can compare two values without ever working with the actual values. In either case, you must compare two computed hashes. You can compare the computed hashes easily if they are both stored as hexadecimal strings (as in the last step of the earlier section). However, both might be in the form of byte arrays. The following code continues from the code that was created in the previous section. This code demonstrates how to compare two byte arrays.
  1. Below the hexadecimal string that is created, create a new hash value that is based on new source data.
    sSourceData = "NotMySourceData";
    //Create a byte array from source data.
    
    tmpSource = ascii->GetBytes(sSourceData);
    Byte tmpNewHash[];
    tmpNewHash = (new MD5CryptoServiceProvider())->ComputeHash(tmpSource);
  2. The most straightforward way to compare two byte arrays is to loop through the arrays and compare each element to its counterpart from the second value. If any elements are different, or if the two arrays are not the same size, the two values are not equal.
    bool bEqual = false;
    if (tmpNewHash->Length == tmpHash->Length)
    {
    	int i=0;
    	while ((i < tmpNewHash->Length) && (tmpNewHash[i] == tmpHash[i]))
    	{
    		i += 1;
    	}
    	if (i == tmpNewHash->Length) 
    	{
    		bEqual = true;
    	}
    }
        
    if (bEqual)
    	Console::WriteLine("The two hash values are the same");
    else
    	Console::WriteLine("The two hash values are not the same");
    Console::ReadLine();
  3. Press CTRL+F5 to save and run your code. You see output that is similar to the following:
    8FD2486D263C1EE4FCF7FA70742F23
    F7711A634146F20AB86D1E5A8F870C
    The two hash values are not the same
back to the top

Complete code listing

#include "stdafx.h"
#include <tchar.h>
#using <mscorlib.dll>

using namespace System;
using namespace System::Security::Cryptography; 
using namespace System::Text; 


String* ByteArrayToString(Byte arrInput[]);

int _tmain(void)
{
    // TODO: Replace the sample code below with your own.
	String* sSourceData;
	Byte tmpSource[];
	Byte tmpHash[];

	ASCIIEncoding* ascii = new ASCIIEncoding();
	sSourceData = "MySourceData";
	//Create a byte array from source data.
	tmpSource = ascii->GetBytes(sSourceData);
	tmpHash = (new MD5CryptoServiceProvider())->ComputeHash(tmpSource);
	Console::WriteLine(ByteArrayToString(tmpHash));
	
	sSourceData = "NotMySourceData";
	tmpSource =ascii->GetBytes(sSourceData);
	Byte tmpNewHash[];
	tmpNewHash = (new MD5CryptoServiceProvider())->ComputeHash(tmpSource);
	Console::WriteLine(ByteArrayToString(tmpNewHash));
	
	bool bEqual = false;
	if (tmpNewHash->Length == tmpHash->Length)
	{
		int i=0;
		while ((i < tmpNewHash->Length) && (tmpNewHash[i] == tmpHash[i]))
		{
			i += 1;
		}
		if (i == tmpNewHash->Length) 
		{
			bEqual = true;
		}
	}
    
	if (bEqual)
		Console::WriteLine("The two hash values are the same");
	else
		Console::WriteLine("The two hash values are not the same");
	Console::ReadLine();

    return 0;
};

String* ByteArrayToString(Byte arrInput[])
{
	int i;
	StringBuilder* sOutput = new StringBuilder(arrInput->Length);
	for (i=0;i < arrInput->Length -1; i++) 
	{
		sOutput->Append(arrInput[i].ToString("X2"));
	}
	return sOutput->ToString();
};
Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the previous code sample. To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:
  1. Click Project, and then click <ProjectName> Properties.

    Note <ProjectName> is a placeholder for the name of the project.
  2. Expand Configuration Properties, and then click General.
  3. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.
For more information about the common language runtime support compiler option, visit the following Microsoft Web site:

/clr (Common Language Runtime Compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

These steps apply to the whole article.

back to the top

REFERENCES

For more information about how to use the cryptographic features of the Microsoft .NET Framework, and about cryptography, visit the following Massachusetts Institute of Technology Web site:For more information about hashing functions, visit the following RSA Security Web site: Microsoft provides third-party contact information to help you find technical support. This contact information may change without notice. Microsoft does not guarantee the accuracy of this third-party contact information.

back to the top

Modification Type:MajorLast Reviewed:1/11/2006
Keywords:kbCrypt kbcode kbHOWTOmaster kbhowto KB815656 kbAudDeveloper