http://www.developer.com/security/article.php/3462901/Managed-C-Authenticating-Users-via-Hash-Codes.htm
A previous article covered how to use the .NET encryption classes to compare string values using hash codes. Another usage of hash codes is in situations where a system needs to authenticate a user without storing the user's password. This is especially useful in situations where a company would be held legally liable should the passwords file be stolen or hacked. As I wrote in my book, Extending MFC Applications with the .NET Framework, this can be accomplished by storing the hash code of the password in a file and thenwhen the user attempts to log intaking the user's entered password, hashing it, and comparing it to the hash code that was saved. If you've ever used a system that warned you that it could not recover your password should you lose it, now you know one technique it could've used to authenticate your password without storing it. This article walks you though this technique using the .NET encryption and XML classes. (Click here to download the code for the demo application.)
A salt is a static string that is added to a password before hashing. The addition of the salt greatly increases the difficulty in cracking the codes, because now if the file is hacked the unauthorized person must also determine the salt that gets added to the input as well as how it's added to the input before even attempting to generate the passwords.
Tom Archer owns his own training company, Archer Consulting Group, which specializes in educating and mentoring .NET programmers and providing project management consulting. If you would like to find out how the Archer Consulting Group can help you reduce development costs, get your software to market faster, and increase product revenue, contact Tom through his Web site.
Managed C++: Authenticating Users via Hash Codes
January 27, 2005

Figure 1. The .NET Encryption classes are used to compare the MD5 hash of the entered password against the stored value for that user.
As .NET has wonderful support for XML, I use the XML format to store the users and passwords. The following sample file has a single user and an MD5 hash value for that user's password:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root [
<!ELEMENT User ANY>
<!ATTLIST User Name ID #REQUIRED>
]>
<Users>
<User Name="tom">97-FB-DF-62-D7-39-18-BD-AF-5A-CB-8A-AF-4A-82-3C</User>
</Users>
</pre>
</li>
The demo application does this in the form load method. As you can see, the application closes if the file cannot be loaded (in the catch block):
using namespace System::Xml;
...
protected: XmlDocument^ passwordFile;
...
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
{
try
{
// load passwords
passwordFile = gcnew XmlDocument();
passwordFile->Load("users.xml");
}
catch(Exception^ ex)
{
MessageBox::Show(ex->Message, "ERROR");
Close();
}
}
This method (from the article's demo) first calculates the MD5 hash code from the user's entered password by copying the password string into a byte array (via the Encoding::GetBytes method). It then uses a MD5CryptoServiceProvider object to compute the hash from that byte array. It is converts the resulting hash code back into a String object (via BitConverter::ToString). Once that is done, it searches the XML document using the XmlDocument::GetElementById method. If it finds the element (representing the user), then it updates its "inner text" to the newly created hash value. If it doesn't find the elementwhich indicates a new userthen it creates a new node, sets its inner-text to the hashed password, creates an attribute object with its value set to the user's name, and adds these objects to the XML document. Finally, it saves the document (file) with a call to XmlDocument::Save:
private: System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e)
{
try
{
// Get the user and password values.
String^ user = editUserName->Text;
String^ password = editPassword->Text;
// Calculate hash code for user's entered password
array<Byte>^ baPassword = Encoding::ASCII->GetBytes(password);
MD5CryptoServiceProvider^ md5csp = gcnew MD5CryptoServiceProvider();
array<Byte>^ baHash = md5csp->ComputeHash(baPassword);
String^ passwordHashString = BitConverter::ToString(baHash);
// Search for specified user
XmlElement^ userNode = passwordFile->GetElementById(user);
if (userNode) // if found, update user's password
{
// Update user's hash code representation of password
userNode->InnerText = passwordHashString;
}
else // Create new user
{
// Create XML node.
XmlNode^ userNode = passwordFile->CreateNode( XmlNodeType::Element, "User", nullptr );
userNode->InnerText = passwordHashString;
// Create attribute and add to node
XmlAttribute^ attr = passwordFile->CreateAttribute("Name");
attr->Value = user;
userNode->Attributes->Append(attr);
// Add node to document
passwordFile->DocumentElement->AppendChild( userNode);
}
// Save the XML document
passwordFile->Save("users.xml");
MessageBox::Show("Successfully saved", "Success");
}
catch(Exception^ ex)
{
MessageBox::Show(ex->Message, "ERROR");
}
}
User authentication is just as easy. The click event for the demo application's "Validate" button calls the Login method, which does the following: The Login method first attempts to locate the user via the XmlDocument::GetElementById method using the specified user name. If that is successful, the entered password is hashed (just as in the btnSave_Click method). The hashed value is then converted into a string and compared against the string representing the user's hashed password in the XML file. If they're equal, then the user is authenticated:
private: System::Void btnValidate_Click(System::Object^ sender, System::EventArgs^ e)
{
if (Login(editUserName->Text, editPassword->Text))
MessageBox::Show("Successfully logged in", "Successful Login");
else
MessageBox::Show("The user name or password are incorrect. Please try again.", "INVALID LOGIN ATTEMPT");
}
private: bool Login(String^ userName, String^ password)
{
bool loginIsValid = false;
try
{
// Search for user
XmlElement^ userNode = passwordFile->GetElementById(userName);
if (userNode) // If found, get password's hash value
{
String^ actualHashValue = userNode->InnerText;
// Hash the user's entered password
array
Adding "Salt" to the Mix
Because a password is such a small sizegenerally 6-10 characters in lengthsomeone that gains unauthorized access to your passwords file could try a brute-force method for determining the passwords. While unlikely, that threat still exists. Therefore, to give yourself an even greater level of security, you could simply add a "salt" to the password.
Download the Code
To download the code for the demo application, click here.
About the Author