36

The new ASP.net Identity project has brought some useful code and interfaces for website security. To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.

IPasswordHasher interface in ASP.net Identity

namespace Microsoft.AspNet.Identity
{
    public interface IPasswordHasher
    {
         string HashPassword(string password);
         PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword);
    }
}

Is it possible to use password salting for more secure encryption in ASP.net Identity and via this interface?

Community
  • 1
  • 1
Edward Wilson
  • 456
  • 1
  • 5
  • 8
  • 8
    Just salt the password before you pass it in. – James Nov 13 '13 at 15:07
  • Would the `string providedPassword` also need to be hashed? – Djeroen Dec 09 '15 at 14:28
  • Although they do offer ways to use your own hasher, it is strongly **not** recommended. Also, the default hasher already salts the password, otherwise hashing the same password twice would provide similar results. – Ioanna Aug 28 '18 at 14:05

3 Answers3

60

HEALTH WARNING for the below answer: Know which version of ASP.Net Identity you are using. You should refer to the source code directly if it is one of the newer versions from the github repository.

As I write this, the current version (3.0.0-rc1/.../PasswordHasher.cs) of the password handler is significantly different to the below answer. This newer version supports multiple hash algorithm versions and is documented as (and may change further by the time you read this):

Version 2:

  • PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
  • (See also: SDL crypto guidelines v5.1, Part III)
  • Format: { 0x00, salt, subkey }

Version 3:

  • PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
  • Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
  • (All UInt32s are stored big-endian.)

The original answer is still valid for the original version of ASP.Net Identity, and is as follows:


@jd4u is correct, but to shed a little more light which wouldn't fit into a comment for his answer:

So, if you are going to use Rfc2898DeriveBytes, just use PasswordHasher - all the heavy lifting is already done (hopefully correctly) for you.

Details

The full code that PasswordHasher (currently) ultimately uses does something very close to:

int saltSize = 16;
int bytesRequired = 32;
byte[] array = new byte[1 + saltSize + bytesRequired];
int iterations = SOME; // 1000, afaik, which is the min recommended for Rfc2898DeriveBytes
using (var pbkdf2 = new Rfc2898DeriveBytes(password, saltSize, iterations))
{
    byte[] salt = pbkdf2.Salt;        
    Buffer.BlockCopy(salt, 0, array, 1, saltSize);
    byte[] bytes = pbkdf2.GetBytes(bytesRequired);
    Buffer.BlockCopy(bytes, 0, array, saltSize+1, bytesRequired);
}
return Convert.ToBase64String(array);
Community
  • 1
  • 1
Andy Brown
  • 18,961
  • 3
  • 52
  • 62
  • Thank you!!! I needed a new method separate from user manager to create my hashed passwords and this worked perfectly – Steven Combs Aug 25 '14 at 00:25
  • 1
    This is the most useful explanation I found so far, a default hasher is embed on the framework so when I save a user I just do this var hash = new PasswordHasher().HashPassword(userViewModel.Password); var userAggregate = UserAggregate.Create(userViewModel.Username, userViewModel.Email, hash, DateTime.Now.ToString()); – Raffaeu Oct 14 '14 at 13:33
  • http://vimeo.com/97530814 Minute 58, Troy Hunt also says 1,000 hash iterations. – cdutcher Jan 02 '15 at 05:09
  • 1) It's a bad idea to use a 32 byte output with PBKDF2-HMAC-SHA1. Outputting more than the native size (20 bytes) slows down the defender by a factor 2 without slowing down the attacker at all. 2) 1000 iterations if a bit on the low side. – CodesInChaos Jan 16 '15 at 16:41
  • 2
    Here's how it looks like right now https://github.com/aspnet/Identity/blob/37d4e2b6ff3e64985f0fa7017108b164dce9233b/src/Microsoft.AspNet.Identity/PasswordHasher.cs It changed from what's described above https://github.com/aspnet/Identity/commit/37d4e2b6ff3e64985f0fa7017108b164dce9233b – Guy Apr 21 '16 at 04:15
  • Is Asp.net Identity using PBKDF2 to hash password? – Jeeva J Oct 12 '16 at 10:02
  • So, if I'm reading this answer (and source) correctly, the default password hasher for AspNet.Identity 2.0 uses PBKDF2-HMACSHA1 with 1,000 iterations. This is out of the box and I have to do nothing. Once I upgrade to Core, it will use version 3 which does HMACSHA256 at 10,000 iterations. It looks like you'll also be able to select which version you want, 2 or 3, and you'll be able to set the iterations via the PasswordHasher options constructor. Can someone just confirm this for me? – fujiiface Feb 16 '17 at 07:59
34

"Is it possible to use password salting for more secure encryption in ASP.net Identity and via this interface?"

Yes, the interface is provided for the new implementation of PasswordHasher already present in Core framework.

Also note that the default implementation is already using Salt+Bytes.

After creating custom PasswordHasher (say MyPasswordHasher), you can assign it to UserManager instance like userManager.PasswordHasher=new MyPasswordHasher()

See one example of such IPasswordHasher

To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.

For implementing alternate system from EF, - You shall implement all Core interfaces. - IPasswordHasher implementation is not required. PasswordHasher is already provided in Core framework as it's implementation.

Community
  • 1
  • 1
jd4u
  • 5,789
  • 2
  • 28
  • 28
9

I ran into an issue while updating from Membership to AspNet.Identity. The Rfc2898 hashes are different from those used before. That's for good reason, but changing the hashes would require all users to reset their passwords. As a solution this custom implementation makes it backwards compatible:

public class MyPasswordHasher : PasswordHasher {

   public FormsAuthPasswordFormat FormsAuthPasswordFormat { get; set; }

   public MyPasswordHasher(FormsAuthPasswordFormat format) {
      FormsAuthPasswordFormat = format;
   }

   public override string HashPassword(string password) {
      return FormsAuthentication.HashPasswordForStoringInConfigFile(password, FormsAuthPasswordFormat.ToString());
   }

   public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) {
     var testHash = FormsAuthentication.HashPasswordForStoringInConfigFile(providedPassword, FormsAuthPasswordFormat.ToString());
     return hashedPassword.Equals(testHash) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
   }
}

Once you create your UserManager instance just set the hasher:

Usermanager.PasswordHasher = new MyPasswordHasher(FormsAuthPasswordFormat.SHA1);

The code complains that the HashPasswordForStoringInConfigFile method is deprecated, but that's fine as we know that the whole exercise is to get rid of the old technology.

Joerg Krause
  • 1,759
  • 1
  • 16
  • 27
  • This is great. I have the same issue in that I want to migrate thousands of users from the Membership provider to the new ASP.Identity. I will give it a try. – agarcian Oct 18 '14 at 09:10
  • This is basically what I ended up doing also. I wanted to point out that your constructor name is incorrect (should be `MyPasswordHasher(...)`. For my implementation, I also update the user's password when logging in to use the new hashing functionality using some of the examples here: http://www.asp.net/identity/overview/migrations/migrating-an-existing-website-from-sql-membership-to-aspnet-identity – trnelson Mar 17 '15 at 12:02
  • I have fixed the copy and paste mistake. – Joerg Krause Mar 18 '15 at 14:01
  • I am trying to do the same but not succeed.. VerifyHashedPassword method first argument refer to the db table AspNetUsers column PasswordHash, right? What I would suppose to put in this column from the old membership column? Only password or password along with salt? – Ammar Khan Sep 29 '15 at 20:51