locked
Identity 3 custom passwordhasher RRS feed

  • Question

  • User-1759553607 posted

    I can't quite seem to piece together how to get a custom passwordhasher working in Identity 3 with ASP.net 5/MVC6. I have an existing user database which had it's own mechanism for password hashing, which is why I need to replace the built in one (rather than reset everyone's password ;))

    This was somewhat easy in Identity 2, but I'm scratching my head with 3.

    Thanks for any assistance!

    Monday, November 23, 2015 9:40 PM

Answers

All replies

  • User614698185 posted

    Hi madmunsterdaddy,

    Here is how the default implementation works. It uses a Key Derivation Function with random salt to produce the hash. The salt is included as part of the output of the KDF. Thus, each time you "hash" the same password you will get different hashes. To verify the hash the output is split back to the salt and the rest, and the KDF is run again on the password with the specified salt. If the result matches to the rest of the initial output the hash is verified.

    Hashing:

    public static string HashPassword(string password)
    {
        byte[] salt;
        byte[] buffer2;
        if (password == null)
        {
            throw new ArgumentNullException("password");
        }
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8))
        {
            salt = bytes.Salt;
            buffer2 = bytes.GetBytes(0x20);
        }
        byte[] dst = new byte[0x31];
        Buffer.BlockCopy(salt, 0, dst, 1, 0x10);
        Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);
        return Convert.ToBase64String(dst);
    }

    Verifying:

    public static bool VerifyHashedPassword(string hashedPassword, string password)
    {
        byte[] buffer4;
        if (hashedPassword == null)
        {
            return false;
        }
        if (password == null)
        {
            throw new ArgumentNullException("password");
        }
        byte[] src = Convert.FromBase64String(hashedPassword);
        if ((src.Length != 0x31) || (src[0] != 0))
        {
            return false;
        }
        byte[] dst = new byte[0x10];
        Buffer.BlockCopy(src, 1, dst, 0, 0x10);
        byte[] buffer3 = new byte[0x20];
        Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 0x3e8))
        {
            buffer4 = bytes.GetBytes(0x20);
        }
        return ByteArraysEqual(buffer3, buffer4);
    }

    For more information, please refer to the following documents:

    http://brockallen.com/2013/10/20/the-good-the-bad-and-the-ugly-of-asp-net-identity/

    http://blogs.msdn.com/b/webdev/archive/2014/01/06/implementing-custom-password-policy-using-asp-net-identity.aspx

    Best Regards,

    Candice Zhou

    Tuesday, November 24, 2015 3:25 AM
  • User-1759553607 posted

    Thanks. I don't need the implementation of one, but where to inject my implementation of one ;)

    This used to be in UserManager, but that's far more complex now.

    I did this:

    services.AddScoped<IPasswordHasher<ApplicationUser>, MyPasswordHasher>();

    Which seems to work.. but I don't know if that's what I am supposed to do?

    Wednesday, November 25, 2015 12:51 AM
  • User614698185 posted

    Hi madmunsterdaddy,

    Yes, you could add this to Startup.cs:

    services.AddScoped<IPasswordHasher<IdentityUser>, MyPasswordHasher<IdentityUser>>(); 

    For more information, please see:

    http://stackoverflow.com/questions/26505446/how-use-custom-ipasswordhasher

    http://stackoverflow.com/questions/30453567/how-to-register-custom-userstore-usermanager-in-di

    http://aspnetguru.com/customize-authentication-to-your-own-set-of-tables-in-asp-net-mvc-5/

    Best Regards,

    Candice Zhou

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, November 25, 2015 6:42 AM