名称:密码学 描述:全面的密码学指导,涵盖加密算法、密码哈希、TLS配置、密钥管理和后量子考虑。在实施加密、选择哈希算法、配置TLS/SSL、管理密码学密钥或审查密码学实现时使用。 允许工具:读取、全局搜索、查找、任务
密码学
安全实施密码学操作的全面指导,涵盖加密算法、密码哈希、TLS和密钥管理。
何时使用此技能
在以下情况下使用此技能:
- 选择加密算法
- 实施密码哈希
- 配置TLS/SSL
- 管理密码学密钥
- 实施数字签名
- 生成随机值
- 审查密码学实现
- 考虑后量子准备
算法快速参考
加密算法
| 算法 | 类型 | 密钥大小 | 使用案例 | 状态 |
|---|---|---|---|---|
| AES-256-GCM | 对称 | 256位 | 数据加密 | ✅ 推荐 |
| ChaCha20-Poly1305 | 对称 | 256位 | 数据加密(移动设备) | ✅ 推荐 |
| RSA-OAEP | 非对称 | 2048+位 | 密钥交换 | ✅ 推荐 |
| ECDH (P-256) | 非对称 | 256位 | 密钥协商 | ✅ 推荐 |
| X25519 | 非对称 | 256位 | 密钥协商 | ✅ 推荐 |
| DES | 对称 | 56位 | 无 | ❌ 已弃用 |
| 3DES | 对称 | 168位 | 仅旧版 | ⚠️ 避免 |
| Blowfish | 对称 | 32-448位 | 无 | ⚠️ 避免 |
签名算法
| 算法 | 类型 | 密钥大小 | 使用案例 | 状态 |
|---|---|---|---|---|
| Ed25519 | EdDSA | 256位 | 签名 | ✅ 推荐 |
| ECDSA (P-256) | ECC | 256位 | 签名、JWT | ✅ 推荐 |
| RSA-PSS | RSA | 2048+位 | 签名 | ✅ 推荐 |
| RSA PKCS#1 v1.5 | RSA | 2048+位 | 旧版签名 | ⚠️ 使用PSS代替 |
哈希函数
| 算法 | 输出大小 | 使用案例 | 状态 |
|---|---|---|---|
| SHA-256 | 256位 | 通用哈希 | ✅ 推荐 |
| SHA-384 | 384位 | 更高安全性 | ✅ 推荐 |
| SHA-512 | 512位 | 最高安全性 | ✅ 推荐 |
| SHA-3-256 | 256位 | SHA-2替代方案 | ✅ 推荐 |
| BLAKE2b | 256-512位 | 快速哈希 | ✅ 推荐 |
| MD5 | 128位 | 无(已破坏) | ❌ 永不使用 |
| SHA-1 | 160位 | 无(已破坏) | ❌ 永不使用 |
密码哈希
永远不要使用通用哈希函数(如SHA-256、MD5)来处理密码。
算法比较
| 算法 | 推荐程度 | 内存硬性 | 备注 |
|---|---|---|---|
| Argon2id | ✅ 最佳 | 是 | PHC获胜者,推荐用于新系统 |
| bcrypt | ✅ 良好 | 否 | 广泛支持,已验证 |
| scrypt | ✅ 良好 | 是 | 良好但调参复杂 |
| PBKDF2 | ⚠️ 可接受 | 否 | NIST批准,但对GPU攻击敏感 |
Argon2id(推荐)
using Konscious.Security.Cryptography;
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// 使用OWASP 2023推荐参数的Argon2id密码哈希器。
/// </summary>
public static class Argon2PasswordHasher
{
private const int DegreeOfParallelism = 4;
private const int MemorySize = 65536; // 64 MB
private const int Iterations = 3;
private const int HashLength = 32;
private const int SaltLength = 16;
/// <summary>
/// 使用Argon2id哈希密码。
/// </summary>
public static string Hash(string password)
{
var salt = RandomNumberGenerator.GetBytes(SaltLength);
var hash = ComputeHash(password, salt);
// 返回PHC格式:$argon2id$v=19$m=65536,t=3,p=4$salt$hash
return $"$argon2id$v=19$m={MemorySize},t={Iterations},p={DegreeOfParallelism}${Convert.ToBase64String(salt)}${Convert.ToBase64String(hash)}";
}
/// <summary>
/// 验证密码与存储的哈希。
/// </summary>
public static bool Verify(string storedHash, string password)
{
var parts = ParseHash(storedHash);
if (parts is null) return false;
var computedHash = ComputeHash(password, parts.Value.Salt);
return CryptographicOperations.FixedTimeEquals(computedHash, parts.Value.Hash);
}
private static byte[] ComputeHash(string password, byte[] salt)
{
using var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
{
Salt = salt,
DegreeOfParallelism = DegreeOfParallelism,
MemorySize = MemorySize,
Iterations = Iterations
};
return argon2.GetBytes(HashLength);
}
private static (byte[] Salt, byte[] Hash)? ParseHash(string storedHash)
{
// 解析PHC格式:$argon2id$v=19$m=...,t=...,p=...$salt$hash
var parts = storedHash.Split('$');
if (parts.Length < 6) return null;
var salt = Convert.FromBase64String(parts[4]);
var hash = Convert.FromBase64String(parts[5]);
return (salt, hash);
}
}
// 用法
var hash = Argon2PasswordHasher.Hash("user_password");
// 返回:$argon2id$v=19$m=65536,t=3,p=4$...
if (Argon2PasswordHasher.Verify(hash, "user_password"))
{
// 密码有效
}
bcrypt
using BCrypt.Net;
// 哈希密码(工作因子12 = 2^12次迭代)
var passwordHash = BCrypt.Net.BCrypt.HashPassword("user_password", workFactor: 12);
// 验证密码
if (BCrypt.Net.BCrypt.Verify("user_password", passwordHash))
{
Console.WriteLine("密码有效");
}
工作因子指南
| 算法 | 最小值 | 推荐值 | 高安全性 |
|---|---|---|---|
| Argon2id | t=2, m=19MB | t=3, m=64MB | t=4, m=128MB |
| bcrypt | 10 | 12 | 14 |
| scrypt | N=2^14 | N=2^16 | N=2^18 |
| PBKDF2 | 310,000 | 600,000 | 1,000,000 |
详细密码哈希指导: 参见密码哈希参考
对称加密
AES-256-GCM(推荐)
using System.Security.Cryptography;
/// <summary>
/// AES-256-GCM加密工具。
/// </summary>
public static class AesGcmEncryption
{
private const int NonceSize = 12; // 96位
private const int TagSize = 16; // 128位
private const int KeySize = 32; // 256位
/// <summary>
/// 使用AES-256-GCM加密数据。返回nonce + 密文 + tag。
/// </summary>
public static byte[] Encrypt(ReadOnlySpan<byte> plaintext, ReadOnlySpan<byte> key)
{
var nonce = RandomNumberGenerator.GetBytes(NonceSize);
var ciphertext = new byte[plaintext.Length];
var tag = new byte[TagSize];
using var aes = new AesGcm(key, TagSize);
aes.Encrypt(nonce, plaintext, ciphertext, tag);
// 组合:nonce + 密文 + tag
var result = new byte[NonceSize + ciphertext.Length + TagSize];
nonce.CopyTo(result.AsSpan(0, NonceSize));
ciphertext.CopyTo(result.AsSpan(NonceSize));
tag.CopyTo(result.AsSpan(NonceSize + ciphertext.Length));
return result;
}
/// <summary>
/// 使用AES-256-GCM解密数据。输入是nonce + 密文 + tag。
/// </summary>
public static byte[] Decrypt(ReadOnlySpan<byte> combined, ReadOnlySpan<byte> key)
{
var nonce = combined[..NonceSize];
var ciphertext = combined[NonceSize..^TagSize];
var tag = combined[^TagSize..];
var plaintext = new byte[ciphertext.Length];
using var aes = new AesGcm(key, TagSize);
aes.Decrypt(nonce, ciphertext, tag, plaintext);
return plaintext;
}
/// <summary>
/// 生成安全的256位密钥。
/// </summary>
public static byte[] GenerateKey() => RandomNumberGenerator.GetBytes(KeySize);
}
// 用法
var key = AesGcmEncryption.GenerateKey();
var encrypted = AesGcmEncryption.Encrypt("sensitive data"u8, key);
var decrypted = AesGcmEncryption.Decrypt(encrypted, key);
从密码派生密钥
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// 使用PBKDF2从密码派生加密密钥。
/// </summary>
public static class KeyDerivation
{
private const int SaltSize = 16;
private const int KeySize = 32; // 256位用于AES-256
private const int Iterations = 600000; // OWASP 2023推荐
/// <summary>
/// 从密码派生加密密钥。返回(密钥,盐)。
/// </summary>
public static (byte[] Key, byte[] Salt) DeriveKey(string password, byte[]? salt = null)
{
salt ??= RandomNumberGenerator.GetBytes(SaltSize);
var key = Rfc2898DeriveBytes.Pbkdf2(
password: Encoding.UTF8.GetBytes(password),
salt: salt,
iterations: Iterations,
hashAlgorithm: HashAlgorithmName.SHA256,
outputLength: KeySize
);
return (key, salt); // 存储盐与加密数据
}
}
非对称加密
RSA密钥生成
using System.Security.Cryptography;
/// <summary>
/// 使用OAEP填充的RSA加密。
/// </summary>
public static class RsaEncryption
{
/// <summary>
/// 生成RSA密钥对。使用2048最小;4096用于长期安全。
/// </summary>
public static RSA GenerateKeyPair(int keySizeInBits = 2048)
{
return RSA.Create(keySizeInBits);
}
/// <summary>
/// 使用公钥和OAEP-SHA256加密。
/// </summary>
public static byte[] Encrypt(byte[] plaintext, RSA publicKey)
{
return publicKey.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);
}
/// <summary>
/// 使用私钥和OAEP-SHA256解密。
/// </summary>
public static byte[] Decrypt(byte[] ciphertext, RSA privateKey)
{
return privateKey.Decrypt(ciphertext, RSAEncryptionPadding.OaepSHA256);
}
}
// 用法
using var rsa = RsaEncryption.GenerateKeyPair(4096);
var publicKey = rsa.ExportRSAPublicKey();
var ciphertext = RsaEncryption.Encrypt(plaintext, rsa);
var decrypted = RsaEncryption.Decrypt(ciphertext, rsa);
数字签名
using System.Security.Cryptography;
/// <summary>
/// Ed25519数字签名(通过ECDsa与曲线)。
/// 注意:.NET 10有原生Ed25519支持。
/// </summary>
public static class DigitalSignatures
{
/// <summary>
/// 创建ECDSA密钥对(P-256,广泛支持)。
/// </summary>
public static ECDsa CreateEcdsaKeyPair()
{
return ECDsa.Create(ECCurve.NamedCurves.nistP256);
}
/// <summary>
/// 使用ECDSA-SHA256签名消息。
/// </summary>
public static byte[] Sign(byte[] message, ECDsa privateKey)
{
return privateKey.SignData(message, HashAlgorithmName.SHA256);
}
/// <summary>
/// 验证签名。
/// </summary>
public static bool Verify(byte[] message, byte[] signature, ECDsa publicKey)
{
return publicKey.VerifyData(message, signature, HashAlgorithmName.SHA256);
}
}
// 用法
using var ecdsa = DigitalSignatures.CreateEcdsaKeyPair();
var signature = DigitalSignatures.Sign(message, ecdsa);
if (DigitalSignatures.Verify(message, signature, ecdsa))
{
Console.WriteLine("签名有效");
}
else
{
Console.WriteLine("签名无效");
}
详细算法选择指导: 参见算法选择指南
TLS配置
推荐TLS设置
# Nginx TLS配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS(HTTP严格传输安全)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# OCSP装订
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
TLS版本要求
| 版本 | 状态 | 备注 |
|---|---|---|
| TLS 1.3 | ✅ 必需 | 最佳安全,改进性能 |
| TLS 1.2 | ✅ 可接受 | 使用适当密码套件仍安全 |
| TLS 1.1 | ❌ 已弃用 | 2020年后已禁用 |
| TLS 1.0 | ❌ 已弃用 | 主要漏洞 |
| SSL 3.0 | ❌ 已破坏 | POODLE攻击 |
| SSL 2.0 | ❌ 已破坏 | 许多漏洞 |
详细TLS配置: 参见TLS配置指南
密钥管理
密钥层次结构
┌─────────────────────────────────────┐
│ 主密钥(KEK) │ <- 存储在HSM或KMS中
│ - 加密所有其他密钥 │
└──────────────────┬──────────────────┘
│
┌───────────┴───────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 数据密钥1 │ │ 数据密钥2 │ <- 用KEK加密
│ (DEK) │ │ (DEK) │
└──────────────┘ └──────────────┘
密钥轮换策略
/// <summary>
/// 支持自动轮换的密钥管理器。
/// </summary>
public sealed class KeyManager(IKmsClient kmsClient) : IDisposable
{
private static readonly TimeSpan RotationPeriod = TimeSpan.FromDays(90);
private string? _currentKeyId;
private DateTime? _keyExpiry;
private readonly SemaphoreSlim _lock = new(1, 1);
/// <summary>
/// 获取当前加密密钥,必要时轮换。
/// </summary>
public async Task<string> GetCurrentKeyAsync(CancellationToken cancellationToken = default)
{
await _lock.WaitAsync(cancellationToken);
try
{
if (NeedsRotation())
{
await RotateKeyAsync(cancellationToken);
}
return _currentKeyId!;
}
finally
{
_lock.Release();
}
}
private bool NeedsRotation() =>
_keyExpiry is null || DateTime.UtcNow > _keyExpiry;
private async Task RotateKeyAsync(CancellationToken cancellationToken)
{
// 在KMS中创建新密钥
var newKey = await kmsClient.CreateKeyAsync(
description: $"数据密钥创建于 {DateTime.UtcNow:O}",
keyUsage: KeyUsage.EncryptDecrypt,
cancellationToken: cancellationToken
);
_currentKeyId = newKey.KeyId;
_keyExpiry = DateTime.UtcNow.Add(RotationPeriod);
// 保留旧密钥用于解密(不要立即删除)
// 用旧密钥加密的数据仍可解密
}
public void Dispose() => _lock.Dispose();
}
// KMS客户端接口(实现为Azure密钥保管库、AWS KMS等)
public interface IKmsClient
{
Task<KmsKey> CreateKeyAsync(string description, KeyUsage keyUsage, CancellationToken cancellationToken);
}
public enum KeyUsage { EncryptDecrypt, SignVerify }
public sealed record KmsKey(string KeyId, DateTime CreatedAt);
随机数生成
using System.Security.Cryptography;
// 用于密码学用途 - 总是使用这些
var secureRandomBytes = RandomNumberGenerator.GetBytes(32); // 32个随机字节
var secureRandomHex = Convert.ToHexString(RandomNumberGenerator.GetBytes(32)); // 64个十六进制字符
var secureRandomUrl = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32))
.Replace('+', '-').Replace('/', '_').TrimEnd('='); // URL安全的base64
// 用于范围内的随机整数(例如,令牌、OTP)
var randomInt = RandomNumberGenerator.GetInt32(100000, 999999); // 6位数OTP
// 永远不要用于密码学
var random = new Random();
random.Next(); // 不是密码学安全的 - 仅用于游戏/模拟
后量子考虑
当前的非对称算法(如RSA、ECDSA、ECDH)对量子计算机脆弱。
NIST后量子标准(2024)
| 算法 | 类型 | 状态 |
|---|---|---|
| ML-KEM(Kyber) | 密钥封装 | ✅ 标准化 |
| ML-DSA(Dilithium) | 数字签名 | ✅ 标准化 |
| SLH-DSA(SPHINCS+) | 数字签名 | ✅ 标准化 |
混合方法(当前推荐)
// 结合经典和后量子算法
// 如果任一被破坏,另一仍提供安全
// 密钥交换:X25519 + ML-KEM-768
// 签名:ECDSA P-256 + ML-DSA-65
// .NET 10+将包括ML-KEM和ML-DSA支持
// 在此之前,使用BouncyCastle等库处理PQ算法
// 这提供了在过渡期间的深度防御:
// 1. 经典算法处理当前威胁
// 2. PQ算法保护免受未来量子攻击
// 3. 组合密钥材料确保任一被破坏时的安全
快速决策树
需要什么密码学操作?
- 加密静态数据 → AES-256-GCM
- 加密传输中数据 → TLS 1.3
- 哈希密码 → Argon2id
- 哈希数据(非密码) → SHA-256或BLAKE2b
- 数字签名 → Ed25519或ECDSA P-256
- 密钥交换 → X25519或ECDH P-256
- 消息认证 → HMAC-SHA256
- 生成随机值 →
RandomNumberGenerator.GetBytes()或RandomNumberGenerator.GetInt32()
安全检查表
加密
- [ ] 使用认证加密(AES-GCM、ChaCha20-Poly1305)
- [ ] 用足够熵生成密钥(256位)
- [ ] 绝不重用nonce/IV
- [ ] 实施适当的密钥管理
密码哈希
- [ ] 使用Argon2id、bcrypt或scrypt
- [ ] 永不使用MD5、SHA-1或无盐哈希
- [ ] 使用适当的工作因子
- [ ] 当参数更改时实施重新哈希
TLS
- [ ] 至少TLS 1.2,推荐TLS 1.3
- [ ] 仅使用强密码套件
- [ ] 来自可信CA的有效证书
- [ ] 启用HSTS
密钥
- [ ] 安全密钥生成
- [ ] 适当的密钥存储(敏感密钥用HSM/KMS)
- [ ] 密钥轮换策略
- [ ] 安全密钥销毁
参考资料
相关技能
| 技能 | 关系 |
|---|---|
authentication-patterns |
使用密码学进行JWT、会话 |
secrets-management |
密码学密钥的安全存储 |
secure-coding |
通用安全实现模式 |
版本历史
- v1.0.0 (2025-12-26):初始发布,包括算法、密码哈希、TLS、密钥管理
最后更新: 2025-12-26