English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Default Implementation and Application of Microsoft.Identity.PasswordHasher Encryption in Asp.net

Those who are familiar with the MS Identity authentication system must know the role of UserManager. He is the scheduler in the entire system, defining a set of user behaviors to help us manage user information, role information, and handle passwords. Its implementation is in UserStore, where we can implement what we define, such as IUserStore, IUserPasswordStore, IRoleStore, etc. We can base on a set of user behaviors, customize our own user information, data structure, and data storage. So regarding the Password Hasher, MS still provides a complete behavior definition, and it is scheduled by UserManager. For example

UserManager.PasswordHasher.HashPassword(password)

The PasswordHasher is defined as follows in the UserManager interface:

I was originally not interested in its default implementation. For the purpose of independent login authentication of multiple applications, an independent user authentication project is needed as an authentication service, which only produces tokens. After successful authentication, the user's HTTP Request Header's Authorization carries the token to access various resources on the application server.

Due to this reason, such a problem has emerged in the password authentication of multiple applications:

For example, application A uses the IPasswordHasher interface to implement a custom encryption method——MD5+In the form of salt, while application B uses the default PasswordHasher provided by Identity to implement it, the following code is obtained by decompiling:

Therefore, in order to be compatible with different encryption methods used by various applications, I had to decompile the source code, obtain its default encryption method, and determine whether to encrypt or decrypt the password based on the different application names. First, let's look at the specific implementation of the MS default PasswordHasher.

// Decompiled with JetBrains decompiler
// Type: Microsoft.AspNet.Identity.Crypto
// Assembly: Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: E3A10FFD-023A-4BC3-AD53-32D145ABF1C9
// Assembly location: C:\Sport\NewProject\V2.0\Api\Fantasy.Sport\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
namespace Microsoft.AspNet.Identity
{
 internal static class Crypto
 {
 private const int PBKDF2IterCount = 1000;
 private const int PBKDF2SubkeyLength = 32;
 private const int SaltSize = 16;
 public static string HashPassword(string password)
 {
  if (password == null)
  throw new ArgumentNullException("password");
  byte[] salt;
  byte[] bytes;
  using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, 16, 1000))
  {
  salt = rfc2898DeriveBytes.Salt;
  bytes = rfc2898DeriveBytes.GetBytes(32);
  }
  byte[] inArray = new byte[49];
  Buffer.BlockCopy((Array) salt, 0, (Array) inArray, 1, 16);
  Buffer.BlockCopy((Array) bytes, 0, (Array) inArray, 17, 32);
  return Convert.ToBase64String(64String(inArray);
 }
 public static bool VerifyHashedPassword(string hashedPassword, string password)
 {
  if (hashedPassword == null)
  return false;
  if (password == null)
  throw new ArgumentNullException("password");
  byte[] numArray = Convert.FromBase64String(64String(hashedPassword);
  if (numArray.Length != 49 || (int) numArray[0] != 0)
  return false;
  byte[] salt = new byte[16];
  Buffer.BlockCopy((Array) numArray, 1, (Array) salt, 0, 16);
  byte[] a = new byte[32];
  Buffer.BlockCopy((Array) numArray, 17, (Array) a, 0, 32);
  byte[] bytes;
  using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, 1000))
  bytes = rfc2898DeriveBytes.GetBytes(32);
  return Crypto.ByteArraysEqual(a, bytes);
 }
 [MethodImpl(MethodImplOptions.NoOptimization)]
 private static bool ByteArraysEqual(byte[] a, byte[] b)
 {
  if (object.ReferenceEquals((object) a, (object) b))
  return true;
  if (a == null || b == null || a.Length != b.Length)
  return false;
  bool flag = true;
  for (int index = 0; index < a.Length; ++index)
  flag &= (int) a[index] == (int) b[index];
  return flag;
 }
 }
}

Someone might ask, how to apply these source codes. The following is a brief introduction to this issue.

At first, I naively thought it was just an encryption, no need to look carefully, just use it.

When registering users and changing passwords, the password encryption is done through the HashPassword method above. So in the new custom PasswordHasher, when comparing the user login password with the application B, why not directly encrypt the user input through HashPassword? So my custom VerifyHashedPassword (Verify means verify) method is to compare whether the Pwd in the database is equal to the result after the hasher process. However, the result is that the same string will produce different encryption results, just like playing with md before.5+The salt is different. So I thought of the default implementation of the VerifyHashedPassword method.

So what we need to say at the end is that you can directly use the encryption method of Microsoft Identity (the Hasher above) and use its VerifyHashedPassword() method when comparing the user input with the hashed storage result already stored in the database. You can also use this encryption algorithm even if you do not use Identity authentication.

That's all for this article. I hope the content of this article can bring some help to your learning or work, and I also hope to get more support for the Yelling Tutorial!

Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please send an email to codebox.com (replace # with @ when sending an email) to report any violations, and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.