【C#】数据加密 、解密、登录验证

本文展示了如何使用CryptographyLib库来加密和解密用户密码,以及对信用卡号进行保护。通过盐值加盐哈希处理密码,使用RSA算法进行公钥/私钥操作,确保数据安全。此外,还涵盖了用户注册、密码检查和登录过程中的安全实践。
摘要由CSDN通过智能技术生成

消费者的卡号需要加密,密码需要salted 和 hashed.

密码学库:CryptographyLib

 User类

  public class User
  {
    public string Name { get; set; }
    public string Salt { get; set; }
    public string SaltedHashedPassword { get; set; }
    public string[] Roles { get; set; }
  }

Protector类:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Xml.Linq;
using static System.Convert;
using static System.Console;

namespace Packt.Shared
{
    public static class Protector
    {
        // salt大小必须至少为 8 个字节,我们将使用 16 个字节 size must be at least 8 bytes, we will use 16 bytes
        private static readonly byte[] salt =
      Encoding.Unicode.GetBytes("7BANANAS");//c#使用的是utf-16进行转码,单个字符占用2个字节

        // iterations should be high enough to take at least 100ms to 
        // generate a Key and IV on the target machine. 50,000 iterations
        // takes 131ms on my 3.3 GHz Dual-Core Intel Core i7 MacBook Pro.
        // 迭代次数应该足够高,至少需要 100 毫秒
        // 在目标机器上生成一个 Key 和 IV。 50,000 次迭代
        // 在我的 3.3 GHz 双核英特尔酷睿 i7 MacBook Pro 上耗时 131 毫秒。
        private static readonly int iterations = 50_000;
        //加密  明文+密码
        public static string Encrypt(
          string plainText, string password)
        {
            byte[] encryptedBytes;//加密的字节
            byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);//普通字节
            //创建用于执行对称算法的加密对象。
            var aes = Aes.Create(); // abstract class factory method

            var stopwatch = Stopwatch.StartNew();
            //使用密码、盐和派生密钥的迭代次数初始化 System.Security.Cryptography.Rfc2898DeriveBytes 类的新实例。
            var pbkdf2 = new Rfc2898DeriveBytes(
              password, salt, iterations);
            //返回此对象的伪随机密钥
            aes.Key = pbkdf2.GetBytes(32); // 设置 256 位密钥set a 256-bit key 
            //返回此对象的伪随机密钥。
            aes.IV = pbkdf2.GetBytes(16); // set a 128-bit IV 

            WriteLine("{0:N0} milliseconds to generate Key and IV using {1:N0} iterations.",
              arg0: stopwatch.ElapsedMilliseconds,
              arg1: iterations);

            using (var ms = new MemoryStream())//使用初始化为零的可扩展容量初始化 System.IO.MemoryStream 类的新实例。
            {   //CreateEncryptor 使用当前 System.Security.Cryptography.SymmetricAlgorithm.Key 创建对称加密器对象
                // 属性和初始化向量 (System.Security.Cryptography.SymmetricAlgorithm.IV)。
                using (var cs = new CryptoStream(
                  ms, aes.CreateEncryptor(), CryptoStreamMode.Write))//使用目标数据流、要使用的转换(对称加密对象)和流模式初始化 System.Security.Cryptography.CryptoStream 类的新实例
                {
                    cs.Write(plainBytes, 0, plainBytes.Length);
                }
                encryptedBytes = ms.ToArray();//加密的字节
            }

            return Convert.ToBase64String(encryptedBytes);
        }
        //解密 密文+密码
        public static string Decrypt(
          string cryptoText, string password)
        {
            byte[] plainBytes;//明文字节
            byte[] cryptoBytes = Convert.FromBase64String(cryptoText);//加密的字节

            var aes = Aes.Create();

            var pbkdf2 = new Rfc2898DeriveBytes(
              password, salt, iterations);

            aes.Key = pbkdf2.GetBytes(32);//秘钥
            aes.IV = pbkdf2.GetBytes(16);//初始化向量

            using (var ms = new MemoryStream())
            { //CreateDecryptor使用当前的 System.Security.Cryptography.SymmetricAlgorithm.Key 属性和初始化向量 (System.Security.Cryptography.SymmetricAlgorithm.IV) 创建对称解密器对象。
                using (var cs = new CryptoStream(
                  ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cryptoBytes, 0, cryptoBytes.Length);
                }
                plainBytes = ms.ToArray();
            }

            return Encoding.Unicode.GetString(plainBytes);
        }
        //用户字典
        private static Dictionary<string, User> Users =
          new Dictionary<string, User>();

        //注册  用户名+密码 +角色数组  .  不存储明文密码,存储salt和经过salt与hash计算的密码
        public static User Register(string username, string password,
          string[] roles = null)
        {
            // generate a random salt
            var rng = RandomNumberGenerator.Create();
            var saltBytes = new byte[16];
            rng.GetBytes(saltBytes);//生成随机字节数组
            var saltText = Convert.ToBase64String(saltBytes);//salt文本

            // generate the salted and hashed password 
            var saltedhashedPassword = SaltAndHashPassword(
              password, saltText);//经过salt和hash处理的密码

            var user = new User
            {
                Name = username,
                Salt = saltText, //salt
                SaltedHashedPassword = saltedhashedPassword,//经过salt和hash处理的密码
                Roles = roles
            };
            Users.Add(user.Name, user);

            return user;
        }

        // check a user's password that is stored
        // in the private static dictionary Users// 检查存储在私有静态字典 Users 中的用户密码
        public static bool CheckPassword(string username, string password)
        {
            if (!Users.ContainsKey(username))
            {
                return false;
            }

            var user = Users[username];

            return CheckPassword(username, password,
              user.Salt, user.SaltedHashedPassword);
        }

        // check a user's password using salt and hashed password
        //使用salt和hashed密码 检查用户密码
        public static bool CheckPassword(string username, string password,
          string salt, string hashedPassword)
        {
            // re-generate the salted and hashed password 
            var saltedhashedPassword = SaltAndHashPassword(
              password, salt);

            return (saltedhashedPassword == hashedPassword);
        }

        private static string SaltAndHashPassword(
          string password, string salt)
        {
            var sha = SHA256.Create();//创建 System.Security.Cryptography.SHA256 的默认实现的实例。
            var saltedPassword = password + salt;//
            //将 8 位无符号整数数组转换为使用 base-64 数字编码的等效字符串表示形式。
            return Convert.ToBase64String(
              sha.ComputeHash(Encoding.Unicode.GetBytes(saltedPassword)));
        }

        public static string PublicKey;//公钥
        //导出RSA参数到xml公钥
        public static string ToXmlStringExt(
          this RSA rsa, bool includePrivateParameters)
        {
            var p = rsa.ExportParameters(includePrivateParameters);//在派生类中重写时,导出 System.Security.Cryptography.RSAParameters。
            XElement xml;
            if (includePrivateParameters)
            {
                xml = new XElement("RSAKeyValue",
                  new XElement("Modulus", ToBase64String(p.Modulus)),
                  new XElement("Exponent", ToBase64String(p.Exponent)),
                  new XElement("P", ToBase64String(p.P)),
                  new XElement("Q", ToBase64String(p.Q)),
                  new XElement("DP", ToBase64String(p.DP)),
                  new XElement("DQ", ToBase64String(p.DQ)),
                  new XElement("InverseQ", ToBase64String(p.InverseQ)));
            }
            else
            {
                xml = new XElement("RSAKeyValue",
                  new XElement("Modulus", ToBase64String(p.Modulus)),
                  new XElement("Exponent", ToBase64String(p.Exponent)));
            }
            return xml?.ToString();
        }
        //从签名算法 参数xml导入RSA
        public static void FromXmlStringExt(
          this RSA rsa, string parametersAsXml)
        {
            var xml = XDocument.Parse(parametersAsXml);
            var root = xml.Element("RSAKeyValue");
            var p = new RSAParameters
            {
                Modulus = FromBase64String(root.Element("Modulus").Value),
                Exponent = FromBase64String(root.Element("Exponent").Value)
            };

            if (root.Element("P") != null)
            {
                p.P = FromBase64String(root.Element("P").Value);
                p.Q = FromBase64String(root.Element("Q").Value);
                p.DP = FromBase64String(root.Element("DP").Value);
                p.DQ = FromBase64String(root.Element("DQ").Value);
                p.InverseQ = FromBase64String(root.Element("InverseQ").Value);
            }
            rsa.ImportParameters(p);
        }
        //生成数据的签名   先SHA256加密数据
        public static string GenerateSignature(string data)
        {
            byte[] dataBytes = Encoding.Unicode.GetBytes(data);
            var sha = SHA256.Create();
            var hashedData = sha.ComputeHash(dataBytes);

            var rsa = RSA.Create();
            PublicKey = rsa.ToXmlStringExt(false); // exclude private key

            return ToBase64String(rsa.SignHash(hashedData,
              HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));//RSASignaturePadding指定用于 RSA 签名创建或验证操作的填充模式和参数。
        }
        //验证签名
        public static bool ValidateSignature(
          string data, string signature)
        {
            byte[] dataBytes = Encoding.Unicode.GetBytes(data);
            var sha = SHA256.Create();
            var hashedData = sha.ComputeHash(dataBytes);//数据的哈希值
            byte[] signatureBytes = FromBase64String(signature);//签名数据
            var rsa = RSA.Create();
            rsa.FromXmlStringExt(PublicKey);//导入RSA参数
            //验证哈希值
            return rsa.VerifyHash(hashedData, signatureBytes,
              HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }

        public static byte[] GetRandomKeyOrIV(int size)
        {
            var r = RandomNumberGenerator.Create();
            var data = new byte[size];
            r.GetNonZeroBytes(data);
            // data is an array now filled with 
            // cryptographically strong random bytes·
            return data;
        }

        public static void LogIn(string username, string password)
        {
            if (CheckPassword(username, password))//用户名 密码验证通过
            {//初始化 System.Security.Principal.GenericIdentity 类的新实例,表示具有指定名称和身份验证类型的用户。
                var identity = new GenericIdentity(username, "PacktAuth");//用户标识:用户名,类型
                //从用户标识和由该标识表示的用户所属的角色名称数组初始化 System.Security.Principal.GenericPrincipal 类的新实例。
                var principal = new GenericPrincipal(
                  identity, Users[username].Roles);

                System.Threading.Thread.CurrentPrincipal = principal;
            }
        }
    }
}

加密Customer数据到xml

<?xml version="1.0" encoding="utf-8"?>
<customers>
  <customer>
    <name>Bob Smith</name>
    <creditcard>EBLUHQBllivoCz84FU5XSM2XoTV7/VYbfnTjUgyKEEDdKsdBMGpTW8lfK2MmXLDJ</creditcard>
    <password>Di5ZcpkcsZtPvJzJs2+b8A+4rrRTl7ooftVJuhKHww0=</password>
    <salt>tYVQ3jSWp9rlS2bmwQ5ZFQ==</salt>
  </customer>
  <customer>
    <name>Leslie Knope</name>
    <creditcard>B6hEivJ6px9gKLZKIaZs0XKEsHRU/cKxWkzOBGv65IitaaJ/ZhJwbYJ8mclfEaX9</creditcard>
    <password>6DbBMIAHDQ3idps1UXnP5RSJZfoEuSBlbToR+XdXnWM=</password>
    <salt>EyxXnlgL55y6KDw/0jEFuw==</salt>
  </customer>
</customers>

Customer类:

  public class Customer
  {
    public string Name { get; set; }
    public string CreditCard { get; set; }
    public string Password { get; set; }
    public string Salt { get; set; }
  }

加密卡号:

using System.Collections.Generic;
using System.IO;
using System.Xml;
using Packt.Shared;
using static System.Console;
using static System.IO.Path;
using static System.Environment;

namespace Exercise02
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("您必须输入密码才能加密文档中的敏感数据.");
            WriteLine("稍后您必须输入相同的密码才能解密文档.");
            Write("Password: ");
            string password = ReadLine();

            // define two example customers and
            // note they have the same password
            var customers = new List<Customer>
      {
        new Customer
        {
          Name = "Bob Smith",
          CreditCard = "1234-5678-9012-3456",
          Password = "Pa$$w0rd",
        },
        new Customer
        {
          Name = "Leslie Knope",
          CreditCard = "8002-5265-3400-2511",
          Password = "Pa$$w0rd",
        }
      };

            //定义要写入的 XML 文件 define an XML file to write to
            string xmlFile = Combine(CurrentDirectory,
        "..", "protected-customers.xml");

            var xmlWriter = XmlWriter.Create(xmlFile,
              new XmlWriterSettings { Indent = true });//Indent 获取或设置一个值,该值指示是否缩进元素。

            xmlWriter.WriteStartDocument();

            xmlWriter.WriteStartElement("customers");

            foreach (var customer in customers)
            {
                xmlWriter.WriteStartElement("customer");
                xmlWriter.WriteElementString("name", customer.Name);

                // to protect the credit card number we must encrypt it
                xmlWriter.WriteElementString("creditcard",
                  Protector.Encrypt(customer.CreditCard, password));

                // to protect the password we must salt and hash it
                // and we must store the random salt used
                var user = Protector.Register(customer.Name, customer.Password);
                xmlWriter.WriteElementString("password", user.SaltedHashedPassword);
                xmlWriter.WriteElementString("salt", user.Salt);

                xmlWriter.WriteEndElement();
            }
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndDocument();
            xmlWriter.Close();

            WriteLine();
            WriteLine("Contents of the protected file:");
            WriteLine();
            WriteLine(File.ReadAllText(xmlFile));
        }
    }
}

 

解密卡号并登录

using System.Collections.Generic;
using System.IO;
using System.Xml;
using Packt.Shared;
using static System.Console;
using static System.IO.Path;
using static System.Environment;
using System.Security.Cryptography;

namespace Exercise03
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("You must enter the correct password to decrypt the document.");
            Write("Password: ");
            string password = ReadLine();//加密密码

            var customers = new List<Customer>();

            // define an XML file to read from
            string xmlFile = Combine(CurrentDirectory,
              "..", "protected-customers.xml");

            if (!File.Exists(xmlFile))
            {
                WriteLine($"{xmlFile} does not exist!");
                return;
            }

            var xmlReader = XmlReader.Create(xmlFile,
              new XmlReaderSettings { IgnoreWhitespace = true });//获取或设置一个值,该值指示是否忽略无关紧要的空白。
            //读取xml
            while (xmlReader.Read())
            {
                if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "customer")
                {
                    xmlReader.Read(); // move to <name>
                    string name = xmlReader.ReadElementContentAsString();
                    string creditcardEncrypted = xmlReader.ReadElementContentAsString();
                    string creditcard = null;
                    string errorMessage = null;
                    try
                    {
                        creditcard = Protector.Decrypt(creditcardEncrypted, password);//解密卡号
                    }
                    catch (CryptographicException)
                    {
                        errorMessage = $"Failed to decrypt {name}'s credit card.";
                    }
                    string passwordHashed = xmlReader.ReadElementContentAsString();//SaltedHashedPassword
                    string salt = xmlReader.ReadElementContentAsString();

                    customers.Add(new Customer
                    {
                        Name = name,
                        CreditCard = creditcard ?? errorMessage,
                        Password = passwordHashed,
                        Salt = salt
                    });
                }
            }

            xmlReader.Close();

            WriteLine();
            int number = 0;
            WriteLine("    {0,-20} {1,-20}",
              arg0: "Name",
              arg1: "Credit Card");

            foreach (var customer in customers)
            {
                WriteLine("[{0}] {1,-20} {2,-20}",
                  arg0: number,
                  arg1: customer.Name,
                  arg2: customer.CreditCard);

                number++;
            }
            WriteLine();

            Write("Press the number of a customer to log in as: ");
            //登录
            string customerName = null;
            try
            {
                number = int.Parse(ReadKey().KeyChar.ToString());
                customerName = customers[number].Name;
            }
            catch
            {
                WriteLine();
                WriteLine("Not a valid customer selection.");
                return;
            }

            WriteLine();
            Write($"Enter {customerName}'s password: ");

            string attemptPassword = ReadLine();
            //验证登录密码
            if (Protector.CheckPassword(
              username: customers[number].Name,
              password: attemptPassword,
              salt: customers[number].Salt,
              hashedPassword: customers[number].Password))
            {
                WriteLine("Correct!");
            }
            else
            {
                WriteLine("Wrong!");
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值