How to Validate Passwords

You cannot simply read encrypted data from the database and decrypt it. This action would present a potential compromise to sensitive data. Instead, you must compare, or validate, known data against encrypted data stored in the database. For example, you can validate a user's password that is typed into a Web page text box against encrypted passwords stored in the Profiles database. The fact that data is encrypted when it is stored and cannot be decrypted is known as one-way encryption.

This topic explores how to validate passwords, but the same concept can be applied to any encrypted data stored in Commerce Server.

The process of validating passwords and other data is complex. It consists of this process:

  1. Determine how the password is stored in the Core Profiles System.

  2. If the password is not encrypted or is asymmetrically encrypted, compare the clear text password with the value stored in the Core Profiles System.

  3. If the password is encrypted with a one-way hash, strip the salt value from the password hash stored in the Core Profiles System. A salt value is a byte sequence that you use to hash the clear text passwords. For more information, see How to Hash Passwords.

  4. You hash the clear text password by using the salt value. You use the hashed value to compare the clear text password against the encrypted password stored in the database. For more information, see How to Hash Passwords.

To validate a password

  1. Create a function called VerifyPassword that retrieves a user's password from the Core Profiles System.

  2. Hash the password and compare it to the user's entered password.

  3. Inside the VerifyPassword function, create a CommerceContext object and call the GetProfile method.

  4. Retrieve the Password property from the UserProfile property collection.

  5. Create a function called VerifyHashedPassword that compares the user's entered password against a hashed password. This function will use the HashPassword function that is described in How to Hash Passwords.

Example

This example contains the logic to validate a clear text password for a user against the password stored in the Core Profiles System. The clear text password could, for example, come from a text box on a Web page. This example shows how to create a new function, called VerifyPassword that you use to validate a password for a user in the Core Profiles System. This function accepts two parameters. The first is the user ID. The second parameter is the clear text password for the user.

The following is an example of how to call the VerifyPassword function:

bool result = false;
result = VerifyPassword("username@mysite.com", "password");

If the password is validated for the user, the value for result will be True. If the password is not validated, the value for result will be False.

Note

The code sample assumes that you are using the email_address field in the UserObject Profile Schema to uniquely identify users in your Commerce Server site. If not, simply change the UserLoginPropertyName value to the applicable property value.

// Name of the user profile.
const string UserProfileName = "UserObject";

// Property that holds the logon name.
const string UserLoginPropertyName = "GeneralInfo.email_address";

// Property that holds the password.
const string UserPasswordPropertyName = "GeneralInfo.user_security_password";

private const int SaltValueSize = 4;

// Hashing algorithms used to verify one-way-hashed passwords:
// MD5 is used for backward compatibility with Commerce Server 2002. If you have no legacy data, MD5 can be removed.
// SHA256 is used on Windows Server 2003.
private static string[] HashingAlgorithms = new string[] { "SHA256", "MD5" };

private bool VerifyPassword(string userid, string password)
{
    Profile userProfile = CommerceContext.Current.ProfileSystem.GetProfile(UserLoginPropertyName, userid, UserProfileName);
    if (userProfile != null)
    {
        ProfileProperty passwordProperty = userProfile[UserPasswordPropertyName];
        string userPassword = passwordProperty.Value.ToString();

        bool isHashed = false;
        ProfilePropertyAttribute encryptionType = passwordProperty.Attributes["encryptiontype"];
        if (encryptionType != null)
            isHashed = string.Equals(encryptionType.Value.ToString(), "1", StringComparison.Ordinal);

        if (isHashed)
        {
            return VerifyHashedPassword(password, userPassword);
        }
        else
        {
            return string.Equals(password, userPassword, StringComparison.Ordinal);
        }
    }

    return false;
}

private bool VerifyHashedPassword(string password, string profilePassword)
{
    int saltLength = SaltValueSize * UnicodeEncoding.CharSize;

    if (string.IsNullOrEmpty(profilePassword) ||
        string.IsNullOrEmpty(password) ||
        profilePassword.Length < saltLength)
    {
        return false;
    }

    // Strip the salt value off the front of the stored password.
    string saltValue = profilePassword.Substring(0, saltLength);

    foreach (string hashingAlgorithmName in HashingAlgorithms)
    {
        HashAlgorithm hash = HashAlgorithm.Create(hashingAlgorithmName);
        string hashedPassword = HashPassword(password, saltValue, hash);
        if (profilePassword.Equals(hashedPassword, StringComparison.Ordinal))
            return true;
    }

    // None of the hashing algorithms could verify the password.
    return false;
}

Compiling the Code

  • To compile the code, you need to include these namespace directives:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Security.Cryptography;

See Also

Other Resources

Profiles Encryption and Decryption

How Does the Profiles System Encrypt Data?

How to Use Asymmetric Encryption with Profiles

How to Hash Passwords

Profile Key Manager