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 Identitynamespace 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?
The default password hasher for ASP.NET Core Identity uses PBKDF2 for password hashing. While PBKDF2 is not the worst choice, there are certainly better password hashing algorithms available to you, such as bcrypt, scrypt, and Argon2.
The app will create a hash of the password, and store it in the database along with the user's details. A hash is a one way function, so given the password you can work out the hash, but given the hash you can't get the original password back.
bcrypt has a fixed output size, which makes it less than perfect for generating encryption keys from passwords. That's the primary function of PBKDF2, while bcrypt is mostly used for simply comparing hashes.
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:
Microsoft.AspNet.Identity.PasswordHasher : IPasswordHasher
already salts for you, Rfc2898DeriveBytes
to generate the salt and the hash, Microsoft.AspNet.Identity.UserManager<TUser>
implementation uses Microsoft.AspNet.Identity.PasswordHasher
as a concrete IPasswordHasher
PasswordHasher
in turn is a really simple wrapper for (ultimately)System.Security.Cryptography.Rfc2898DeriveBytes
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With