`

C# 分层加密算法

    博客分类:
  • C#
阅读更多
使用PBKDF2算法方案,该算法是一个标准的密钥导出算法,可用于导出对称密钥, 应用PBKDF2的密钥导出函数主要是用来导出根秘钥(也叫初始密钥),然后用此根秘钥加密工作秘钥(工作秘钥由信息中心通过https传送给iRAD客户端或者其他安全通道预共享的方式传送给iRad客户端,用于记住密码功能中的加密)保存到本地。在使用PBKDF2导出根秘钥时,用到两个参数“初始向量”和“秘钥因子”, 为了满足合规要求,一是要求这两个参数都要随机生成(长度不少于128位或16字节);二是要求这两个参数分开存储,通常的做法时将初始向量数组(通过预设的随机运算——例如来自于openssl的安全随机数序列,然后产生初始向量数组)硬编码到代码中,而将秘钥因子(16进制)存储到配置文件中。

具体到利用PBKDF2算法(PKCS#5)来导出初始密钥的使用,这里提供一个参考:
计算公式为:DK  =  PBKDF2(Password, Salt, count, dkLen)
输入:
Password   :用户输入的口令或者读取的一串字符串,这里使用“密钥因子”。
Salt      :盐值,字符串,这里使用“初始向量”
count     :迭代次数,正整数,默认使用“50,000”次,华为要求不小于10000次
dkLen    :导出密钥的字节长度,正整数,该长度需根据应用程序或密码应用模块所需要的工作密钥长度来定义,以AES128加密算法为例,密钥长度为128bit,即16字节。
输出:
DK         :导出的密钥,长度为dkLen个字节的字符串。
Hash函数: 
优先使用HmacSHA256、HmacSHA384、HmacSHA512等强密码算法,如果是由于使用的加密库等方面的原因导致不支持相应的强密码算法,也可以使用HmacSHA1,但迭代次数(count)需定义为“100,000”次。





using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace TestPassword
{
    public class PasswordSecurity
    {
        class InvalidHashException : Exception
        {
            public InvalidHashException()
            {
            }

            public InvalidHashException(string message)
                : base(message)
            {
            }

            public InvalidHashException(string message, Exception inner)
                : base(message, inner)
            {
            }
        }

        class CannotPerformOperationException : Exception
        {
            public CannotPerformOperationException()
            {
            }

            public CannotPerformOperationException(string message)
                : base(message)
            {
            }

            public CannotPerformOperationException(string message, Exception inner)
                : base(message, inner)
            {
            }
        }

        public class PasswordStorage
        {
            // These constants may be changed without breaking existing hashes.
            public const int SALT_BYTES = 16;
            // The number of bytes of salt. By default, 24 bytes, which is 192 bits. This is more than enough. This constant should not be changed.

            public const int HASH_BYTES = 16;

            public const int PBKDF2_ITERATIONS = 100000; // PBKDF2 迭代次数,默认32000

            // These constants define the encoding and may not be changed.
            // 对应format: algorithm:iterations:hashSize:salt:hash 
            public const int HASH_ALGORITHM_INDEX = 0; // 加密方式所对应的索引,目前只支持sha1
            public const int ITERATION_INDEX = 1; // 迭代次数所对应的索引
            public const int HASH_SIZE_INDEX = 2; // hashsize所对应的索引
            public const int SALT_INDEX = 3; // salt值所对应的索引
            public const int PBKDF2_INDEX = 4; // hash值所对应的索引
            public const int HASH_SECTIONS = 5; // 总共存储几段数据;根据分隔符,对应 format中字段

            private const string HASH_ALGORITHM = "sha1"; // 加密方式,目前只支持sha1

            /// <summary>
            /// 创建hash+salt后的密码
            /// </summary>
            /// <param name="password">原始密码,比如abcdef</param>
            /// <returns></returns>
            public static string CreateHash(string password)
            {
                // Generate a random salt
                byte[] salt = new byte[SALT_BYTES];
                try
                {
                    using (RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider())
                    {
                        csprng.GetBytes(salt);
                    }
                }
                catch (CryptographicException ex)
                {
                    throw new CannotPerformOperationException("Random number generator not available.", ex);
                }
                catch (ArgumentNullException ex)
                {
                    throw new CannotPerformOperationException("Invalid argument given to random number generator.", ex);
                }

                byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTES);

                // format: algorithm:iterations:hashSize:salt:hash

                /*
                 *  algorithm is the name of the cryptographic hash function ("sha1").
                    iterations is the number of PBKDF2 iterations ("64000").
                    hashSize is the length, in bytes, of the hash field (after decoding).
                    salt is the salt, base64 encoded.
                    hash is the PBKDF2 output, base64 encoded. It must encode hashSize bytes.
                 * 
                 */

                return Convert.ToBase64String(hash);
                //return string.Format("{0}:{1}:{2}:{3}:{4}"
                //    , HASH_ALGORITHM
                //    , PBKDF2_ITERATIONS
                //    , hash.Length
                //    , Convert.ToBase64String(salt)
                //    , Convert.ToBase64String(hash));
            }

            /// <summary>
            /// 验证密码是否有效
            /// </summary>
            /// <param name="password">原始密码,比如abcdef</param>
            /// <param name="goodHash">已存的hash,从DB中读取;format: algorithm:iterations:hashSize:salt:hash</param>
            /// <returns></returns>
            public static bool VerifyPassword(string password, string goodHash)
            {
                char[] delimiter = { ':' };
                string[] split = goodHash.Split(delimiter);

                if (split.Length != HASH_SECTIONS)
                {
                    throw new InvalidHashException("Fields are missing from the password hash.");
                }

                // We only support SHA1 with C#.
                if (split[HASH_ALGORITHM_INDEX] != HASH_ALGORITHM)
                {
                    throw new CannotPerformOperationException("Unsupported hash type.");
                }

                int iterations = 0;
                try
                {
                    iterations = Int32.Parse(split[ITERATION_INDEX]);
                }
                catch (ArgumentNullException ex)
                {
                    throw new CannotPerformOperationException("Invalid argument given to Int32.Parse", ex);
                }
                catch (FormatException ex)
                {
                    throw new InvalidHashException("Could not parse the iteration count as an integer.", ex);
                }
                catch (OverflowException ex)
                {
                    throw new InvalidHashException("The iteration count is too large to be represented.", ex);
                }

                if (iterations < 1)
                {
                    throw new InvalidHashException("Invalid number of iterations. Must be >= 1.");
                }

                byte[] salt = null;
                try
                {
                    salt = Convert.FromBase64String(split[SALT_INDEX]);
                }
                catch (ArgumentNullException ex)
                {
                    throw new CannotPerformOperationException("Invalid argument given to Convert.FromBase64String", ex);
                }
                catch (FormatException ex)
                {
                    throw new InvalidHashException("Base64 decoding of salt failed.", ex);
                }

                byte[] hash = null;
                try
                {
                    hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
                }
                catch (ArgumentNullException ex)
                {
                    throw new CannotPerformOperationException("Invalid argument given to Convert.FromBase64String", ex);
                }
                catch (FormatException ex)
                {
                    throw new InvalidHashException("Base64 decoding of pbkdf2 output failed.", ex);
                }

                int storedHashSize = 0;
                try
                {
                    storedHashSize = Int32.Parse(split[HASH_SIZE_INDEX]);
                }
                catch (ArgumentNullException ex)
                {
                    throw new CannotPerformOperationException("Invalid argument given to Int32.Parse", ex);
                }
                catch (FormatException ex)
                {
                    throw new InvalidHashException("Could not parse the hash size as an integer.", ex);
                }
                catch (OverflowException ex)
                {
                    throw new InvalidHashException("The hash size is too large to be represented.", ex);
                }

                if (storedHashSize != hash.Length)
                {
                    throw new InvalidHashException("Hash length doesn't match stored hash length.");
                }

                byte[] testHash = PBKDF2(password, salt, iterations, hash.Length);
                return SlowEquals(hash, testHash);
            }

            private static bool SlowEquals(byte[] a, byte[] b)
            {
                uint diff = (uint)a.Length ^ (uint)b.Length;
                for (int i = 0; i < a.Length && i < b.Length; i++)
                {
                    diff |= (uint)(a[i] ^ b[i]);
                }
                return diff == 0;
            }

            private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
            {
                using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt))
                {
                    pbkdf2.IterationCount = iterations;
                    return pbkdf2.GetBytes(outputBytes);
                }
            }


            /// <summary>
            /// HMAC-SHA256 加密
            /// </summary>
            /// <param name="input"> 要加密的字符串 </param>
            /// <param name="key"> 密钥 </param>
            /// <param name="encoding"> 字符编码 </param>
            /// <returns></returns>
            public static string HMACSHA256Encrypt(string input, string key, Encoding encoding)
            {
                return HashEncrypt(new HMACSHA256(encoding.GetBytes(key)), input, encoding);
            }

            /// <summary>
            /// 哈希加密算法
            /// </summary>
            /// <param name="hashAlgorithm"> 所有加密哈希算法实现均必须从中派生的基类 </param>
            /// <param name="input"> 待加密的字符串 </param>
            /// <param name="encoding"> 字符编码 </param>
            /// <returns></returns>
            private static string HashEncrypt(HashAlgorithm hashAlgorithm, string input, Encoding encoding)
            {
                var data = hashAlgorithm.ComputeHash(encoding.GetBytes(input));

                return BitConverter.ToString(data).Replace("-", "");
            }
        }
    }
}

///生成根秘钥
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace TestPassword
{
    class Program
    {
        
        public Program()
        {

        }

        /// <summary>
        /// 加密字符串  
        /// </summary>
        /// <param name="rmd"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public string CharEncrypt(RootModel rmd, string str)
        {
            string strKey = string.Empty;
            //解密工作秘钥 (加密方式AES/CBC/ISO10126)
            string strWorkKey = AesHelper.AESDecryptNew(rmd.workKeyEcpt, rmd.rootKey, rmd.workKeyIV);

            //先UTF-8,BASE 64
            string EnStr = Convert.ToBase64String(Encoding.UTF8.GetBytes(str));

            //加密字符串
            strKey = AesHelper.AESEncrypt(EnStr, strWorkKey, RNGCSP.RNGGetRandom());

            if(!string.IsNullOrWhiteSpace(strKey))
            {
                strKey += "@" + RNGCSP.RNGGetRandom();
            }

            return strKey;
        }
        
        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="rmd"></param>
        /// <returns></returns>
        public string WorkDecrypt(RootModel rmd, string strDecrypt)
        {

            //解密工作秘钥 (加密方式AES/CBC/ISO10126)
            string strWorkKey= AesHelper.AESDecryptNew(rmd.workKeyEcpt, rmd.rootKey, rmd.workKeyIV);

            string strNew = string.Empty;

            if (!string.IsNullOrWhiteSpace(strDecrypt))
            {
                if(strDecrypt.Contains("@"))
                {
                    string[] arr = strDecrypt.Split('@');

                    if (arr.Length>1)
                    {
                        //解密字符串
                        strNew = AesHelper.AESDecryptNew(arr[0], strWorkKey, arr[1]);
                    }
                }
            }
           
            return  Encoding.UTF8.GetString(Convert.FromBase64String(strNew));

        }


        static void Main(string[] args)
        {

            Program pro = new Program();

            RootModel rm = new RootModel();
            //根密钥
            rm.rootKey = "M2UyYzQ0NmMwNjNjYTQ4OA==";
            //工作秘钥IV
            rm.workKeyIV = "mlJDbTEmDjBD/1xy6jBomg==";
            //工作秘钥加密后
            rm.workKeyEcpt = "3R8RaUxY1Fy7UJ8BvOdYbYxkL6fzdXaOfObdl21bxaI=";
            //解密字符串
            string strDecrypt = "EjwONCy04h0/AE3l+A4y9A==@Uz2VFravYLeG+oyqrFUS7w==";
            //解密字符串
            //string strChar = pro.WorkDecrypt(rm, strDecrypt);

            //加密字符串
            string strEnChar = pro.CharEncrypt(rm, "testpjf");

            Console.WriteLine(strEnChar);

            //string strChar = pro.WorkDecrypt(rm, strEnChar);

            ////生成根秘钥 初始向量、秘钥因子(字符串)
            byte[] RootKey = new byte[32];

            ////生成根密钥(PBDF2导出根密钥)
            string RootSecretKey = pro.EncodePassWord("M2UyYzQ0NmMwNjNjYTQ4OA==");


            Console.ReadKey();

        }

        public string EncodePassWord(string strPwd)
        {
            return PasswordSecurity.PasswordStorage.CreateHash(strPwd);
            // sha1:64000:18:ou2x9eUw82+dnxGetsTaNJLzLXiaElu8:7Ga+qwM4g8Bb/iPOfnQTd6HA
            // sha1:64000:18:8daBj8djNvUBLE5Y3vRTvMaooydwBfYg:EV9mmvk1oinBGPoufd3aQ85m
            //Assert.IsNotNull(hashPassword);

        }

        public bool decodePassWord(string strPwd,string strEncodePwd)
        {
            return PasswordSecurity.PasswordStorage.VerifyPassword(strPwd,strEncodePwd);
           // Assert.IsTrue(result);
        }
        
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestPassword
{
    using System;
    using System.IO;
    using System.Text;
    using System.Security.Cryptography;
    //生成随机数
    public class RNGCSP
    {
        private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
        private static int S_BYTES = 16;
        public static string RNGGetRandom()
        {
            string strResult=string.Empty;

            byte[] salt = new byte[S_BYTES];

            try
            {
                using (RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider())
                {
                    csprng.GetBytes(salt);
                }
            }
            catch (CryptographicException ex)
            {
                return null;
            }

            return Convert.ToBase64String(salt);

        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestPassword
{
    public class RootModel
    {
        /// <summary>
        /// 加密后根密钥
        /// </summary>
        public string rootKey { get; set; }

        /// <summary>
        /// 加密后工作秘钥
        /// </summary>
        public string workKeyEcpt { get; set; }

        /// <summary>
        /// 工作IV盐值
        /// </summary>

        public string workKeyIV { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace TestPassword
{
    public class AesHelper
    {

        /// <summary>
        /// AES加密 (128-ECB加密模式)
        /// </summary>
        /// <param name="toEncrypt">内容</param>
        /// <param name="key">秘钥</param>
        /// <returns></returns>
        public static string AESEncrypt(string toEncrypt, string key,string IV)
        {
            try
            {
                //
                byte[] keyArray = Convert.FromBase64String(key);

                byte[] toEncryptArray = Convert.FromBase64String(Convert.ToBase64String(Encoding.UTF8.GetBytes(toEncrypt)));

                byte[] IVArray = Convert.FromBase64String(IV);

                using (RijndaelManaged rDel = new RijndaelManaged())
                {
                    rDel.Key = keyArray;
                    rDel.IV = IVArray;
                    rDel.Mode = CipherMode.CBC;
                    rDel.Padding = PaddingMode.ISO10126;

                    ICryptoTransform cTransform = rDel.CreateEncryptor();

                    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

                    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
                }
            }
            catch 
            {
                return null;
            }
        }


        /// <summary>
        /// AES解密(128-ECB加密模式)
        /// </summary>
        /// <param name="toDecrypt">密文</param>
        /// <param name="key">秘钥(Base64String)</param>
        /// <returns></returns>
        public static string AESDecryptNew(string toDecrypt, string Rootkey,string IV)
        {
            try
            {
                byte[] RootkeyArray = Convert.FromBase64String(Rootkey); //128bit
                byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
                byte[] IVArray = Convert.FromBase64String(IV); //128bit

                using ( RijndaelManaged rDel = new RijndaelManaged())
                {
                    rDel.Key = RootkeyArray; //获取或设置对称算法的密钥
                    rDel.Mode = CipherMode.CBC; //获取或设置对称算法的运算模式,必须设置为CBC  
                    rDel.IV = IVArray;
                    rDel.Padding = PaddingMode.ISO10126; //获取或设置对称算法中使用的填充模式,必须设置为PKCS7  
                    ICryptoTransform cTransform = rDel.CreateDecryptor(); //用当前的 Key 属性和初始化向量 (IV) 创建对称解密器对象
                    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

                    return Convert.ToBase64String(resultArray);
                }
               
            }
            catch
            {
                return null;
            }
        }

       
    }
}


  • 大小: 31.1 KB
分享到:
评论

相关推荐

    十套c#面试题,基本包含了所有c#知识

    本资源摘要信息涵盖了 C# 面试题的方方面面,涵盖了 XML、XSD、XSL、J2EE、Persistent Object、加密算法、设计模式、架构设计、测试等多个方面的知识点。 XML、XSD、XSL 在面试题中,我们可以看到 XML、XSD、XSL ...

    门票销售C#源码

    C#提供了多种加密算法,如SHA256,可以用来保护用户的敏感信息。 9. **状态管理** 对于在线售票,需要跟踪用户的购物车状态,使用session或cookie来临时保存用户选择的票务信息。 10. **并发控制** 当多个用户...

    C#案例_医院管理系统

    1. 数据安全:C#提供了多种加密算法,如AES、RSA等,用于保护患者隐私和系统数据的安全。 2. 用户权限:通过角色权限模型,C#能够实现对不同用户访问系统功能的精细控制,确保系统操作的合法性。 四、异常处理与...

    大学生软件设计与规范及C#课程所有作业.zip

    用户登录系统则涉及到身份验证、密码加密等安全问题,这在现代软件系统中具有重要地位,需要掌握加密算法和会话管理等知识。 通过这些项目,学生不仅能够熟悉C#语言,还能接触到软件工程的全过程,包括需求分析、...

    c#SQL数据库课程设计 整合版

    C#将用于创建界面,而SQL数据库将用于存储和处理数据,可能还需要实现库存预测算法或库存优化策略。 4. **图书馆系统**: 图书馆系统涉及到书籍借阅、归还、查询和预订功能。C#将用于构建用户友好的界面,SQL...

    基于C#的智慧医疗健康评估系统源码.zip

    2. 健康评估:根据用户输入的健康数据,如生活习惯、病史等,运用算法进行评估,提供个性化健康建议。 3. 数据录入与查询:支持各类医疗数据的录入、修改和查询,方便医生和患者查看个人健康记录。 4. 预约挂号:...

    C# .net 图书馆管理系统~原创作品,带C#和SQL2005源码

    同时,为了保护用户信息的安全,密码通常会进行加密存储,例如使用SHA256等哈希算法。 在数据库设计方面,SQL Server 2005提供了可靠的数据存储和事务处理能力。系统可能包含多个表,如用户表(User)、图书表...

    编程项目实战+毕业项目+基于ASP.NET架构的RSA可视化算法程序的研究与实现

    整个工程分四层,实现RSA加密算法的C++核心类库、封装C++核心类库的DLL组件、引用DLL的.Net类、实现文件操作功能的.Net窗体应用程序。2.2节详细介绍各部分的设计与开发。 考虑到工作量,本软件加解密数据没有严格...

    C#系统项目参考-企业QQ系统

    - 加密解密:使用AES、RSA等算法保护敏感信息,如用户密码。 - 安全编码:遵循OWASP安全编码最佳实践,防止SQL注入、XSS攻击等安全威胁。 综上所述,企业QQ系统项目涉及了C#的多个核心技术和最佳实践,涵盖了从...

    C# 实现 手机零售商销售管理系统

    - **分层架构**:MPSMS采用了经典的三层架构设计,包括表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这样的设计保证了系统的模块化,易于维护和扩展。 - **MVC模式**:在UI层,我们采用了Model-View-...

    Expert C# 2008 Business Objects.pdf

    2. **数据加密**:介绍了常见的加密算法及其在保护敏感数据过程中的应用。 #### 六、部署与维护 1. **持续集成与持续部署**:介绍了持续集成和持续部署的概念及其对软件开发周期的影响。 2. **单元测试与代码覆盖率...

    C# 考试系统

    为了保证系统的安全,C#考试系统可能采用了加密技术保护数据,防止非法访问。此外,通过代码优化和数据库索引等方式,提高系统的运行效率和响应速度。 综上所述,【C# 考试系统】是龙运在线利用C#语言和技术栈构建...

    北京市国有控股企业热费负担信息系统C#

    系统可能采用了三层架构,包括表示层、业务逻辑层和数据访问层,以实现良好的分层设计和模块化。这样的架构使得系统更易于维护、扩展和升级。 1. 表示层:用户界面,负责与用户交互,如显示数据、接收用户输入等。 ...

    深入.Net平台软件系统分层开发

    《深入.Net平台软件系统分层开发》项目是一个全面探索基于.NET框架和C#语言的软件系统构建技术的实践性教学案例。在这个项目中,我们将会深入理解如何利用.NET平台的强大功能,采用分层架构来设计和实现高效、可扩展...

    C#学生成绩管理系统

    例如,系统可能使用哈希算法对用户密码进行加密存储,然后在登录时比较输入的密码与存储的哈希值,以判断用户身份。 角色管理和权限设置是系统安全性的关键。在该系统中,不同用户可能拥有不同的角色,如管理员、...

    个人财务管理系统设计说明书(完整版).doc

    采用加密算法保护用户数据,防止未经授权的访问和修改,同时提供数据备份功能,以防意外数据丢失。 7. 测试与维护 在开发过程中进行单元测试、集成测试和系统测试,确保系统稳定可靠。后期进行持续的维护更新,解决...

    图书馆管理信息系统

    C#支持加密算法,可以保护读者隐私和图书馆数据不被非法获取。 在开发图书馆管理信息系统时,通常会采用三层架构,即表示层、业务逻辑层和数据访问层。表示层负责用户交互,业务逻辑层处理业务规则,数据访问层则...

    C#小区物业管理系统附源码

    C#的数学运算能力和数据结构支持复杂费用算法的实现,同时,结合报表生成工具,可以自动生成账单和财务报表。 五、报修与服务请求 系统应具备报修功能,允许业主在线提交维修请求,物业人员接收到请求后进行处理。...

    SoEasyPlatform.rar

    此外,平台可能还实现了加密算法,保护敏感数据的安全,防止未授权访问。 六、性能优化与并发处理 在高并发场景下,SoEasyPlatform可能采用了异步编程模型,利用C#的async/await关键字,提高了系统的响应速度。...

Global site tag (gtag.js) - Google Analytics