面向云技术架构 - 痴者工良

  • 首页
  • 工良写的电子书
    • Istio 入门教程
    • kubernetes 教程
    • 从 C# 入门 Kafka
    • 多线程和异步
    • 动态编程-反射、特性、AOP
    • 表达式树
  • 本站文章导航
  • 隐私政策
愿有人陪你颠沛流离
遇到能让你付出的事物或者人,都是一种运气。
能遇到,就该珍惜。或许你们最终没能在一起,但你会切实地感受到力量。
正因为这样,那段相遇才变得有价值,才没有辜负这世间的每一段相遇。
  1. 首页
  2. .NET
  3. 正文

C# pbkdf2 加密算法

2021年8月12日 1484点热度 0人点赞 0条评论
内容纲要

直接使用 .NET 的 CLR 库生成,不依赖第三方框架。
已将代码修正为最新实现,去掉过时接口。
基于密码的密钥导出函数2(PBKDF2)让别人更难通过穷举法猜到你的帐户密码。

pbkdf2 加密是不可逆的,因此可以用来处理密码等,只能对比,不能还原。

比如说,每个用户设置一个加密密钥,每个用户使用自己的密钥加密密码,且密码不可逆。
即使拿到一个用户的密码,破解了,每个用户的密钥都是不一样的,没法大规模爆破。

    /// <summary>
    /// Pbkdf2
    /// </summary>
    public static class Pbkdf2Helper
    {
        private const int SALT_SIZE = 128; // size in bytes,salt 的大小
        private const int HASH_SIZE = 128; // size in bytes,生成的哈希串的大小
        private const int ITERATIONS = 1000; // number of pbkdf2 iterations,表示循环次数

        #region 生成 Salt

        /// <summary>
        /// 随机生成 Salt,相当于生成密钥
        /// </summary>
        /// <returns></returns>
        public static byte[] CreateSalt()
        {
            // 生成盐
            RandomNumberGenerator provider = RandomNumberGenerator.Create();
            byte[] salt = new byte[SALT_SIZE];
            provider.GetBytes(salt);
            return salt;
        }

        /// <summary>
        /// 随机生成 Salt,相当于生成密钥,同时返回此密钥的字符串
        /// </summary>
        /// <param name="text">Salt 的字符串 表示</param>
        /// <returns></returns>
        public static byte[] CreateSalt(out string text)
        {
            // 生成盐
            RandomNumberGenerator provider = RandomNumberGenerator.Create();
            byte[] salt = new byte[SALT_SIZE];
            provider.GetBytes(salt);
            text = BitConverter.ToString(salt);
            return salt;
        }

        #endregion

        #region 加密

        /// <summary>
        /// 将一个字符串加密
        /// </summary>
        /// <param name="text">待加密的字符串</param>
        /// <param name="salt">盐</param>
        /// <returns></returns>
        public static string CreateHashString(string text, out byte[] salt)
        {
            salt = CreateSalt();
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(text, salt, ITERATIONS, HashAlgorithmName.SHA1);
            var bytes = pbkdf2.GetBytes(HASH_SIZE);

            return BitConverter.ToString(bytes);
        }

        /// <summary>
        /// 将一个字符串加密
        /// </summary>
        /// <param name="text">待加密的字符串</param>
        /// <param name="salt">盐</param>
        public static string CreateHashString(string text, out string salt)
        {
            var _salt = CreateSalt();
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(text, _salt, ITERATIONS, HashAlgorithmName.SHA1);
            var bytes = pbkdf2.GetBytes(HASH_SIZE);
            salt = BitConverter.ToString(_salt);
            return BitConverter.ToString(bytes);
        }

        /// <summary>
        /// 将一个字符串加密
        /// </summary>
        /// <param name="text">待加密的字符串</param>
        /// <param name="salt">盐</param>
        /// <returns></returns>
        public static string CreateHashString(string text, byte[] salt)
        {
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(text, salt, ITERATIONS, HashAlgorithmName.SHA1);
            var bytes = pbkdf2.GetBytes(HASH_SIZE);

            return BitConverter.ToString(bytes);
        }

        #endregion

        #region 验证

        /// <summary>
        /// 检查一个字符串是否与密文相同
        /// </summary>
        /// <param name="password">未加密的字符串</param>
        /// <param name="hashPassword">密文</param>
        /// <param name="salt">盐</param>
        /// <returns></returns>
        public static bool HashCheck(string password, string hashPassword, string salt)
        {
            // 还原 salt
            var chars = salt.Split('-').ToArray();
            var saltBytes = chars.Select(x => (byte)int.Parse(x, System.Globalization.NumberStyles.AllowHexSpecifier)).ToArray();
            return EqualHash(password, hashPassword, saltBytes);
        }

        /// <summary>
        /// 检查一个字符串是否与密文相同
        /// </summary>
        /// <param name="text">未加密的字符串</param>
        /// <param name="hash">密文</param>
        /// <param name="salt">盐</param>
        /// <returns></returns>
        public static bool EqualHash(string text, string hash, byte[] salt)
        {
            // 原文生成密文
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(text, salt, ITERATIONS,HashAlgorithmName.SHA1);
            var bytes = pbkdf2.GetBytes(HASH_SIZE);

            // 密文还原 byte
            var chars = hash.Split('-').ToArray();
            var hashBytes = chars.Select(x => (byte)int.Parse(x, System.Globalization.NumberStyles.AllowHexSpecifier)).ToArray();

            return EqualsBytes(bytes, hashBytes);
        }

        #endregion

        /// <summary>
        /// 判断两个字节数组是否相等
        /// </summary>
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <returns></returns>
        public static bool EqualsBytes(byte[] b1, byte[] b2)
        {
            return b1.AsSpan().SequenceEqual(b2.AsSpan());
        }

    // 转换 salt
    public static string ConvertSaltToString(byte[] salt)
    {
        return BitConverter.ToString(salt);
    }

    // 转换 salt
    public static byte[] ConvertSaltToBytes(string salt)
    {
        byte[] data = Array.ConvertAll<string, byte>(salt.Split("-"), c => Convert.ToByte(c, 16));
        return data;
    }
}
void Main()
{
    // 加密之后
    var a1 = Pbkdf2Helper.CreateHashString("aaa", out byte[] bytes);
    Console.WriteLine("a1 加密后:");
    Console.WriteLine(a1);

    // 密钥 byte[] 存储为字符串
    var str = Pbkdf2Helper.ConvertSaltToString(bytes);

    // 密钥 字符串 还原为 byte[]
    var bs = Pbkdf2Helper.ConvertSaltToBytes(str);

    // 使用相同的 salt 加密字符串
    var a2 = Pbkdf2Helper.CreateHashString("aaa", bs);
    Console.WriteLine("a2 加密后:");
    Console.WriteLine(a2);

    Console.WriteLine("a1 == a2 :");
    Console.WriteLine(a1 == a2);
    Console.WriteLine(Pbkdf2Helper.EqualHash("aaa", a1, bytes));
    Console.WriteLine(Pbkdf2Helper.EqualHash("aaa", a2, bs));
}

file

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: c clr linq net system
最后更新:2023年8月4日

痴者工良

高级程序员劝退师

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2023 whuanle.cn. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备18051778号

粤公网安备 44030902003257号