密码学基础与实践:哈希、HMAC、AES、RSA/ECDSA、随机数、X.509
面向工程实践的系统指南:从原理到落地。涵盖 SHA 系列哈希、HMAC、对称加密(AES 及模式)、非对称(RSA/ECDSA/Ed25519)、安全随机数与熵源、X.509 证书的生成与验证;配合命令与代码片段,并指出常见陷阱与最佳实践。
总览与原则
- 目标:提供数据的保密性、完整性、认证与不可否认性;在工程中正确选型与安全使用。
- 通用原则:
- 使用经过审计的库与默认安全配置;避免自实现低层算法。
- 首选 AEAD(如 AES-GCM/ChaCha20-Poly1305)、强随机数(CSPRNG)、强哈希(SHA-256/512、SHA-3)。
- 关注密钥生命周期与管理:生成、存储、轮转、吊销与审计(KMS/HSM/秘密管理)。
保密性 完整性 数据 加密 HMAC/签名 安全传输 验证
哈希(SHA 系列)
- 定义:输入任意长度消息,输出固定长度摘要;满足抗碰撞、抗第二原像与单向性。
- 常用:SHA-256/512(SHA-2)、SHA3-256/512(SHA-3)。
- 用途:
- 完整性校验(配合签名或 HMAC);密码存储(需加盐 + 专用函数如 Argon2/PBKDF2/bcrypt/scrypt)。
- 指纹与标识(证书指纹、文件校验)。
- 误区:
- 单独哈希不提供认证,容易被替换;需要 HMAC 或数字签名。
示例(浏览器 SubtleCrypto):
js
const digest = async (msg) => {
const enc = new TextEncoder().encode(msg);
const hash = await crypto.subtle.digest('SHA-256', enc);
return Array.from(new Uint8Array(hash)).map(b=>b.toString(16).padStart(2,'0')).join('');
};
HMAC(基于哈希的消息认证码)
- 作用:提供完整性与认证(密钥持有者可验证)。常见
HMAC-SHA256/HMAC-SHA1(逐步淘汰)。 - 原理(简化):
HMAC(K, m) = H( (K ⊕ opad) || H( (K ⊕ ipad) || m ) )。 - 用途:
- API 请求签名、TURN 临时凭证(用户名+时间戳 的 HMAC)、Webhook 验证。
- 误区:
- 密钥管理不当、时间戳与时区错误导致过期判断失效;截断长度过短易被暴力。
Client Server msg, HMAC(K,msg) 计算 HMAC(K,msg) 验证通过/拒绝 Client Server
示例(Node.js):
js
import crypto from 'crypto';
function hmacSha256(key, msg) {
return crypto.createHmac('sha256', key).update(msg).digest('hex');
}
对称加密(AES 及模式)
- AES 模式:
- CBC:需随机 IV,易受填充攻击;不提供完整性,实际应配合 HMAC;不再推荐。
- CTR:流模式,需唯一 nonce;不自带完整性;慎用。
- GCM:AEAD 模式(加密 + 鉴别);需唯一 nonce;现代首选。
- ChaCha20-Poly1305:AEAD,在无硬件 AES 加速或移动端常优于 GCM。
- 关键点:
- nonce/IV 管理:GCM/ChaCha20 需保证唯一性;重复 nonce 将破坏安全性。
- 认证数据(AAD):如协议头部,可加入鉴别但不加密。
示例(Node.js AES-GCM):
js
import crypto from 'crypto';
function aesGcmEncrypt(key, plaintext, aad) {
const iv = crypto.randomBytes(12); // GCM nonce
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
if (aad) cipher.setAAD(aad);
const enc = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = cipher.getAuthTag();
return { iv, enc, tag };
}
function aesGcmDecrypt(key, {iv, enc, tag}, aad) {
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
if (aad) decipher.setAAD(aad);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(enc), decipher.final()]);
}
非对称密码:RSA、ECDSA/Ed25519、ECDH
- 功能划分:
- 加密(密钥协商/交换):RSA-OAEP、ECDH(椭圆曲线 Diffie-Hellman)。
- 签名与验证:RSA-PSS、ECDSA(P-256/SECP256R1)、Ed25519(EdDSA)。
- 推荐:
- 签名:RSA-PSS 或 Ed25519;验证速度快,参数简单。
- 密钥协商:ECDH(P-256/P-384)或基于 TLS 的 ECDHE。
- 误区:
- RSA-PKCS#1 v1.5 加密已不推荐;签名模式需区分(PSS vs v1.5)。
- 曲线选择要遵循平台支持(浏览器常用 P-256;Ed25519 在 WebCrypto 支持有限)。
示例(OpenSSL 生成 RSA 与签名):
bash
# 生成 RSA 私钥(2048以上)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa.key
# 派生公钥
openssl pkey -in rsa.key -pubout -out rsa.pub
# 签名与验证(SHA-256 + PSS)
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sign rsa.key -out msg.sig msg.bin
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -verify rsa.pub -signature msg.sig msg.bin
随机数与熵源
- 原则:使用 CSPRNG(操作系统提供):
/dev/urandom(Linux/Unix)、CryptGenRandom/BCryptGenRandom(Windows)、crypto.getRandomValues(Web)。 - 禁止:
Math.random()或非加密安全的 PRNG 做密钥/nonce。 - 注意:
- 唯一性与不可预测性;GCM/ChaCha20 nonce 必须唯一。
- 种子管理:避免固定种子;测试环境与生产区分。
示例(Web):
js
const key = crypto.getRandomValues(new Uint8Array(32));
const nonce = crypto.getRandomValues(new Uint8Array(12));
X.509 证书:结构、生成与验证
- 结构要点:
- Subject/Issuer、Serial、Validity(NotBefore/NotAfter)、SubjectAltName(DNS/IP)、KeyUsage/ExtendedKeyUsage。
- 公钥算法(RSA/ECDSA)、签名算法(SHA256withRSA 等)。
- 链与验证:
- 证书链(Leaf→Intermediate→Root);验证域名(SAN)、有效期、撤销(OCSP/CRL)、信任存储。
- 实践:
- 服务端证书(TLS/DTLS)用于握手与身份;WebRTC 的 DTLS 指纹(
a=fingerprint)绑定证书哈希用于会话验证。
- 服务端证书(TLS/DTLS)用于握手与身份;WebRTC 的 DTLS 指纹(
示例(OpenSSL 自签与 CSR):
bash
# 生成 ECDSA 私钥(P-256)
openssl ecparam -genkey -name prime256v1 -noout -out ecdsa.key
# 生成 CSR(包含 SAN)
cat > csr.conf <<'EOF'
[ req ]
prompt = no
distinguished_name = dn
req_extensions = req_ext
[ dn ]
CN = your-domain.example
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = your-domain.example
EOF
openssl req -new -key ecdsa.key -out ecdsa.csr -config csr.conf
# 自签证书(开发用,不推荐生产)
openssl x509 -req -in ecdsa.csr -signkey ecdsa.key -days 365 -out ecdsa.crt -extensions req_ext -extfile csr.conf
验证链 站点证书 中间CA 根CA 客户端信任存储
从原理到实践:工程清单
- 选型与配置:
- 哈希:SHA-256/512、SHA3,密码存储使用 Argon2/PBKDF2。
- HMAC:请求签名、临时凭证;校时与时区;签名长度≥128位。
- 对称:优先 AES-GCM/ChaCha20-Poly1305;严格管理 nonce;使用 AAD。
- 非对称:签名用 RSA-PSS/Ed25519;协商用 ECDH(ECDHE)。
- 随机数:系统 CSPRNG;禁止 Math.random 用于密钥生成。
- 证书:SAN 与 EKU 配置正确;自动续期与吊销检查;DTLS 指纹校验。
- 密钥管理:
- 使用 KMS/Secrets Manager/HSM 管理密钥;审计访问与轮转;分环境隔离。
- 安全部署:
- 强制 TLS ≥ 1.2;禁用弱套件;启用 HSTS/CSP;最小权限与短期凭证。
- 常见陷阱:
- 重复 nonce(GCM/ChaCha20)导致灾难性泄露;
- 使用旧模式(RSA v1.5、AES-CBC 无 MAC);
- 证书域名与 SAN 不匹配;
- 时间与随机源问题导致 HMAC/证书校验异常。
关联到 WebRTC 的实践(速链)
- DTLS 指纹:
a=fingerprint传递证书哈希,防中间人;必须通过已鉴权与加密的信令通道。 - 媒体安全:SRTP(AES-CTR/HMAC 或 AES-GCM AEAD),现代实现倾向 AEAD。
- TURN 凭证:使用 HMAC 的短期用户+口令(TURN REST),避免静态凭证滥用。
- 浏览器随机:
crypto.getRandomValues;候选隐私:mDNS。
延伸参考
- NIST 与 IETF:AES-GCM、ChaCha20-Poly1305、HMAC、SHA-2/3、RSA-PSS、Ed25519、X.509、OCSP/CRL。
- 工具与库:OpenSSL、BoringSSL、libsodium、Node.js crypto、WebCrypto API。
- 实践指南:OWASP ASVS/Cheat Sheets、TLS 配置最佳实践。
总结:理解"保密性/完整性/认证"的目标,选用现代算法与安全模式(AEAD、强哈希、强随机),再把密钥与证书管理、时间与身份策略落实到工程细节,才能让系统在真实网络与对抗面前保持稳健与可审计。
深入原理与关系映射
哈希的内部原理与安全性质
- Merkle--Damgård(SHA-2):对消息分块迭代压缩,末尾添加长度与填充;易受"长度扩展攻击",因此带密钥的完整性校验应使用 HMAC,而非"secret-prefix MAC"。
- Sponge(SHA-3):吸收/挤压(absorb/squeeze)结构,抗长度扩展;适用于新设计场景。
- 安全性质:抗碰撞(难找到 m1≠m2 且 H(m1)=H(m2))、抗第二原像、单向性。
HMAC 的抗攻击能力与构造意义
- HMAC 通过两次哈希与内外填充(ipad/opad)抵御长度扩展与某些结构攻击;只要底层哈希为抗碰撞且密钥保密,HMAC 即具认证性。
- 与数字签名区别:HMAC 需要共享秘密,适合"对称认证";签名适合"公开验证与不可否认"。
对称加密的安全模型与 AEAD
- 语义安全(IND-CPA):攻击者在已知明文模型下无法区分密文;CTR/CBC 满足保密但不提供完整性。
- 抗主动攻击(IND-CCA):需要认证的加密(AEAD)。GCM 内含 GHASH(多项式 MAC),Poly1305 为消息认证码;重复 nonce 会破坏安全(GCM 泄露密钥相关信息)。
- AAD(Associated Data):如协议头部,加入认证但不加密,确保整体完整性。
非对称的数学基础与实践要点
- RSA:基于模幂与因数分解困难;加密需 OAEP 填充,签名首选 PSS;v1.5 过时且易被利用。
- ECDSA/Ed25519:椭圆曲线上的签名;ECDSA 若重复或泄露随机数 k 将暴露私钥,建议使用 RFC 6979(确定性签名)。Ed25519 设计简洁且高效,但平台支持需确认。
- ECDH/ECDHE:基于离散对数困难;用于协商共享秘密,再派生对称密钥;注意小子群攻击与曲线选择(P-256/Curve25519)。
随机性的本质与风险
- CSPRNG 保证输出不可预测;初始熵不足(特别是嵌入式设备)会导致低安全度,需合并多源熵(TRNG+系统事件)。
- nonce/IV 的唯一性要求:重复将破坏 AEAD 安全;常用 96-bit GCM nonce 与 32-bit/64-bit 计数器结合确保唯一。
X.509 与 PKI 的信任链
- 信任锚(Root CA)→中间 CA→站点证书;客户端验证 SAN、有效期与链完整性;OCSP/CRL 用于撤销。
- WebRTC 的 DTLS 指纹:SDP 中的
a=fingerprint为证书哈希,双方在握手前就"固定指纹",防止中间人修改证书。
典型协议映射:TLS/DTLS 与 WebRTC
Client Server TLS/DTLS 握手:使用证书与签名认证身份,使用 ECDHE 协商密钥 ClientHello (随机数, 套件支持) ServerHello + Certificate (X.509) ServerKeyExchange (ECDHE) ClientKeyExchange (ECDHE) Finished (HMAC/MAC 验证) Finished 派生对称会话密钥,数据平面使用 AEAD (AES-GCM) Client Server
选择与对比(速查)
- 签名:优先 RSA-PSS/Ed25519(视平台支持);避免 RSA v1.5。
- 加密:优先 AEAD(AES-GCM/ChaCha20-Poly1305);避免 CBC+无 MAC。
- 哈希:SHA-256/512 或 SHA-3;带密钥校验使用 HMAC。
- 随机:系统 CSPRNG;确保 nonce 唯一性。
- 证书:SAN/EKU 正确,自动续期与撤销;指纹校验。
从零搭建安全通道(实操路径)
- 生成证书与指纹,配置 TLS/DTLS;
- 选择 AEAD 与套件,设定最低 TLS 版本与禁用弱套件;
- 使用 HMAC 为临时凭证与 API 请求签名;
- 使用系统 CSPRNG 生成密钥与 nonce,记录并保证不重复;
- 配置日志与审计,定期轮转密钥与证书。