C#加解密:从入门到放弃?不,是到实战!

刚接触加密那会儿,我被那些术语绕得头晕——AES、DES、RSA、散列、盐值...听起来就像天书。但真正用起来才发现,日常开发中掌握那么三四个套路就够用了。

先搞懂三个核心概念

1. 对称加密(AES)—— 像保险箱

  • 同一把钥匙加密和解密
  • 速度快,适合大数据量
  • 关键问题:钥匙怎么安全地交给对方?

2. 非对称加密(RSA)—— 像信箱

  • 公钥加密,私钥解密
  • 速度慢,适合小数据量
  • 完美解决钥匙传递问题

3. 哈希(MD5、SHA)—— 像指纹

  • 单向的,无法还原
  • 主要用于校验数据完整性
  • 注意:MD5现在已不安全,别用在密码加密上

实战场景1:用户密码加密

这是我踩过的第一个坑。早期项目我直接MD5加密密码,直到有天发现彩虹表一撞一个准...

现在正确的做法:

// 使用PBKDF2或BCrypt,它们会加盐且计算很慢,防止暴力破解
public string HashPassword(string password)
{
    // 生成随机的盐值(16字节)
    byte[] salt = new byte[16];
    using (var rng = RandomNumberGenerator.Create())
    {
        rng.GetBytes(salt);
    }
    
    // 使用PBKDF2进行哈希(迭代10000次)
    var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256);
    byte[] hash = pbkdf2.GetBytes(20); // 20字节哈希值
    
    // 组合盐值和哈希值存储
    byte[] hashBytes = new byte[36];
    Array.Copy(salt, 0, hashBytes, 0, 16);
    Array.Copy(hash, 0, hashBytes, 16, 20);
    
    return Convert.ToBase64String(hashBytes);
}

// 验证密码
public bool VerifyPassword(string password, string hashedPassword)
{
    byte[] hashBytes = Convert.FromBase64String(hashedPassword);
    byte[] salt = new byte[16];
    Array.Copy(hashBytes, 0, salt, 0, 16);
    
    var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256);
    byte[] hash = pbkdf2.GetBytes(20);
    
    // 比较哈希值
    for (int i = 0; i < 20; i++)
    {
        if (hashBytes[i + 16] != hash[i])
            return false;
    }
    return true;
}

实战场景2:配置文件加密(AES)

数据库连接字符串、API密钥这些敏感信息,千万别明文写在配置文件里!

public class AesHelper
{
    private readonly byte[] _key; // 256位密钥
    private readonly byte[] _iv;  // 128位初始化向量
    
    public AesHelper(string base64Key, string base64Iv)
    {
        _key = Convert.FromBase64String(base64Key);
        _iv = Convert.FromBase64String(base64Iv);
    }
    
    public string Encrypt(string plainText)
    {
        using (var aes = Aes.Create())
        {
            aes.Key = _key;
            aes.IV = _iv;
            
            using (var encryptor = aes.CreateEncryptor())
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                using (var sw = new StreamWriter(cs))
                {
                    sw.Write(plainText);
                }
                return Convert.ToBase64String(ms.ToArray());
            }
        }
    }
    
    public string Decrypt(string cipherText)
    {
        using (var aes = Aes.Create())
        {
            aes.Key = _key;
            aes.IV = _iv;
            
            using (var decryptor = aes.CreateDecryptor())
            using (var ms = new MemoryStream(Convert.FromBase64String(cipherText)))
            using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
            using (var sr = new StreamReader(cs))
            {
                return sr.ReadToEnd();
            }
        }
    }
}

// 使用示例
var helper = new AesHelper("你的Base64密钥", "你的Base64IV");
string encrypted = helper.Encrypt("Server=localhost;Database=test;");
string decrypted = helper.Decrypt(encrypted);

重要提醒: 密钥和IV要妥善保管,最好放在环境变量或密钥管理服务中。

实战场景3:数据传输加密(RSA + AES组合拳)

这是最实用的组合方案:用RSA加密AES的密钥,再用AES加密实际数据。

// 发送方
public class Sender
{
    public (string encryptedData, string encryptedKey) SendData(string data, string receiverPublicKey)
    {
        // 1. 生成随机的AES密钥
        using (var aes = Aes.Create())
        {
            aes.GenerateKey();
            aes.GenerateIV();
            
            // 2. 用AES加密数据
            var aesHelper = new AesHelper(Convert.ToBase64String(aes.Key), Convert.ToBase64String(aes.IV));
            string encryptedData = aesHelper.Encrypt(data);
            
            // 3. 用对方的RSA公钥加密AES密钥
            using (var rsa = RSA.Create())
            {
                rsa.ImportFromPem(receiverPublicKey);
                byte[] encryptedKey = rsa.Encrypt(aes.Key, RSAEncryptionPadding.OaepSHA256);
                
                return (encryptedData, Convert.ToBase64String(encryptedKey));
            }
        }
    }
}

// 接收方
public class Receiver
{
    private readonly RSA _privateKey;
    
    public Receiver(string privateKey)
    {
        _privateKey = RSA.Create();
        _privateKey.ImportFromPem(privateKey);
    }
    
    public string ReceiveData(string encryptedData, string encryptedKey)
    {
        // 1. 用自己的私钥解密AES密钥
        byte[] aesKey = _privateKey.Decrypt(Convert.FromBase64String(encryptedKey), RSAEncryptionPadding.OaepSHA256);
        
        // 2. 用AES密钥解密数据
        using (var aes = Aes.Create())
        {
            // 注意:IV也需要安全传递,这里简化处理
            var helper = new AesHelper(Convert.ToBase64String(aesKey), "base64IV");
            return helper.Decrypt(encryptedData);
        }
    }
}

我踩过的坑,希望你避开

  1. 密钥管理混乱:早期我把密钥硬编码在代码里,换环境的时候欲哭无泪。现在都用环境变量或专门的密钥管理工具。

  2. 模式选择错误:AES的ECB模式不安全,一定要用CBC或GCM模式。

  3. 忘记处理异常:加解密失败很常见,一定要做好异常处理,别让密文泄露到日志里。

  4. 性能问题:RSA加密大量数据慢得要死,所以要用上面那种组合方案。

实用建议

  • 密码存储:用PBKDF2、BCrypt或Argon2
  • 配置文件加密:AES足够好用
  • 网络传输:RSA+AES组合拳
  • 数据校验:用HMAC-SHA256而不是简单的MD5

最后提醒一句:除非你是密码学专家,否则不要自己发明加密算法。用.NET框架提供的这些标准实现,已经足够安全了。

需要生成密钥对?评论区告诉我,下次分享一键生成RSA密钥对的实用工具类。

posted @ 2025-09-25 09:05  深圳蔓延科技有限公司  阅读(38)  评论(0)    收藏  举报