Changing passwordFormat from Encrypted to Hashed Changing passwordFormat from Encrypted to Hashed asp.net asp.net

Changing passwordFormat from Encrypted to Hashed


Greg's solution is a good start, but it won't affect existing users. The SqlMembershipProvider protects existing users and passwords by storing the PasswordFormat (0=clear, 1=Hashed, 2=Encrypted) in the table along with passwords. Changing the provider password format only affects inserts to the user tables. In order to convert existing users' passwords to Hashed, you have to change the PasswordFormat parameter for each entry. Here is a simple way to do this:

void HashAllPasswords(){    var clearProvider = Membership.Providers["SqlProvider_Clear"];    var hashedProvider = Membership.Providers["SqlProvider_Hashed"];    int dontCare;    if (clearProvider == null || hashedProvider == null) return;    var passwords = clearProvider.GetAllUsers(0, int.MaxValue, out dontCare)        .Cast<MembershipUser>().ToDictionary(u => u.UserName, u => u.GetPassword());    using (var conn = new SqlConnection(           ConfigurationManager.ConnectionStrings[0].ConnectionString))    {        conn.Open();        using (var cmd = new SqlCommand(               "UPDATE [aspnet_Membership] SET [PasswordFormat]=1", conn))            cmd.ExecuteNonQuery();    }    foreach (var entry in passwords)    {        var resetPassword = hashedProvider.ResetPassword(entry.Key, null);        hashedProvider.ChangePassword(entry.Key, resetPassword, entry.Value);    }}


This is the approach I'd start with to see how far I got:

  1. Create two MembershipProviders in my web.config, one for encrypted passwords and one for hashed.
  2. Loop through all users using encrypted password provider. (SqlMembershipProvider.GetAllUsers)
  3. Get the user's password using encrypted password provider. (MembershipUser.GetPassword)
  4. Change the user's password to the same password using hashed password provider. (MembershipUser.ChangePassword)

So it'd be something like this:

    <membership defaultProvider="HashedProvider">        <providers>            <clear />            <add name="HashedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="false"  requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Hashed"  type="System.Web.Security.SqlMembershipProvider" />            <add name="EncryptedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="true" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Encrypted" type="System.Web.Security.SqlMembershipProvider" />        </providers>    </membership>

code:

SqlMembershipProvider hashedProvider = (SqlMembershipProvider)Membership.Providers["HashedProvider"];SqlMembershipProvider encryptedProvider = (SqlMembershipProvider)Membership.Providers["EncryptedProvider"];int unimportant;foreach (MembershipUser user in encryptedProvider.GetAllUsers(0, Int32.MaxValue, out unimportant )){    hashedProvider.ChangePassword(user.UserName, user.GetPassword(), user.GetPassword());}


For security reasons, it's definitely the right decision to switch from encrypted passwords to hashes in your database.

Generally to create hashes out of your existing encrypted passwords, you should first decrypt them and then hash them. Be aware that you will loose (when you finally switch) the original passwords. Instead you're going to have a unique fingerprint (hash) of the users passwords.

Think also about using salt for the hashing (defense against rainbow tables etc.) and also have a look in slow hashing algorithms like BCrypt (Codeplex & Article: How To Safely Store A Password) for security reasons instead of fast ones like MD5.

Keep also in mind, that it will be way more effort to switch the hashing algorithm in the future than changing it from ecryption to hash. So you want to do it right the first time ;)