Asp.Net Core 密码加密方案

使用PBKDF2算法来创建哈希的方法。PBKDF2全称Password-Based Key Derivation Function,它的基本原理是通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,最终产生秘钥。如果重复的次数足够大,破解的成本将非常大。

PBKDF2定义如下

DK = PBKDF2(PRF, Password, Salt, c, dkLen)
  • PRF 是一个伪随机函数,可以简单的理解为 Hash 函数。
  • Password 表示口令 。
  • Salt 表示盐值,一个随机数。
  • c 表示迭代次数。
  • dkLen 表示最后输出的密钥长度。

    我们先引入NuGet包

    Install-Package Microsoft.AspNetCore.Cryptography.KeyDerivation -Version 3.1.6

    我们创建一个加密密码的方法,传入需要加密密码,和盐。参数的含义已经写在注释里了。

          private static string HashPassword(string value, string salt)
            {
                var valueBytes = KeyDerivation.Pbkdf2(
                    password: value,//密码
                    salt: Encoding.UTF8.GetBytes(salt),//盐
                    prf: KeyDerivationPrf.HMACSHA512,//伪随机函数,这里是SHA-512
                    iterationCount: 10000,//迭代次数
                    numBytesRequested: 256 / 8);//最后输出的秘钥长度
    
                return Convert.ToBase64String(valueBytes);
            }
    

    现在密码有了,还缺点盐,我们再写一个随机盐生成的方法。

       private  static string GenerateSalt()
            {
                byte[] randomBytes = new byte[128 / 8];
                using (var generator = RandomNumberGenerator.Create())
                {
                    generator.GetBytes(randomBytes);
                    return Convert.ToBase64String(randomBytes);
                }
            }
    

    好了,现在我们有了密码,有了盐,也有了加密好的hash值,那么用户登录的时候,如何校验密码是否正确呢,我们再写一个hash校验的方法。这时我们需要输入用户输入的密码,盐,以及生成好的hash值,就可以判断用户输入的密码是否正确了。

       private static bool Validate(string password, string salt, string hash)
                => HashPassword(password, salt) == hash;
    

    至此,内部的密码加密和校验部分已经完成了,但还有一个问题,就是创建用户密码的时候,如何存储的用户密码的hash值和盐呢,这里我采取使用“点”进行拼接存储,即使用salt.hash的形式,相应的,取值校验,再以“点”进行拆分。具体代码如下

            public static string HashPassword(string password)
            {
                var salt = GenerateSalt();
                var hash = HashPassword(password, salt);
                var result = $"{salt}.{hash}";
                Console.WriteLine("hash result:{0}", result);
                return result;
            }
    

    相应的,我们再提供一个对外的密码校验函数

           public static bool VerifyHashedPassword(string password, string storePassword)
            {
                if (string.IsNullOrEmpty(password))
                {
                    throw new ArgumentNullException(nameof(password));
                }
    
                if (string.IsNullOrEmpty(storePassword))
                {
                    throw new ArgumentNullException(nameof(storePassword));
                }
    
                var parts = storePassword.Split('.');
                var salt = parts[0];
                var hash = parts[1];
    
                return Validate(password, salt, hash); ;
            }
    

    至此,所有代码编写完成,我们下面来试试效果。

    我们输入一个简单的密码,1234,循环了5次,模拟5个用户都使用1234这个密码,我们看一下效果。

                var password = "1234";
    
                for (int i = 0; i < 5; i++)
                {
                    var result = PasswordHasher.HashPassword(password);
                    var right = PasswordHasher.VerifyHashedPassword(password, result);
                    Console.WriteLine("password is right:{0}", right);
                }
    

    可以看出这五条数据虽然拥有相同的密码,但是拥有不同的盐和hash值。

  • 完整的代码如下

  • public class PasswordHasher
        {
            private static string HashPassword(string value, string salt)
            {
                var valueBytes = KeyDerivation.Pbkdf2(
                    password: value,
                    salt: Encoding.UTF8.GetBytes(salt),
                    prf: KeyDerivationPrf.HMACSHA512,
                    iterationCount: 10000,
                    numBytesRequested: 256 / 8);
    
                return Convert.ToBase64String(valueBytes);
            }
            public static string HashPassword(string password)
            {
                var salt = GenerateSalt();
                var hash = HashPassword(password, salt);
                var result = $"{salt}.{hash}";
                Console.WriteLine("hash result:{0}", result);
                return result;
            }
    
            private static bool Validate(string password, string salt, string hash)
                => HashPassword(password, salt) == hash;
    
            public static bool VerifyHashedPassword(string password, string storePassword)
            {
                if (string.IsNullOrEmpty(password))
                {
                    throw new ArgumentNullException(nameof(password));
                }
    
                if (string.IsNullOrEmpty(storePassword))
                {
                    throw new ArgumentNullException(nameof(storePassword));
                }
    
                var parts = storePassword.Split('.');
                var salt = parts[0];
                var hash = parts[1];
    
                return Validate(password, salt, hash); ;
            }
    
            private static string GenerateSalt()
            {
                byte[] randomBytes = new byte[128 / 8];
                using (var generator = RandomNumberGenerator.Create())
                {
                    generator.GetBytes(randomBytes);
                    return Convert.ToBase64String(randomBytes);
                }
            }
    
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值