One-Way Hashing: Converting and Comparing User Input to the Hashed Value

You can use one-way hashing to encrypt data that does not need to be decrypted; an example implementation is password encryption. The Commerce Server 2002 one-way hashing encryption uses the MD5 Hashing Algorithm.

The following example illustrates a hashed values comparison code example. This example illustrates a scenario that involves one-way hashed passwords. When the user creates the password, the password value is submitted to the Profile Service via the password property. Later, when the user visits the site on another occasion, authenticating against the previously created profile, the site retrieves the salt from the initial characters in the hash, adds the salt to the input value that the user has given, and then hashes this combined value. The resultant password hash is then compared against the previously stored hash minus the pre-appended salt.

This hash example uses an MD5 algorithm combined with random salt. The salt is retrieved as the first four bytes (eight hexadecimal digits) of the value returned from the profile property. The salt is pre-appended to the input value before hashing.

The hash value used for comparison must use a case insensitive comparison, or it must verify that all hexadecimal letter digits are in upper case. This code example illustrates the conversion to upper case.

Ee783861.note(en-US,CS.20).gifNote

  • For this hashing algorithm, you must use little-endian string byte ordering to feed the byte stream to the MD5 hash in string comparison implementation.
// get password from user
string inputPassword = Request.QueryString["password"].Value;
// get password stored in user profile
Profile profile = profileContext.GetProfile(userId, profileDefinition);
string storedPassword = (string)profile["GeneralInfo.Password"].Value;

// get salt value
byte saltByte1 = Byte.Parse(storedPassword.Substring(0,2), System.Globalization.NumberStyles.HexNumber);
byte saltByte2 = Byte.Parse(storedPassword.Substring(2,2), System.Globalization.NumberStyles.HexNumber);
byte saltByte3 = Byte.Parse(storedPassword.Substring(4,2), System.Globalization.NumberStyles.HexNumber);
byte saltByte4 = Byte.Parse(storedPassword.Substring(6,2), System.Globalization.NumberStyles.HexNumber);

// create byte array to hash that has salt and password string
System.Text.UnicodeEncoding encode = new System.Text.UnicodeEncoding(); 
// encoding format is little endian
byte[] dataBuffer = new byte[encode.GetByteCount(inputPassword) + 4]; // get number of bytes and create buffer
dataBuffer[0] = saltByte1; // put salt into first 4 bytes of the buffer
dataBuffer[1] = saltByte2;
dataBuffer[2] = saltByte3;
dataBuffer[3] = saltByte4;

byte[] inputPasswordBytes = encode.GetBytes(inputPassword);

// copy bytes of password into buffer after salt
inputPasswordBytes.CopyTo(dataBuffer, 4); 
// get hash
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hash = md5.ComputeHash(dataBuffer); // get MD5 hashed value

// convert hash value to hex string
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach(byte outputByte in hash)
// convert each byte to a Hexadecimal upper case string
   sb.Append(outputByte.ToString("x2").ToUpper());

// verify input password's hash value matches stored hash minus the salt
if (storedPassword.SubString(8) == sb.ToString())
{
// user is now authenticated
}

Copyright © 2005 Microsoft Corporation.
All rights reserved.