locked
Converting encrypted passwords to hashed passwords - problem RRS feed

  • Question

  • User1036621594 posted

    Hello all,

    I have a database of 65,000 users - all of which have their passwords stored using ASP.NET's 'Encrypted' formats.  For reasons that I wont go into, we now need to convert all these passwords over to 'Hashed' format.

    The problem is that once I've converted the password, I can no longer login to that account with the original password.

    I found this on Stack Overflow which was very helpful:

    http://stackoverflow.com/questions/4948824/changing-passwordformat-from-encrypted-to-hashed 

    ...and from that a I have created a solution that does the conversion, but it has a problem.

    The idea is that you create 2 membership providers - one encrypted (used to read the existing user's password) and the other is hashed (used for changing the user's password)

    Here's what I'm using to convert the password for a single account - just for testing before I tackle all 65,000 accounts:

     void TestPasswordConversion()
        {
            var encryptedProvider = Membership.Providers["EncryptedProvider"];
            var hashedProvider = Membership.Providers["HashedProvider"];
    
            string Username = "testaccountnamehere";
           
            MembershipUser user = Membership.GetUser(Username);
    
            string CurrentPassword = user.GetPassword();
    
            var resetPassword = hashedProvider.ResetPassword(Username, null);
            hashedProvider.ChangePassword(Username, resetPassword, CurrentPassword);
    
            Guid userID = new Guid(user.ProviderUserKey.ToString());
            UpdateUser(userID);
    
        }   
    
    void UpdateUser(Guid userID)
        {
            using (var conn = new SqlConnection(
                   ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))
            {
                conn.Open();
                using (var cmd = new SqlCommand(
                       "UPDATE [aspnet_Membership] SET [PasswordFormat]=1 where UserID = '" + userID + "'", conn))
                   cmd.ExecuteNonQuery();            
                
            }
    
        }

    So as you can see, we're getting back the existing password and then using it to change the password using the hashed membership provider.

    It also runs a simple UPDATE to change the password format for that user in the aspnet_membership table to 1 (Hashed).

    The problem I have is that once the conversion is done, I can't actually login with the orginal password.  Somewhere along the line, the password that gets hashed and saved is different to the original password.

    Does anyone have any ideas as to what might be happening?

    Wednesday, May 28, 2014 7:48 AM

Answers

  • User1036621594 posted

    Hi Patrice,

    Many thanks for your assistance here - I have now solved the problem. I decided to try to convert from Encrypted to Clear just to see what would happen  - I quickly realised that the passwords were not actually being converted into the desired format.  The answer was so simple in the end - you have to change the PasswordFormat column in the aspnet_membership table to the desired format BEFORE you do the password change. If you don't it will reset the password using the existing format - regardless of which provider (hashed/encrypted/plain) is being used.

     I have 2 providers in the web.config - the encrypted one is currently the default:

    <membership defaultProvider="AspNetSqlMembershipProvider" >
              <providers>
                  <remove name="AspNetSqlMembershipProvider" />
                  <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyConn" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="true" passwordFormat="Encrypted" maxInvalidPasswordAttempts="20" minRequiredPasswordLength="2" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" />
                  <add name="HashedProvider" connectionStringName="MyConn" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" minRequiredNonalphanumericCharacters="0" applicationName="/" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" />
    
              </providers>
          </membership>


    Here are the methods for doing the conversion on a single account:

         void TestPasswordConversion()
            {
                var hashedProvider = Membership.Providers["HashedProvider"];
    
                string Username = "testusernamehere";
           
                MembershipUser user = Membership.GetUser(Username);
                Guid userID = new Guid(user.ProviderUserKey.ToString());
                string CurrentPassword = user.GetPassword();
    
                UpdateUser(userID, 1); //Important = change password type field to Hashed(1) before password resets and changes!       
    
                var resetPassword = hashedProvider.ResetPassword(Username, null);
                bool PWChanged = hashedProvider.ChangePassword(Username, resetPassword, CurrentPassword);
    
                if (!PWChanged)
                {
                    UpdateUser(userID,2); //If it failed, revert back to Encrypted(2) type so we can deal with it later
    
                }
    
            }
    
    
     void UpdateUser(Guid userID, int PWType)
        {
            using (var conn = new SqlConnection(
                   ConfigurationManager.ConnectionStrings["BiggerplateConnectionString"].ConnectionString))
            {
                conn.Open();
                using (var cmd = new SqlCommand(
                       "UPDATE [aspnet_Membership] SET [PasswordFormat]=" + PWType + " where UserID = '" + userID + "'", conn))
                   cmd.ExecuteNonQuery();
                Literal1.Text += "User: " + userID.ToString() + " updated<br/>";
                
            }
    
        }

    Thanks for your time - its always good to talk this stuff over - it helps you think in a different direction!

    All the best,

    Nick

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, May 29, 2014 6:55 AM

All replies

  • User753101303 posted

    Hi,

    And the default provider is ? Have you checked that you retrieve the correct password from your source membership ? Have you tried what happens if you hardcode the password does it work ? For now I'm trying to understand if providing a new hardcoded password is ok. If no it would point at an issue on the password change. If yes, it could point rather to an issue in the password retrieval.

    Not sure why you have to update the password format ? (each membership is configured for a format, I'm not sure why you would have to change the PasswordFormat column). You are doing this change for which membership db ?

    Also when doing the login test you swapped the provider so that you goes to the correct membership db ? Ah or you have two providers pointing to the same db rather than doing a copy and moving this from a source to a destination db ?

     

    Wednesday, May 28, 2014 8:29 AM
  • User1036621594 posted

    Hi Patrice,

    Thanks for your reply!

    Have you checked that you retrieve the correct password from your source membership ?

    Yes, I have checked a the correct original password is being retrieved.

    Have you tried what happens if you hardcode the password does it work ?

    I have just tried that - and it didn't make any difference - so it must be something to do with the password change. I'm guessing that the hashed is being salted correctly, but i'm not sure and I dont know how to check!

    Ah or you have two providers pointing to the same db rather than doing a copy and moving this from a source to a destination db ?

    Yes - that's right - 2 providers pointed at the same db.

    The other thing to mention is that most of the current accounts would have been set-up on .net v2. We only migrated over to 4.5 more recently, and I know that there's been some kind of default hash algorithm change. Maybe this could contributing to the problem?

    Wednesday, May 28, 2014 10:54 AM
  • User753101303 posted

    Ah what if you test the boolean value returned by ChangePassword ? What if you try to log using the password returned by ResetPassword ? Could it be that currently it resets the password but that ChangePassword fails. They both have the same complexity/length/whatever settings ?

     

    Wednesday, May 28, 2014 11:35 AM
  • User1036621594 posted

    Hi Patrice,

    Many thanks for your assistance here - I have now solved the problem. I decided to try to convert from Encrypted to Clear just to see what would happen  - I quickly realised that the passwords were not actually being converted into the desired format.  The answer was so simple in the end - you have to change the PasswordFormat column in the aspnet_membership table to the desired format BEFORE you do the password change. If you don't it will reset the password using the existing format - regardless of which provider (hashed/encrypted/plain) is being used.

     I have 2 providers in the web.config - the encrypted one is currently the default:

    <membership defaultProvider="AspNetSqlMembershipProvider" >
              <providers>
                  <remove name="AspNetSqlMembershipProvider" />
                  <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyConn" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="true" passwordFormat="Encrypted" maxInvalidPasswordAttempts="20" minRequiredPasswordLength="2" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" />
                  <add name="HashedProvider" connectionStringName="MyConn" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" minRequiredNonalphanumericCharacters="0" applicationName="/" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" />
    
              </providers>
          </membership>


    Here are the methods for doing the conversion on a single account:

         void TestPasswordConversion()
            {
                var hashedProvider = Membership.Providers["HashedProvider"];
    
                string Username = "testusernamehere";
           
                MembershipUser user = Membership.GetUser(Username);
                Guid userID = new Guid(user.ProviderUserKey.ToString());
                string CurrentPassword = user.GetPassword();
    
                UpdateUser(userID, 1); //Important = change password type field to Hashed(1) before password resets and changes!       
    
                var resetPassword = hashedProvider.ResetPassword(Username, null);
                bool PWChanged = hashedProvider.ChangePassword(Username, resetPassword, CurrentPassword);
    
                if (!PWChanged)
                {
                    UpdateUser(userID,2); //If it failed, revert back to Encrypted(2) type so we can deal with it later
    
                }
    
            }
    
    
     void UpdateUser(Guid userID, int PWType)
        {
            using (var conn = new SqlConnection(
                   ConfigurationManager.ConnectionStrings["BiggerplateConnectionString"].ConnectionString))
            {
                conn.Open();
                using (var cmd = new SqlCommand(
                       "UPDATE [aspnet_Membership] SET [PasswordFormat]=" + PWType + " where UserID = '" + userID + "'", conn))
                   cmd.ExecuteNonQuery();
                Literal1.Text += "User: " + userID.ToString() + " updated<br/>";
                
            }
    
        }

    Thanks for your time - its always good to talk this stuff over - it helps you think in a different direction!

    All the best,

    Nick

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, May 29, 2014 6:55 AM