Asp.Net Core Identity中IdentityUser对象的PasswordHash解析

PasswordHash的组成说明

(一) 概述

Asp.Net Core Identity中的IdentityUser表中,PasswordHash默认是一长串的Base64格式的字符串,目前版本称为V3,而Asp.Net Identity中的版本称为V2。

比如,在网页注册页面输入的密码Ss_123,可能生成的PasswordHash为:AQAAAAEAACcQAAAAEHfLUrXi8Zh9fMzc6PC4b0q1JzQYhMoVMlTUFtJnIuMhMKfuOqw+tVz/1pXg0jzHgg==

该string实际是代表61个字节的二进制数据的Base64格式,本质上是包括算法名称、Salt和Hash结果的字符串数据。解析如下:

(1)PasswordHash的数据格式分为V2版和V3版,其中V2版是Asp.net Identity中使用的,而V3版实在Asp.Net Core Identity中使用的,前者长度为49字节,后者长度为61字节。

(2)V3版本中,数据长度:61字节,即1+4+4+4+16+32=61,表示    “版本+算法类型+迭代次数+Salt长度+Salt数据+密码哈希结果  ”,其中版本的值为1,迭代次数的默认值为10000,Salt占用的字节长度默认为16,哈希值的默认长度为32。默认情况下,使用的算法为HMCASHA256。需要说明的是,算法类型、迭代次数、Salt长度均占据4个字节,按照Big-endian格式存放,与Intel CPU中的little-endian不同,因此需要使用这些数据的时候,需要进行转换。比如:Array.Reverse()方法可以对数组中存放的数据进行转换,另外Asp.Net Core Identity源码中使用的转换方式为:

//buffer的length应该等于4,然后通过移位与位或运算来将big-endian转换位little-endian       
 private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
        {
            return ((uint)(buffer[offset + 0]) << 24)
                | ((uint)(buffer[offset + 1]) << 16)
                | ((uint)(buffer[offset + 2]) << 8)
                | ((uint)(buffer[offset + 3]));
        }

 

(3)V2版本中:数据长度:49字节,1+16+32=49,表示    “版本+Salt+哈希值  ”,其中版本的值为0,Salt占用的字节长度为16,哈希值占用32直接。默认情况下,该版本的迭代次数为1000,默认算法为HMCASHA1,相应的Base64的长度为68.

(二)Hash算法

接着需要说明的是算法,生成Hash值的算法来自KeyDerivation类中的Pbkdf2方法,输入参数包括:原始密码,盐,算法,迭代次数,生成的Hash值的字节数。

            Console.Write("Enter a password: ");
            //需要进行Hash运算的原始密码
            string password = Console.ReadLine();

            // 产生随机的128位的Salt
            byte[] salt = new byte[128 / 8];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }
       
            // 生成256位的hash结果 (算法:HMACSHA256,迭代次数:10000,盐:salt数组)
            //注:numBytesRequested表示生成的Hash值的字节数
            string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
                password: password,
                salt: salt,
                prf: KeyDerivationPrf.HMACSHA256,
                iterationCount: 10000,
                numBytesRequested: 256 / 8));

            Console.WriteLine($"Hashed: {hashed}");

(三)测试

比如,当passwordhash值为“AQAAAAEAACcQAAAAEHfLUrXi8Zh9fMzc6PC4b0q1JzQYhMoVMlTUFtJnIuMhMKfuOqw+tVz/1pXg0jzHgg==”时(原始密码为Ss_123),则通过以下代码的计算,可以证实上面的说法。

//针对v3版本的测试
    Console.Write("Enter a password: ");    //此处输入Ss_123
            string password = Console.ReadLine();


            string passwordHashString= "AQAAAAEAACcQAAAAEHfLUrXi8Zh9fMzc6PC4b0q1JzQYhMoVMlTUFtJnIuMhMKfuOqw+tVz/1pXg0jzHgg==";
        
            byte[] hashpwd = Convert.FromBase64String(passwordHashString);

            byte version = hashpwd[0];
            byte[] count =hashpwd[5..9];  //迭代次数
            byte[] saltLen = hashpwd[9..13]; //盐长度,此处为big-endian存放的
            byte[] saltData = hashpwd[13..29];  //盐
            byte[] phash = hashpwd[29..61];     //hash值,又叫sub-key

            Array.Reverse(count);    //将big-endian转换为little-endian
            Array.Reverse(saltLen);  //将big-endian转换
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值