VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#网络编程之加密与解密(对称加密、非对称加密、哈希算法)

第17章 加密与解密
17.1 加密与解密(对称加密、非对称加密、哈希算法)
一、为什么要搞加密?我踩过的“明文裸奔坑”
刚做第一个项目时,把用户密码明文存在数据库里——结果服务器被黑,用户密码全泄露,赔了用户钱不说,公司信誉也毁了。后来改成用SHA256加盐哈希存储密码,再用AES加密用户的敏感数据(比如银行卡号),用RSA签名防止数据被篡改,再也没出过安全问题。这节我把自己vb.net教程C#教程python教程SQL教程access 2010教程从“明文裸奔”到“加密防护”的踩坑经验揉进去,用大白话讲透三种核心加密方式:对称加密、非对称加密、哈希算法,结合C#代码逐行讲解实战用法,以及加密的最佳实践,让你的网络程序像银行系统一样安全。
二、对称加密:“一把钥匙开一把锁”,适合大数据传输
对称加密是用同一把密钥加密和解密数据——加密速度快,适合处理大数据,比如大文件传输、实时视频流。常见的对称加密算法有AES、DES、3DES,其中AES是现在的标准,DES和3DES已经被淘汰(不安全)。
类比:对称加密就像你用一把锁把文件锁起来,把钥匙给朋友,朋友用同一把钥匙打开——速度快,但钥匙不能丢,否则别人拿到钥匙就能打开文件。

  1. C#实战:用AES加密和解密大文件,避免内存拷贝
    示例:用AES-256-GCM加密1GB的大文件,边读边加密,避免把整个文件读到内存里:
    csharp
	using System;
	using System.IO;
	using System.Security.Cryptography;
	
	namespace SymmetricEncryptionDemo;
	
	class Program
	{
	static void Main(string[] args)
	{
	string inputFilePath = @"C:	estGB.file";
	string encryptedFilePath = @"C:	estGB.encrypted";
	string decryptedFilePath = @"C:	estGB.decrypted";
	
	// 生成AES密钥和IV(初始化向量),注意:密钥和IV要保存好,解密时需要
	using var aes = Aes.Create();
	aes.KeySize = 256; // AES-256,安全级别最高
	aes.Mode = CipherMode.GCM; // GCM模式,支持AEAD(认证加密带关联数据),同时保证加密和完整性
	aes.GenerateKey();
	aes.GenerateIV();
	
	try
	{
	// 加密文件
	EncryptFile(inputFilePath, encryptedFilePath, aes.Key, aes.IV);
	Console.WriteLine("文件加密完成");
	
	// 解密文件
	DecryptFile(encryptedFilePath, decryptedFilePath, aes.Key, aes.IV);
	Console.WriteLine("文件解密完成");
	}
	catch (Exception ex)
	{
	Console.WriteLine($"加密/解密失败:{ex.Message}");
	}
	}
	
	/// <summary>
	/// 用AES加密文件,边读边加密,避免内存拷贝
	/// </summary>
	static void EncryptFile(string inputPath, string outputPath, byte[] key, byte[] iv)
	{
	using var inputStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
	using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
	// 写入IV到输出文件开头,解密时需要用IV
	outputStream.Write(iv, 0, iv.Length);
	
	// 创建AES加密器
	using var aes = Aes.Create();
	aes.Key = key;
	aes.IV = iv;
	aes.Mode = CipherMode.GCM;
	using var encryptor = aes.CreateEncryptor();
	// 创建CryptoStream,把输入流加密后写到输出流
	using var cryptoStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);
	
	// 用Span<byte>边读边加密,避免内存拷贝
	var buffer = new byte[1024 * 1024]; // 1MB缓冲区
	int bytesRead;
	while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
	{
	var span = buffer.AsSpan(0, bytesRead);
	cryptoStream.Write(span);
	}
	
	// GCM模式需要写入认证标签,验证数据完整性
	if (encryptor is ICryptoTransform transform && transform is IGcmTransform gcmTransform)
	{
	var tag = gcmTransform.Tag;
	outputStream.Write(tag, 0, tag.Length);
	}
	}
	
	/// <summary>
	/// 用AES解密文件,边读边解密,避免内存拷贝
	/// </summary>
	static void DecryptFile(string inputPath, string outputPath, byte[] key, byte[] iv)
	{
	using var inputStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
	using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
	
	// 从输入文件开头读取IV
	var readIv = new byte[iv.Length];
	inputStream.Read(readIv, 0, readIv.Length);
	
	// 创建AES解密器
	using var aes = Aes.Create();
	aes.Key = key;
	aes.IV = readIv;
	aes.Mode = CipherMode.GCM;
	using var decryptor = aes.CreateDecryptor();
	// 创建CryptoStream,把输入流解密后写到输出流
	using var cryptoStream = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);
	
	// 用Span<byte>边读边解密,避免内存拷贝
	var buffer = new byte[1024 * 1024];
	int bytesRead;
	while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
	{
	var span = buffer.AsSpan(0, bytesRead);
	outputStream.Write(span);
	}
	
	// GCM模式需要验证认证标签,防止数据被篡改
	if (decryptor is ICryptoTransform transform && transform is IGcmTransform gcmTransform)
	{
	var tag = new byte[16]; // GCM标签长度固定16字节
	inputStream.Read(tag, 0, tag.Length);
	gcmTransform.Tag = tag;
	}
	}
	}
  1. 代码逐行讲解
    1.Aes.Create():创建AES实例,自动选择系统中最快的AES实现(硬件加速);
    2.KeySize = 256:使用AES-256,密钥长度256位,安全级别最高(AES有128、192、256三种密钥长度);
    3.Mode = CipherMode.GCM:使用GCM模式,支持AEAD(认证加密带关联数据)——同时保证数据加密和完整性,防止数据被篡改;
    4.GenerateKey()/GenerateIV():生成随机密钥和IV——IV是初始化向量,用于保证相同的密钥加密相同的数据得到不同的密文,防止模式识别攻击;
    5.CryptoStream:把输入流加密/解密后写到输出流,边读边处理,避免把整个文件读到内存里;
    6.IGcmTransform.Tag:GCM模式的认证标签,解密时需要验证标签,防止数据被篡改——如果数据被篡改,解密时会抛出CryptographicException。
  2. 对称加密的常见坑与注意事项
    不要用ECB模式:ECB模式是不安全的,相同的明文会得到相同的密文,容易被破解——必须用CBC、GCM、CTR等模式;
    IV要随机:IV不能固定,必须每次加密都用随机的IV,否则相同的密钥加密相同的数据会得到相同的密文;
    密钥要安全存储:密钥不能硬编码在代码里,要存在环境变量、密钥管理服务(KMS)、Windows证书存储里;
    大文件用流处理:不要把整个文件读到内存里,用边读边加密的方式,避免内存溢出。
    三、非对称加密:“公钥加密私钥解密”,适合密钥交换和签名
    非对称加密用一对密钥:公钥(公开)和私钥(保密)——公钥加密的数据只能用私钥解密,私钥签名的数据只能用公钥验证。加密速度慢,适合小数据,比如密钥交换、数字签名。常见的非对称加密算法有RSA、ECC(椭圆曲线加密),其中ECC比RSA更安全,密钥长度更短(256位ECC相当于3072位RSA)。
    类比:非对称加密就像你有一个邮箱,任何人都可以用公钥(邮箱地址)给你发邮件(加密数据),只有你能用私钥(邮箱密码)打开邮件(解密数据);你用私钥签名的邮件(数字签名),任何人都可以用公钥验证是不是你发的。
  3. C#实战:用RSA实现密钥交换和数字签名
    示例:生成RSA密钥对,用公钥加密对称密钥,用私钥解密;用私钥签名数据,用公钥验证签名:
    csharp
	using System;
	using System.Security.Cryptography;
	using System.Text;
	
	namespace AsymmetricEncryptionDemo;
	
	class Program
	{
	static void Main(string[] args)
	{
	// 生成RSA密钥对(2048位,安全级别足够)
	using var rsa = RSA.Create(2048);
	// 导出公钥(可以公开)
	string publicKey = rsa.ToXmlString(includePrivateParameters: false);
	// 导出私钥(必须保密)
	string privateKey = rsa.ToXmlString(includePrivateParameters: true);
	
	Console.WriteLine("公钥:");
	Console.WriteLine(publicKey);
	Console.WriteLine("
私钥:");
	Console.WriteLine(privateKey);
	
	// 1. 密钥交换:用公钥加密对称密钥,用私钥解密
	var aesKey = new byte[32]; // AES-256密钥
	RandomNumberGenerator.Fill(aesKey);
	Console.WriteLine("
原始AES密钥:");
	Console.WriteLine(Convert.ToBase64String(aesKey));
	
	// 用公钥加密AES密钥
	byte[] encryptedAesKey = rsa.Encrypt(aesKey, RSAEncryptionPadding.OaepSHA256);
	Console.WriteLine("
加密后的AES密钥:");
	Console.WriteLine(Convert.ToBase64String(encryptedAesKey));
	
	// 用私钥解密AES密钥
	byte[] decryptedAesKey = rsa.Decrypt(encryptedAesKey, RSAEncryptionPadding.OaepSHA256);
	Console.WriteLine("
解密后的AES密钥:");
	Console.WriteLine(Convert.ToBase64String(decryptedAesKey));
	
	// 2. 数字签名:用私钥签名数据,用公钥验证签名
	string data = "这是要签名的数据,防止被篡改";
	byte[] dataBytes = Encoding.UTF8.GetBytes(data);
	
	// 用私钥签名数据
	byte[] signature = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
	Console.WriteLine("
数字签名:");
	Console.WriteLine(Convert.ToBase64String(signature));
	
	// 用公钥验证签名
	bool isSignatureValid = rsa.VerifyData(dataBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
	Console.WriteLine("
签名验证结果:" + (isSignatureValid ? "有效" : "无效"));
	}
	}
  1. 代码逐行讲解
    1.RSA.Create(2048):生成2048位的RSA密钥对——2048位是现在的安全标准,1024位已经不安全;
    2.ToXmlString:导出公钥和私钥——includePrivateParameters: false导出公钥,true导出私钥;
    3.Encrypt/Decrypt:用公钥加密,私钥解密——RSAEncryptionPadding.OaepSHA256是安全的填充方式,比PKCS#1 v1.5更安全;
    4.SignData/VerifyData:用私钥签名,公钥验证——HashAlgorithmName.SHA256是哈希算法,RSASignaturePadding.Pss是安全的签名填充方式;
    5.RandomNumberGenerator.Fill:生成随机的AES密钥——不要用Random类生成密钥,Random是伪随机,不安全,必须用RandomNumberGenerator(真随机)。
  2. 非对称加密的常见坑与注意事项
    不要用非对称加密加密大数据:非对称加密速度慢,适合加密对称密钥(比如AES密钥),然后用对称加密传输大数据——这就是HTTPS的混合加密方式;
    私钥要绝对保密:私钥不能泄露,否则别人可以用私钥解密数据、伪造签名;
    用安全的填充方式:加密用OaepSHA256,签名用Pss,不要用PKCS#1 v1.5(已经被破解);
    ECC比RSA更高效:如果支持的话,优先用ECC(椭圆曲线加密)——256位ECC的安全级别相当于3072位RSA,密钥长度更短,加密解密速度更快。
    四、哈希算法:“不可逆的指纹”,适合数据校验和密码存储
    哈希算法是把任意长度的数据转换成定长的哈希值——不可逆(不能从哈希值还原原始数据)、唯一(不同的数据得到不同的哈希值)、定长(不管输入多大,哈希值长度固定)。适合存储密码、校验数据完整性、生成数字签名。常见的哈希算法有SHA256、SHA512、MD5(已经被淘汰,不安全)、SHA1(已经被淘汰,不安全)。
    类比:哈希算法就像给数据拍一张“指纹照片”——不管数据多大,指纹都是固定长度的,不能从指纹还原数据,但是可以用指纹验证数据有没有被篡改。
  3. C#实战:用SHA256计算文件哈希,用加盐哈希存储密码
    示例1:计算1GB大文件的SHA256哈希,边读边计算,避免把整个文件读到内存里:
    csharp
	using System;
	using System.IO;
	using System.Security.Cryptography;
	
	namespace HashDemo;
	
	class Program
	{
	static void Main(string[] args)
	{
	string filePath = @"C:	estGB.file";
	string hash = CalculateFileHash(filePath, HashAlgorithmName.SHA256);
	Console.WriteLine($"文件SHA256哈希:{hash}");
	}
	
	static string CalculateFileHash(string filePath, HashAlgorithmName hashAlgorithm)
	{
	using var hashAlgorithm = HashAlgorithm.Create(hashAlgorithm.Name);
	using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
	
	// 用Span<byte>边读边计算哈希,避免内存拷贝
	var buffer = new byte[1024 * 1024];
	int bytesRead;
	while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
	{
	var span = buffer.AsSpan(0, bytesRead);
	hashAlgorithm.TransformBlock(span, 0, span.Length, span, 0);
	}
	hashAlgorithm.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
	
	return BitConverter.ToString(hashAlgorithm.Hash).Replace("-", "").ToLower();
	}
	}

示例2:用加盐哈希存储密码,防止彩虹表攻击:
csharp

	using System;
	using System.Security.Cryptography;
	using System.Text;
	
	namespace PasswordHashDemo;
	
	class Program
	{
	static void Main(string[] args)
	{
	string password = "MySecurePassword123!";
	// 生成加盐哈希
	string hashedPassword = HashPassword(password);
	Console.WriteLine("加盐哈希后的密码:");
	Console.WriteLine(hashedPassword);
	
	// 验证密码
	bool isPasswordValid = VerifyPassword(password, hashedPassword);
	Console.WriteLine("
密码验证结果:" + (isPasswordValid ? "正确" : "错误"));
	}
	
	static string HashPassword(string password)
	{
	// 生成随机盐(16字节)
	byte[] salt = new byte[16];
	RandomNumberGenerator.Fill(salt);
	// 用Rfc2898DeriveBytes生成加盐哈希,迭代次数100000次(越高越安全,性能越低)
	var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000, HashAlgorithmName.SHA256);
	byte[] hash = pbkdf2.GetBytes(32); // 32字节哈希值
	
	// 把盐和哈希值存在一起,用冒号分隔
	return $"{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}";
	}
	
	static bool VerifyPassword(string password, string hashedPassword)
	{
	// 拆分盐和哈希值
	string[] parts = hashedPassword.Split(':');
	if (parts.Length != 2)
	return false;
	
	byte[] salt = Convert.FromBase64String(parts[0]);
	byte[] hash = Convert.FromBase64String(parts[1]);
	
	// 用相同的盐和迭代次数生成哈希值
	var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000, HashAlgorithmName.SHA256);
	byte[] computedHash = pbkdf2.GetBytes(32);
	
	// 比较哈希值(用Span<byte>比较,避免内存拷贝)
	return computedHash.AsSpan().SequenceEqual(hash.AsSpan());
	}
	}
  1. 代码逐行讲解
    文件哈希部分:
    1.HashAlgorithm.Create:创建哈希算法实例,支持SHA256、SHA512等;
    2.TransformBlock/TransformFinalBlock:边读边计算哈希,避免把整个文件读到内存里——TransformBlock处理部分数据,TransformFinalBlock处理最后一部分数据;
    3.BitConverter.ToString:把哈希值转换成十六进制字符串,方便存储和展示。
    密码哈希部分:
    1.Rfc2898DeriveBytes:基于PBKDF2算法生成加盐哈希——迭代次数越高,破解难度越大,一般设置100000次以上;
    2.盐(Salt):随机生成的16字节数据,每个用户的盐都不一样,防止彩虹表攻击——彩虹表是预计算的哈希值表,加盐后每个用户的哈希值都不一样,彩虹表就没用了;
    3.SequenceEqual:用Span比较哈希值,避免内存拷贝,性能更高。
  2. 哈希算法的常见坑与注意事项
    不要直接存储哈希值:必须加盐(Salt),否则容易被彩虹表攻击;
    不要用MD5和SHA1:MD5和SHA1已经被破解,不安全,必须用SHA256、SHA512等;
    哈希算法不可逆:不能从哈希值还原原始数据,所以适合存储密码,不适合加密需要解密的数据;
    用RandomNumberGenerator生成盐:不要用Random类生成盐,Random是伪随机,不安全,必须用RandomNumberGenerator。
    五、三种加密方式的对比与最佳实践
加密方式 核心特性 适用场景 常见算法 性能
对称加密 同一密钥加密解密 大数据传输、文件加密 AES-256-GCM 快
非对称加密 公钥加密私钥解密,签名验证 密钥交换、数字签名、身份认证 RSA-2048、ECC-256 慢
哈希算法 不可逆、唯一、定长 数据校验、密码存储、数字签名 SHA256、SHA512 快

最佳实践:
1.混合加密:用非对称加密交换对称密钥,用对称加密传输大数据——这就是HTTPS的加密方式;
2.密码存储:用加盐哈希(PBKDF2、Argon2)存储密码,不要直接存储明文或哈希值;
3.数据完整性:用哈希算法或GCM模式验证数据完整性,防止数据被篡改;
4.密钥管理:密钥要安全存储,不要硬编码在代码里,用密钥管理服务(KMS)、Windows证书存储、环境变量存储密钥。
六、总结:加密是网络安全的“第一道防线”
对称加密是“快马”,适合大数据传输,用AES-256-GCM;
非对称加密是“信使”,适合密钥交换和签名,用RSA-2048或ECC-256;
哈希算法是“指纹”,适合数据校验和密码存储,用SHA256加盐;
最佳实践:混合加密、加盐哈希、安全存储密钥,不要踩我之前踩过的“明文裸奔坑”。
下一节我们会学习SSL/TLS协议(HTTPS、WSS、TLS 1.3),这是三种加密方式的组合应用,让你的网络程序像银行系统一样安全。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49537.html


相关教程