C#.Net-加密解密-学习笔记
一、加密的分类
加密
├── 不可逆加密(单向散列)
│ └── MD5
└── 可逆加密
├── 对称加密(加密/解密用同一个密钥)
│ └── DES / AES
└── 非对称加密(加密/解密用不同密钥)
└── RSA / ECC
二、MD5 ------ 不可逆加密(哈希散列)
核心特点
| 特点 | 说明 |
|---|---|
| 不可逆 | 只能加密,无法从密文还原原文 |
| 固定长度 | 任意长度的内容,结果都是 32 位(16进制字符串) |
| 雪崩效应 | 原文改动一点点,结果变化非常大 |
| 相同输入相同输出 | 同一原文每次加密结果完全一样 |
| 与文件名无关 | 文件内容不变,改名字不影响 MD5 值 |
代码示例
csharp
// 字符串加密(默认32位)
string hash = MD5Encrypt.Encrypt("123456");
// 16位(取32位结果的第9~24位字符)
string hash16 = MD5Encrypt.Encrypt("123456", 16);
// 文件摘要
string fileHash = MD5Encrypt.AbstractFile(@"C:\test.txt");
核心实现原理
csharp
HashAlgorithm provider = CryptoConfig.CreateFromName("MD5") as HashAlgorithm;
byte[] bytes = Encoding.UTF8.GetBytes(source);
byte[] hashValue = provider.ComputeHash(bytes);
// 把每个字节转成两位16进制字符串拼接
sb.Append(hashValue[i].ToString("x2"));
MD5 的实际用途
1. 防篡改 / 文件校验
- SVN 等版本管理工具用 MD5 检测文件是否被修改
- 网盘"极速秒传":扫描本地文件 MD5,与服务器已有文件比对,一致则无需重新上传
2. 密码存储
-
数据库不能存明文密码,存 MD5 密文
-
登录时把用户输入的密码 MD5 后与数据库比对
-
为防止简单密码被暴力破解,通常要加盐
加盐示例:MD5("123456" + "固定盐值zhaoxi")
或者:MD5(MD5("123456")) // 二次加密
3. 数字签名 / 防抵赖
- 对文件内容做 MD5 摘要,由权威第三方保存,证明文件归属
MD5 "被破解"的真相
MD5 本身没有被数学破解,但可以通过**彩虹表(暴力标本库)**反查。
- 32位 MD5 有 2^128 种可能,不可能全部存储
- 加盐后,彩虹表基本失效
三、DES ------ 对称可逆加密
核心特点
- 加密和解密用同一个密钥
- 速度快,适合大量数据加密
- 密钥长度固定 8字节
- 缺点:密钥需要安全传递,一旦泄露全完
代码示例
csharp
// 加密
string encrypted = DesEncrypt.Encrypt("Hello World");
// 解密
string original = DesEncrypt.Decrypt(encrypted);
核心实现原理
csharp
// 密钥和初始向量都取配置文件中 DesKey 的前8位
private static byte[] _rgbKey = ASCIIEncoding.ASCII.GetBytes(Constant.DesKey.Substring(0, 8));
private static byte[] _rgbIV = ASCIIEncoding.ASCII.GetBytes(Constant.DesKey.Substring(0, 8));
// 加密流程:明文 → CryptoStream(加密器) → MemoryStream → Base64字符串
DESCryptoServiceProvider dsp = new DESCryptoServiceProvider();
CryptoStream crypStream = new CryptoStream(memStream,
dsp.CreateEncryptor(_rgbKey, _rgbIV), CryptoStreamMode.Write);
密文最终用 Base64 编码输出,方便存储和传输。
同类算法
| 算法 | 密钥长度 | 说明 |
|---|---|---|
| DES | 56位(8字节) | 较老,安全性一般 |
| 3DES | 168位 | DES 的增强版 |
| AES | 128/192/256位 | 目前主流,推荐使用 |
四、RSA ------ 非对称可逆加密
核心概念
RSA 使用一对密钥:公钥(Public Key)和私钥(Private Key)。
| 密钥 | 特点 | 用途 |
|---|---|---|
| 公钥 | 可以公开给任何人 | 加密数据 / 验证签名 |
| 私钥 | 只有自己保存 | 解密数据 / 生成签名 |
关键原则:两个 key 无法互相推导出对方。
两种使用场景
场景一:保密通信(公钥加密,私钥解密)
发送方用接收方的公钥加密 → 只有持有私钥的接收方才能解密
csharp
KeyModel keys = RsaEncrypt.GetKeyPair();
// 用公钥加密
string encrypted = RsaEncrypt.Encrypt("Hello", keys.PublicKey);
// 用私钥解密
string original = RsaEncrypt.Decrypt(encrypted, keys.PrivateKey);
场景二:数字签名(私钥签名,公钥验证)
发送方用私钥对内容签名 → 任何人用公钥都能验证签名是否合法
csharp
// 生成签名(用私钥)
string signature = RsaEncrypt.SignData("消息原文", keys.PrivateKey);
// 验证签名(用公钥)
bool isValid = RsaEncrypt.VerifyData("消息原文", signature, keys.PublicKey);
// 原文被篡改 → false
// 签名被篡改 → false
核心实现原理
csharp
// 生成密钥对
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
string publicKey = RSA.ToXmlString(false); // false = 只含公钥
string privateKey = RSA.ToXmlString(true); // true = 含公钥+私钥
// 加密
rsa.FromXmlString(encryptKey);
byte[] resultBytes = rsa.Encrypt(DataToEncrypt, false);
// 签名(内部用 SHA1 做摘要,再用私钥加密摘要)
byte[] AOutput = oRSA3.SignData(messagebytes, "SHA1");
// 验签
bool bVerify = RSA.VerifyData(messagebytes, "SHA1", messageAutographbytes);
C# 内置 RSA 的限制
C# 内置的 RSACryptoServiceProvider 只支持:
- 公钥加密 + 私钥解密
- 私钥签名 + 公钥验签
如果需要"私钥加密 + 公钥解密",需要引入第三方库 BouncyCastle。
五、三种加密方式对比总结
| 对比项 | MD5 | DES(对称) | RSA(非对称) |
|---|---|---|---|
| 是否可逆 | 否 | 是 | 是 |
| 密钥数量 | 无 | 1个(共享) | 2个(公钥+私钥) |
| 速度 | 快 | 快 | 慢 |
| 安全性 | 中(需加盐) | 中(密钥传递风险) | 高 |
| 典型用途 | 密码存储、文件校验 | 数据传输加密 | 安全通信、数字签名 |
六、实际项目中的常见组合
HTTPS 的工作原理(RSA + AES 组合):
- 服务器把公钥发给客户端
- 客户端生成一个随机的 AES 密钥,用公钥加密后发给服务器
- 服务器用私钥解密,得到 AES 密钥
- 后续通信全部用 AES 对称加密(速度快)
这样既解决了对称加密密钥传递不安全的问题,又保证了通信速度。
七、配置文件读取(扩展知识)
项目中通过 appsettings.json 存储 DES 密钥,用 Microsoft.Extensions.Configuration 读取:
json
{
"DesKey": "Richard123456"
}
csharp
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile("appSettings.json");
IConfigurationRoot configuration = builder.Build();
string desKey = configuration.GetSection("DesKey").Value;
密钥不要硬编码在代码里,放配置文件或环境变量更安全。