Click here to Skip to main content
Click here to Skip to main content

Manually validating an ASP.NET user account with a SHA1 hashed password

By , 16 Jan 2009
 

Introduction

Recently, I came across a situation where I needed to provide the same authentication service provided by the ASP.NET Roles and Membership provider, but on a mobile device. A mobile device would sync to a backend database, pulling down all the aspNet_XXXX tables. The user of the mobile device would then be able to validate their account against the mobile device using their existing ASP.NET Roles and Membership credentials.

Using the code

The code below first demonstrates checking for a username match, and then comparing the password hash originally generated by the user to the hash created with the password they have supplied the program.

In the last lines of the program, I persist the user data so that it is available to the rest of the program.

public bool LogonUser(string userName, string passWord)
{
    Guid userID = Guid.Empty;
    string originalHash = "";
    string saltValue = "";
    DataLayer dataLayer = new DataLayer();

    // first check for a username
    try
    {
        string SQL =
        " Select    aspnet_Membership.UserId, "
        + "        Password, "
        + "         PasswordSalt "
        + " From    aspnet_Membership inner join  "
        + "         aspnet_Users on aspnet_Membership.UserID" 
        + " = aspnet_Users.UserID "
        + " Where    LoweredUserName = @p1 ";

        SqlCeCommand sqlCeCommand = new SqlCeCommand(SQL, 
                     dataLayer.GetOpenConnection);
        SqlCeParameter param1 = 
          sqlCeCommand.Parameters.Add("p1", 
                       System.Data.SqlDbType.NVarChar);
        param1.Value = userName.ToLower();

        SqlCeDataReader reader = sqlCeCommand.ExecuteReader();
        while (reader.Read())
        {
            userID = reader.GetGuid(0);
            originalHash = reader.GetString(1);
            saltValue = reader.GetString(2);
            break;
        }

        reader.Close();
    }
    catch (Exception ex)
    {
        new Logger().Log(ex);
        throw ex;
    }
    finally
    {
        dataLayer.CloseSQLConnection();
    }

    // username exists
    if (userID.CompareTo(Guid.Empty) != 0)
    {

        // compare password hashes
        byte[] bIn = Encoding.Unicode.GetBytes(passWord);
        byte[] bSalt = Convert.FromBase64String(saltValue);
        byte[] bAll = new byte[bSalt.Length + bIn.Length];
        byte[] bRet = null;

        Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
        Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);

        HashAlgorithm s = HashAlgorithm.Create("SHA1");

        bRet = s.ComputeHash(bAll);
        string newHash = Convert.ToBase64String(bRet);

        // check the hash in the datbase matched the new hash we generated
        if (originalHash != newHash)
            throw new Exception("Incorrect Username/Password" + 
                                " combination. Please try again");

    }
    else
    {
        throw new Exception("Incorrect Username/Password" + 
                            " combination. Please try again");
    }

    // store the users credentials in the config object for app instance use
    Config.UserID = userID;
    Config.UserName = userName;
    Config.PassWord = passWord;

    return true;

}

It took me a while to get this, so hopefully, this will save someone else scratching their head!

License

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

About the Author

Malcolm Swaine
Software Developer (Senior) www.malcolmswaine.com
Thailand Thailand
Member
Professional freelance business software developer working from Thailand.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberCarl Randall26 Nov '12 - 5:33 
QuestionThanks. Worked great.memberPaul Brown16 Nov '12 - 9:03 
I used the hashing as part of blog post on migrating to the new MVC4 SimpleMembership. You can find it here.
http://pretzelsteelersfan.blogspot.com/2012/11/migrating-legacy-apps-to-new.html[^]
GeneralCheersmemberGiles Park9 Sep '09 - 23:03 
Generalif saltValue is emptymemberHaozes16 Jan '09 - 16:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 16 Jan 2009
Article Copyright 2009 by Malcolm Swaine
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid