版本:2026-07-02 最终整合版
目标:围绕现代 HTTPS/TLS 仍在主流使用的加密技术,建立一份“链路完整、算法细粒度、数学原理清楚、单向/陷门安全本质融入每个算法”的技术文档。
主线协议:TLS 1.3
兼容视角:TLS 1.2 中仍安全的 ECDHE + AEAD 组合
不主讲:SSL、TLS 1.0/1.1、RSA Key Exchange、静态 DH、RC4、3DES、CBC 套件、MD5/SHA-1 签名、DSA、EXPORT 套件等历史/弃用技术。
目录
- 总览:现代 HTTPS 到底由哪些安全能力组成
- 现代 HTTPS/TLS 1.3 完整握手链路
- ECDHE:现代 HTTPS 的密钥协商核心
- HKDF + HMAC + Transcript Hash:共享秘密如何派生成通信密钥
- X.509 / CA 证书链:服务器公钥如何变得可信
- 数字签名体系:RSA-PSS、ECDSA、EdDSA
- AEAD 记录层加密:AES-GCM 与 ChaCha20-Poly1305
- RSA-OAEP:现代可用的公钥加密方案,但不是 TLS 1.3 主线
- 现代推荐与弃用技术边界
- 最终总结
- 参考文献
1. 总览:现代 HTTPS 到底由哪些安全能力组成
HTTPS 可以简单写成:
HTTPS = HTTP + TLSHTTP 负责业务语义:
GET /user/profilePOST /loginCookieJSONHTML图片视频TLS 负责通信安全:
身份认证密钥协商密钥派生数据加密完整性校验防篡改防伪造前向安全性现代 TLS 1.3 的主线不是“用服务器公钥加密所有 HTTP 内容”,也不是“浏览器生成会话密钥 K 后用 RSA 公钥加密 K 发过去”。
更准确的现代链路是:
1. 浏览器和服务器通过 ClientHello / ServerHello 交换能力和 ECDHE 临时公钥2. 双方用 ECDHE 各自算出同一个共享秘密 shared secret3. 服务器发送 X.509 证书链,浏览器验证服务器公钥是否可信4. 服务器用证书对应私钥签名握手 transcript,证明自己持有私钥5. 双方用 HKDF 从 shared secret 派生握手密钥、应用数据密钥、IV、finished_key6. 双方用 Finished 验证整个握手 transcript 没有被篡改7. 后续 HTTP 数据用 AES-GCM 或 ChaCha20-Poly1305 做 AEAD 认证加密可以把现代 HTTPS 拆成五类密码学能力:
| 能力 | 代表算法/机制 | 解决的问题 |
|---|---|---|
| 身份认证 | X.509 证书链、CA 签名、CertificateVerify | 确认连接的是目标服务器,不是中间人 |
| 密钥协商 | ECDHE / X25519 / P-256 | 双方在不安全网络上得到同一个共享秘密 |
| 密钥派生 | HKDF + HMAC + SHA-256/SHA-384 | 从共享秘密派生出多把隔离密钥 |
| 数据保护 | AES-GCM、ChaCha20-Poly1305 | 后续 HTTP 数据加密、防篡改、认证 |
| 安全绑定 | Transcript Hash、Finished | 把握手消息、密钥、身份绑定到同一个上下文 |
1.1 这份文档的算法讲解方法
每个算法不再只讲“流程”,而是按以下结构展开:
1. 它在 HTTPS 里负责什么2. 输入是什么3. 输出是什么4. 正向计算为什么容易5. 反向求解、伪造或攻击为什么困难6. 它依赖哪个数学困难问题或安全假设7. 它在 TLS 1.3 中如何落地8. 工程实现要注意什么这样你能真正理解:
为什么公钥可以公开为什么私钥不能推出来为什么 aG 不能反推出 a为什么签名能验证身份为什么证书链不能被伪造为什么对称密钥泄露后才危险为什么 nonce 复用会出大问题2. 现代 HTTPS/TLS 1.3 完整握手链路
下面以用户访问:
https://www.example.com为例,从通信开始讲到后续 HTTP 数据加密传输。
2.1 DNS 解析
浏览器首先需要知道目标域名对应的 IP:
www.example.com → 203.0.113.10这一步不是 TLS 本身,但它发生在连接之前。后续 TLS 证书验证会检查:
证书里的域名是否匹配 www.example.com2.2 TCP 连接建立
HTTPS over TCP 场景下,浏览器先和服务器建立 TCP 连接:
Client → Server:SYNServer → Client:SYN + ACKClient → Server:ACKTCP 只解决可靠传输,不解决加密和身份认证。
TLS 在 TCP 连接之上工作。
2.3 ClientHello:客户端声明能力并发送临时公钥
浏览器发送 TLS 1.3 ClientHello。
典型内容:
ClientHello { supported_versions = [TLS 1.3, TLS 1.2] cipher_suites = [ TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256 ] client_random server_name = "www.example.com" supported_groups = [x25519, secp256r1, secp384r1] signature_algorithms = [ ecdsa_secp256r1_sha256, rsa_pss_rsae_sha256, rsa_pss_pss_sha256, ed25519 ] key_share = { group = x25519, key_exchange = A } alpn = ["h2", "http/1.1"]}这里最核心的是:
key_share = A客户端本地生成临时私钥:
a然后计算临时公钥:
A = aG发送的是:
A不发送的是:
aa 是本次连接的临时私钥,连接结束后会丢弃。
2.4 ServerHello:服务器选择参数并发送临时公钥
服务器收到 ClientHello 后,选择双方都支持的参数。
典型 ServerHello:
ServerHello { selected_version = TLS 1.3 selected_cipher_suite = TLS_AES_128_GCM_SHA256 server_random key_share = { group = x25519, key_exchange = B }}服务器本地生成临时私钥:
b计算临时公钥:
B = bG发送的是:
B不发送的是:
b2.5 双方计算 ECDHE 共享秘密
客户端拿到服务器临时公钥:
B = bG客户端自己知道:
a所以客户端计算:
S = aB = a(bG) = abG服务器拿到客户端临时公钥:
A = aG服务器自己知道:
b所以服务器计算:
S = bA = b(aG) = abG双方得到同一个共享秘密:
S = abG网络攻击者能看到:
GA = aGB = bG但不知道:
abS = abG这就是 ECDHE 密钥协商。
注意,这一步只解决:
双方算出同一个秘密还没有单独解决:
对方到底是不是 www.example.com身份认证要靠证书链和 CertificateVerify。
2.6 ServerHello 后派生握手密钥
TLS 1.3 在 ServerHello 后,客户端和服务器都已经有:
ECDHE shared secret S然后双方可以用 HKDF 派生握手阶段密钥:
S → handshake_secret → handshake_traffic_keys因此 TLS 1.3 中 ServerHello 之后的部分握手消息通常已经受到加密保护,例如:
EncryptedExtensionsCertificateCertificateVerifyFinished这和 TLS 1.2 不同,TLS 1.3 尽早加密更多握手内容。
2.7 Certificate:服务器发送证书链
服务器发送:
Certificate { Server Certificate Intermediate CA Certificate ...}服务器证书包含:
域名 / SAN:www.example.com服务器长期公钥 server_public_key有效期用途:TLS Web Server Authentication签发者:Intermediate CAIntermediate CA 对服务器证书内容的签名中间 CA 证书包含:
主体:Intermediate CA中间 CA 公钥 intermediate_public_key签发者:Root CARoot CA 对中间 CA 证书内容的签名浏览器本地已经预装一批可信根证书:
Root CA CertificateRoot CA Public Key浏览器本地没有 Root CA 私钥。
2.8 浏览器验证证书链
证书链不是嵌套解密,而是逐层验签。
整体路径:
Root CA 公钥 ↓ 验证签名Intermediate CA 证书可信 ↓ 取出 Intermediate CA 公钥Intermediate CA 公钥 ↓ 验证签名Server 证书可信 ↓ 取出 Server 公钥浏览器还会检查:
证书域名是否匹配当前访问的 www.example.com证书是否过期证书用途是否允许 serverAuth中间 CA 是否具备 CA=true中间 CA 是否具备 keyCertSign证书路径长度是否满足关键扩展是否可理解证书是否被吊销证书链验证通过后,浏览器才认为:
server_public_key 确实属于 www.example.com2.9 CertificateVerify:服务器证明自己持有私钥
证书是公开的,攻击者可以复制证书内容。
所以服务器还必须证明:
我持有 server_public_key 对应的 server_private_key服务器会对当前握手 transcript 做签名:
transcript_hash = Hash(ClientHello || ServerHello || EncryptedExtensions || Certificate || ...)
signature = Sign(server_private_key, transcript_hash)浏览器使用服务器证书里的公钥验签:
Verify(server_public_key, transcript_hash, signature)如果通过,说明:
服务器确实持有证书对应私钥服务器临时公钥 B 被绑定到真实服务器身份上中间人不能替换 B 后还能通过签名验证2.10 Finished:双方确认握手未被篡改
双方根据握手密钥派生出 finished_key,然后生成 Finished:
verify_data = HMAC(finished_key, Hash(handshake_transcript))如果握手过程中任何消息被中间人修改:
handshake_transcript 不同transcript_hash 不同verify_data 不同Finished 校验失败Finished 让双方确认:
我们看到的是同一组握手消息我们派生出的是同一组密钥这个握手没有被中途篡改2.11 后续应用数据加密
握手完成后,HTTP 数据会被 TLS Record Layer 加密。
例如:
GET /api/user HTTP/2Cookie: session=...进入 TLS 后:
plaintext = HTTP data
ciphertext, tag = AEAD_Encrypt( key = client_application_write_key, nonce = per_record_nonce, plaintext = HTTP data, aad = TLS record header)服务器解密:
plaintext = AEAD_Decrypt( key, nonce, ciphertext, aad, tag)tag 验证失败则直接丢弃。
3. ECDHE:现代 HTTPS 的密钥协商核心
ECDHE 是现代 HTTPS/TLS 1.3 的关键算法之一。它不是加密 HTTP 数据,也不是数字签名,而是:
密钥协商算法它解决的问题是:
客户端和服务器如何在不安全网络上协商出同一个共享秘密?3.1 ECDHE 在 TLS 中负责什么
ECDHE 输出一个共享秘密:
shared_secret = S这个 S 不直接用来加密 HTTP 数据,而是交给 HKDF 派生正式密钥。
在 TLS 1.3 中:
ECDHE shared secret ↓HKDF ↓handshake traffic secretapplication traffic secretwrite keywrite ivfinished keyECDHE 负责:
产生只有客户端和服务器知道的原始共享秘密HKDF 负责:
把共享秘密变成可用于 TLS 各阶段的密钥AEAD 负责:
用派生出的密钥加密 HTTP 数据3.2 ECDHE 的输入与输出
公开参数:
椭圆曲线参数基点 G曲线阶 n客户端输入:
临时私钥 a客户端输出:
临时公钥 A = aG服务器输入:
临时私钥 b服务器输出:
临时公钥 B = bG交换后:
客户端计算 S = aB服务器计算 S = bA最终双方得到:
S = abG3.3 aG 到底是什么
aG 不是普通乘法。
在椭圆曲线群里:
G 是曲线上的一个公开基点a 是一个大整数aG 表示把 G 重复加 a 次也就是:
aG = G + G + G + ... + G一共加 a 次。
这个操作叫:
椭圆曲线标量乘法它和普通整数乘法不同。
点加法的结果仍然是曲线上的点:
G = (x_G, y_G)A = aG = (x_A, y_A)3.4 正向为什么容易
虽然数学定义是“加 a 次”,但实现不会真的循环 a 次。
实现会用类似快速幂的算法:
double-and-addMontgomery ladderwindow method例如计算:
13G因为:
13 = 8 + 4 + 1可以先计算:
2G4G8G然后:
13G = 8G + 4G + G复杂度大约是:
O(log a)所以:
给定 a 和 G,计算 A = aG 很快X25519 采用 Montgomery ladder 风格的标量乘法,既高效,也有利于常数时间实现,从而降低侧信道风险。
3.5 反向为什么困难:ECDLP
攻击者看到:
GA = aG想求:
a这个问题叫:
椭圆曲线离散对数问题Elliptic Curve Discrete Logarithm Problem, ECDLP形式化:
已知 G 和 A,且 A = aG,求 a。为什么不能像普通数字那样:
a = A / G因为:
A 和 G 是椭圆曲线上的点aG 是重复点加法椭圆曲线群里没有高效的“除以 G”操作可以恢复 a可以类比为:
正向:从起点 G 按规则跳 a 步,得到 A反向:只知道起点 G 和终点 A,要猜到底跳了多少步由于群非常大,无法逐个试。
3.6 暴力破解为什么不可行
以 X25519 对应的安全级别粗略理解,私钥空间非常大。
如果群阶接近:
2^252普通暴力枚举需要接近:
2^252次尝试。
通用攻击算法 Pollard rho 复杂度大约是:
O(√n)如果:
n ≈ 2^252那么:
√n ≈ 2^126这仍然是现实不可行的计算量。
所以 X25519 常被认为提供约 128-bit 安全级别。
3.7 为什么双方都能算出 abG
客户端:
S_client = aB = a(bG) = abG服务器:
S_server = bA = b(aG) = baG = abG这里依赖椭圆曲线群的标量乘法结合性:
a(bG) = (ab)G = b(aG)攻击者没有 a 或 b,只有:
GaGbG想直接求:
abG这个问题叫:
Computational Diffie-Hellman Problem, CDH形式化:
给定 G, aG, bG,求 abG。在合适曲线参数下,这被认为不可高效求解。
3.8 ECDHE 的安全本质嵌入总结
ECDHE 的安全不是来自“服务器藏着一个能反解 aG 的陷门”。
它的核心是:
正向 a → aG 容易反向 aG → a 困难给定 G, aG, bG 求 abG 困难因此 ECDHE 更准确说是:
基于椭圆曲线离散对数困难和 Diffie-Hellman 困难的密钥协商而不是典型的:
陷门加密函数RSA 才是典型陷门函数。
3.9 ECDHE 在 TLS 中为什么还需要签名
如果只有 ECDHE,没有证书和签名,会出现中间人攻击。
中间人可以分别和客户端、服务器做两次 ECDHE:
客户端 ↔ 中间人中间人 ↔ 服务器客户端以为共享秘密是和服务器协商的,其实是和中间人协商的。
所以 TLS 里需要:
证书链:证明服务器长期公钥可信CertificateVerify:服务器用长期私钥签名握手 transcript这样服务器临时公钥 B 会被签名绑定到服务器身份上。
4. HKDF + HMAC + Transcript Hash:共享秘密如何派生成通信密钥
HKDF 不是非对称算法,也不是陷门函数。
它是:
基于 HMAC 的密钥派生函数在 TLS 1.3 中,它把 ECDHE 的原始共享秘密变成多把有明确用途的密钥。
4.1 HKDF 在 TLS 中负责什么
ECDHE 产生的是:
shared_secret = S这个值不能直接作为 AES-GCM 或 ChaCha20-Poly1305 的 key。
原因:
1. 原始共享秘密格式不适合直接当对称密钥2. 握手阶段和应用数据阶段需要不同密钥3. 客户端发送方向和服务器发送方向需要不同密钥4. Finished、Record Encryption、Key Update 等用途需要隔离5. 密钥应绑定到握手 transcript,防止上下文混淆HKDF 负责:
提取 entropy扩展为多把用途隔离的密钥绑定上下文信息4.2 HMAC 的基本结构
HKDF 基于 HMAC。
HMAC 可以粗略理解为:
HMAC(K, m) = Hash((K XOR opad) || Hash((K XOR ipad) || m))它把哈希函数变成带密钥的消息认证函数。
HMAC 的安全本质是:
不知道 K,就无法预测或伪造 HMAC 输出HMAC 不是可逆加密,也不是陷门函数。
它是:
伪随机函数 / 消息认证码4.3 HKDF-Extract:提纯
HKDF 第一步:
PRK = HKDF-Extract(salt, IKM)具体形式:
PRK = HMAC(salt, IKM)其中:
IKM = input keying material,例如 ECDHE shared secretsalt = 盐值,TLS key schedule 中通常是前一级 secretPRK = pseudo-random key它的作用:
把可能不完全均匀的输入密钥材料提炼成伪随机密钥可以理解成:
原始共享秘密 → 提纯后的密钥种子4.4 HKDF-Expand:扩展
第二步:
OKM = HKDF-Expand(PRK, info, L)其中:
PRK:提纯后的伪随机密钥info:上下文标签L:输出长度OKM:输出密钥材料info 非常重要。
如果没有上下文标签,不同用途的密钥可能混用。
TLS 1.3 用:
HKDF-Expand-Label(secret, label, context, length)实现强制域分离。
例如:
"c hs traffic":客户端握手流量密钥"s hs traffic":服务器握手流量密钥"c ap traffic":客户端应用数据密钥"s ap traffic":服务器应用数据密钥"finished":Finished 校验密钥"key":实际 AEAD key"iv":实际 AEAD IV4.5 TLS 1.3 Key Schedule 细化
简化但贴近标准的结构:
early_secret = HKDF-Extract(0, PSK or 0)
derived_secret_1 = Derive-Secret(early_secret, "derived", "")
handshake_secret = HKDF-Extract(derived_secret_1, ECDHE_shared_secret)
client_handshake_traffic_secret = Derive-Secret(handshake_secret, "c hs traffic", transcript_hash)
server_handshake_traffic_secret = Derive-Secret(handshake_secret, "s hs traffic", transcript_hash)
derived_secret_2 = Derive-Secret(handshake_secret, "derived", "")
master_secret = HKDF-Extract(derived_secret_2, 0)
client_application_traffic_secret = Derive-Secret(master_secret, "c ap traffic", transcript_hash)
server_application_traffic_secret = Derive-Secret(master_secret, "s ap traffic", transcript_hash)然后从 traffic secret 派生真正记录层使用的 key 和 IV:
write_key = HKDF-Expand-Label(traffic_secret, "key", "", key_length)
write_iv = HKDF-Expand-Label(traffic_secret, "iv", "", iv_length)Finished key:
finished_key = HKDF-Expand-Label(base_key, "finished", "", hash_length)4.6 Transcript Hash 为什么关键
TLS 1.3 派生 traffic secret 时,会把握手 transcript 的哈希放进去:
traffic_secret = Derive-Secret(secret, label, Hash(handshake_messages))这意味着密钥不仅依赖:
ECDHE shared secret还依赖:
双方实际看到的握手消息如果中间人修改了:
ClientHelloServerHelloCertificateCertificateVerify任意一项,双方 transcript_hash 就会不同,派生出的密钥或 Finished 校验就会失败。
因此 transcript_hash 把:
算法协商结果临时公钥服务器证书服务器签名绑定到同一个握手上下文里。
4.7 HKDF 的安全本质嵌入总结
HKDF 不是靠“反向困难”来加密数据。
它的安全本质是:
如果输入 secret 有足够熵如果 HMAC/SHA-256 具备伪随机性那么攻击者无法预测派生出的密钥它解决的是:
共享秘密如何变成多把上下文隔离的高质量密钥而不是:
公钥如何解密签名如何验签5. X.509 / CA 证书链:服务器公钥如何变得可信
证书链是 HTTPS 身份认证的核心。
它解决的问题不是:
如何加密数据而是:
浏览器如何确认这个服务器公钥确实属于 www.example.com5.1 证书不是“加密嵌套包”
一个常见误区是:
根公钥解密外层证书暴露中间层公钥再解密内层服务器证书这是不准确的。
证书链是:
签名链不是:
嵌套加密链每张证书本身都是可读结构,里面明文包含主体公钥:
中间 CA 公钥在中间 CA 证书里服务器公钥在服务器证书里但浏览器不会直接信任它们。
浏览器通过上一级公钥验签,确认这张证书没有被篡改且确实由上一级签发。
5.2 X.509 证书结构
证书大体结构:
Certificate { tbsCertificate signatureAlgorithm signatureValue}tbsCertificate 是 “to be signed certificate”,即被签名的主体内容。
常见字段:
versionserialNumberissuervaliditysubjectsubjectPublicKeyInfoextensions重要扩展:
Subject Alternative Name:域名列表Basic Constraints:是否是 CAKey Usage:digitalSignature、keyCertSign 等Extended Key Usage:serverAuth 等Subject Key IdentifierAuthority Key IdentifierName ConstraintsCertificate PoliciesCRL Distribution PointsAuthority Information Access / OCSP5.3 CA 签发服务器证书
服务器先生成密钥对:
server_private_keyserver_public_key然后生成 CSR:
CSR { 域名 服务器公钥 申请者信息 申请者签名}CA 验证域名控制权,例如:
DNS TXT 验证HTTP 文件验证TLS-ALPN 验证验证通过后,CA 构造服务器证书内容:
tbsCertificate { subject = www.example.com subjectPublicKeyInfo = server_public_key issuer = Intermediate CA validity = ... extensions = SAN, KeyUsage, EKU, ...}CA 对 tbsCertificate 签名:
signatureValue = Sign(CA_private_key, Hash(tbsCertificate))最终证书:
Certificate = tbsCertificate + signatureAlgorithm + signatureValue5.4 浏览器逐层验证证书链
假设证书链是:
Root CA ↓Intermediate CA ↓Server Certificate浏览器本地信任 Root CA 公钥。
第一步,验证中间 CA 证书:
Verify( publicKey = Root CA 公钥, message = Intermediate.tbsCertificate, signature = Intermediate.signatureValue)验签成功后:
Intermediate CA 证书内容可信Intermediate CA 公钥可信第二步,验证服务器证书:
Verify( publicKey = Intermediate CA 公钥, message = Server.tbsCertificate, signature = Server.signatureValue)验签成功后:
Server 证书内容可信Server 公钥可信这里的安全本质是:
攻击者可以复制证书但不能修改证书内容后重新生成合法 CA 签名因为攻击者没有 CA 私钥5.5 路径构建与路径验证
浏览器并不是简单按服务器发来的顺序盲目验证。
它通常要先做路径构建:
Server Cert ← Intermediate CA Cert ← Root CA Trust Anchor匹配依据包括:
IssuerSubjectAuthority Key IdentifierSubject Key Identifier路径构建后,再做路径验证:
签名是否正确有效期是否有效用途是否允许Basic Constraints 是否正确Key Usage 是否允许签发Name Constraints 是否满足路径长度是否满足是否吊销5.6 域名匹配
现代证书主要看:
Subject Alternative Name / SAN例如:
DNS:www.example.comDNS:*.example.com如果用户访问:
https://www.example.com则证书 SAN 必须匹配:
www.example.com通配符匹配有边界:
*.example.com 可以匹配 a.example.com通常不能匹配 a.b.example.com如果证书链验签通过,但域名不匹配,浏览器仍然不能信任它。
5.7 Basic Constraints 与 Key Usage
中间 CA 证书必须说明自己是 CA:
Basic Constraints: CA = TRUE并且必须允许签发证书:
Key Usage: keyCertSign服务器证书通常需要:
Key Usage: digitalSignatureExtended Key Usage: serverAuth否则它不能被用作 TLS 服务器认证。
5.8 吊销检查
证书可能在有效期内被撤销,例如:
私钥泄露证书误签发域名控制权变化CA 发现错误常见机制:
CRL:证书吊销列表OCSP:在线证书状态协议OCSP Stapling:服务器在握手中附带 OCSP 响应现实浏览器对吊销检查有工程权衡,不同浏览器策略可能不同,但概念上吊销属于证书验证链的一部分。
5.9 证书链的安全本质嵌入总结
证书链依赖底层签名算法的不可伪造性。
整体逻辑是:
Root CA 私钥签 Intermediate CA 证书Intermediate CA 私钥签 Server 证书Server 私钥签 TLS 握手 transcript浏览器只需要持有公钥就能逐层验证:
Root CA 公钥验 IntermediateIntermediate CA 公钥验 ServerServer 公钥验 CertificateVerify攻击者失败的原因是:
没有 CA 私钥,不能伪造下级证书签名没有 Server 私钥,不能伪造 CertificateVerify这就是 HTTPS 身份认证链路的核心。
6. 数字签名体系:RSA-PSS、ECDSA、EdDSA
数字签名在 HTTPS 中主要出现在两个地方:
1. CA 给证书签名2. 服务器在 CertificateVerify 中给握手 transcript 签名签名解决的问题:
身份认证防篡改不可伪造签名不是为了隐藏内容。
证书内容、握手 transcript 的大部分结构并不是靠签名隐藏,而是靠签名保证:
这确实是某个私钥持有者签过的内容没有被改过6.1 RSA-PSS:基于 RSA 陷门函数的现代签名
RSA-PSS 是现代推荐的 RSA 签名方案之一。
RSA 的核心是典型陷门函数:
正向容易:M → M^e mod n反向困难:没有 d 很难从 C 求 M陷门:p/q/φ(n)/dRSA-PSS 把这个 RSA 陷门能力用于签名。
6.1.1 RSA 密钥生成
选择两个大素数:
p, q计算:
n = p × qφ(n) = (p - 1)(q - 1)选择公钥指数:
e常见:
e = 65537计算私钥指数:
d = e^{-1} mod φ(n)也就是:
e × d ≡ 1 mod φ(n)公钥:
(n, e)私钥:
(n, d)工程私钥通常还保存:
p, q, dp, dq, qInv用于 CRT 加速。
6.1.2 RSA 为什么是陷门函数
公开信息:
n, e秘密信息:
p, q, φ(n), d正向计算:
Y = X^e mod n很容易,用快速模幂即可。
反向求解:
给定 Y,求 X如果没有 d,就相当困难。
但如果知道 d:
X = Y^d mod n可以高效恢复。
为什么 d 难得到?
因为:
d = e^{-1} mod φ(n)而:
φ(n) = (p - 1)(q - 1)要知道 φ(n),通常需要知道 p 和 q。
而从:
n = p × q反推出:
p, q是大整数分解问题,在足够大参数下不可行。
所以 RSA 的陷门就是:
p/q 或 d6.1.3 RSA 正确性公式
RSA 的基本数学关系:
e × d ≡ 1 mod φ(n)所以存在整数 k:
ed = 1 + kφ(n)对消息代表的整数 M:
(M^e)^d= M^(ed)= M^(1 + kφ(n))= M × (M^φ(n))^k根据欧拉定理:
M^φ(n) ≡ 1 mod n所以:
M^(ed) ≡ M mod n这就是为什么:
公钥指数 e 做过的事情私钥指数 d 能在模 n 世界里配套还原签名方向也是同一个数学关系:
S = EM^d mod nEM = S^e mod n6.1.4 RSA-PSS 签名不是裸 RSA
真实签名不能直接:
S = Hash(message)^d mod n因为裸 RSA 具有代数结构,容易被构造攻击。
RSA-PSS 会先做安全编码:
输入:
messagehash algorithm,例如 SHA-256saltMGF1RSA private key步骤:
mHash = Hash(message)
salt = random bytes
M' = 0x00 00 00 00 00 00 00 00 || mHash || salt
H = Hash(M')
DB = PS || 0x01 || salt
dbMask = MGF1(H)
maskedDB = DB XOR dbMask
EM = maskedDB || H || 0xbc
S = EM^d mod n验签:
EM = S^e mod n
检查:1. 最后字节是否 0xbc2. maskedDB 是否能正确恢复 DB3. DB 中 PS || 0x01 || salt 格式是否正确4. 用恢复出的 salt 和 message hash 重新计算 H5. H 是否一致6.1.5 RSA-PSS 的安全本质嵌入总结
RSA-PSS 的安全来自两层:
1. RSA 陷门函数: 没有私钥 d,无法生成能被公钥 e 验证的 RSA 结果。
2. PSS 编码: salt + Hash + MGF1 + 严格格式,让签名不再是裸 RSA 的简单代数结构。它在 TLS 中常用于:
证书签名CertificateVerify6.2 ECDSA:基于椭圆曲线离散对数的签名
ECDSA 是现代 TLS 证书和服务器签名中常见的算法之一。
它和 ECDHE 一样基于椭圆曲线离散对数困难。
6.2.1 ECDSA 的密钥关系
公开基点:
G曲线阶:
n私钥:
d公钥:
Q = dG安全本质:
知道 d 和 G,算 Q = dG 容易知道 Q 和 G,求 d 困难这仍然是 ECDLP。
6.2.2 ECDSA 签名流程
对消息:
message先哈希:
z = Hash(message)生成一次性随机数:
k计算曲线点:
R = kG取:
r = x_R mod n如果 r = 0,重新选择 k。
计算:
s = k^{-1}(z + r d) mod n如果 s = 0,重新选择 k。
签名:
(r, s)6.2.3 ECDSA 验签流程
输入:
messagesignature = (r, s)public key Q先检查:
1 <= r <= n-11 <= s <= n-1计算:
z = Hash(message)
w = s^{-1} mod n
u1 = z w mod n
u2 = r w mod n
R' = u1G + u2Q验签条件:
r == x_{R'} mod n6.2.4 ECDSA 为什么能验签
签名时:
s = k^{-1}(z + rd) mod n两边整理:
k = s^{-1}(z + rd) mod n验签时:
w = s^{-1}u1 = zwu2 = rw所以:
u1G + u2Q= zwG + rwQ因为:
Q = dG所以:
u1G + u2Q= zwG + rw(dG)= w(z + rd)G= s^{-1}(z + rd)G= kG= R所以验签方重构出了签名时的 R,只需检查:
r 是否等于 R 的 x 坐标 mod n6.2.5 ECDSA 为什么不泄露私钥
验签方知道:
Q = dGrsz但不知道:
dk要从 Q = dG 求 d,仍然是 ECDLP。
因此,验签可以确认代数关系成立,却不能推出私钥。
6.2.6 ECDSA 的关键风险:k 不能复用
如果两个消息复用了同一个 k:
s1 = k^{-1}(z1 + rd) mod ns2 = k^{-1}(z2 + rd) mod n相减:
s1 - s2 = k^{-1}(z1 - z2) mod n推出:
k = (z1 - z2)(s1 - s2)^{-1} mod n一旦得到 k,由:
s = k^{-1}(z + rd)可得:
sk = z + rd所以:
d = (sk - z)r^{-1} mod n这意味着:
ECDSA nonce k 一旦复用或泄露,私钥 d 可能直接暴露。这也是为什么 ECDSA 实现必须极其重视随机数或确定性 nonce。
6.2.7 ECDSA 的安全本质嵌入总结
ECDSA 的安全来自:
1. 私钥 d 到公钥 Q = dG 正向容易2. 公钥 Q 到私钥 d 反向困难3. 签名公式把 d 隐藏在模运算关系中4. 验签方能验证关系成立,但不能从关系中求出 d5. k 必须安全,否则私钥可能泄露6.3 EdDSA / Ed25519:更现代的 Edwards 曲线签名
EdDSA 是 Edwards-curve Digital Signature Algorithm,常见实例是 Ed25519。
它也基于椭圆曲线离散对数困难,但相比 ECDSA,在工程实现上更不容易踩随机数坑。
6.3.1 EdDSA 密钥关系
基点:
B私钥派生出的标量:
a公钥:
A = aB安全本质仍然是:
知道 a 和 B,算 A = aB 容易知道 A 和 B,求 a 困难6.3.2 EdDSA 签名高层流程
EdDSA 的具体细节较多,这里给出核心逻辑。
对消息:
message生成确定性 nonce:
r = Hash(prefix || message)计算:
R = rB计算挑战:
h = Hash(R || A || message)计算:
S = r + h a mod L签名:
signature = (R, S)6.3.3 EdDSA 验签关系
验签检查:
SB == R + hA为什么成立?
因为:
S = r + ha所以:
SB= (r + ha)B= rB + h(aB)= R + hA验证者知道:
BARSmessage可以计算:
h = Hash(R || A || message)并检查:
SB 是否等于 R + hA但不能从:
A = aB反推出:
a因为这仍然是椭圆曲线离散对数问题。
6.3.4 EdDSA 的工程优势
EdDSA 常见优势:
签名 nonce 通常确定性生成减少传统 ECDSA 随机 k 出错风险性能好实现相对规整适合现代协议生态但在公开 Web PKI/TLS 证书生态中,RSA 和 ECDSA 仍然非常常见;Ed25519 的实际可用性取决于 CA、浏览器、TLS 栈支持。
7. AEAD 记录层加密:AES-GCM 与 ChaCha20-Poly1305
TLS 握手完成后,真正的 HTTP 数据不再用非对称算法处理,而是用对称 AEAD。
AEAD 是:
Authenticated Encryption with Associated Data它同时提供:
保密性完整性认证性7.1 AEAD 在 TLS 中负责什么
TLS 应用数据加密输入:
plaintext:HTTP 数据key:application write keynonce:每条记录唯一的 nonceaad:TLS record header 等关联数据输出:
ciphertexttag接收方:
用同样 key 和 nonce 验证 tagtag 正确才释放 plaintexttag 错误直接失败AEAD 的核心工程原则:
1. 同一个 key 下 nonce 绝不能重复2. 必须先验证 tag,再使用 plaintext3. AAD 虽不加密,但被认证7.2 TLS 1.3 记录 nonce 构造
TLS 1.3 通常不是每条记录随机生成 nonce。
它使用:
per_record_nonce = static_write_iv XOR padded_sequence_number其中:
static_write_iv:HKDF 派生sequence_number:每个方向从 0 递增这样保证:
同一个连接、同一个方向、同一个 key 下,nonce 不重复7.3 AES-GCM:AES-CTR 加密 + GHASH 认证
AES-GCM 是现代 TLS 最常见 AEAD 之一。
它由两部分组成:
AES-CTR:负责加密GHASH:负责认证7.3.1 AES 是什么
AES 是对称分组密码。
NIST FIPS 197 定义了:
AES-128AES-192AES-256共同点:
分组大小:128 bit密钥长度:128 / 192 / 256 bit轮数:10 / 12 / 14AES 对一个 128-bit block 做多轮变换:
SubBytesShiftRowsMixColumnsAddRoundKey其中:
SubBytes:提供非线性ShiftRows:改变字节位置MixColumns:扩散列内影响AddRoundKey:混入轮密钥AES 的安全本质不是“单向陷门函数”。
它是:
密钥控制的伪随机置换知道 key:
可以加密可以解密不知道 key:
无法预测输出无法反推出明文7.3.2 AES-CTR 如何加密
GCM 中的加密部分本质是 CTR。
给定:
key Knoncecounter生成计数器块:
counter_1counter_2counter_3...计算密钥流:
stream_1 = AES_K(counter_1)stream_2 = AES_K(counter_2)stream_3 = AES_K(counter_3)明文分块:
P1, P2, P3加密:
C1 = P1 XOR stream_1C2 = P2 XOR stream_2C3 = P3 XOR stream_3解密:
P1 = C1 XOR stream_1因为:
X XOR Y XOR Y = X7.3.3 GHASH 如何认证
GCM 的认证部分 GHASH 在有限域:
GF(2^128)上计算。
先生成认证子密钥:
H = AES_K(0^128)然后对:
AADciphertext长度信息做有限域乘法累积:
GHASH_H(AAD, ciphertext)最终 tag 概念上是:
tag = AES_K(J0) XOR GHASH_H(AAD, ciphertext)如果攻击者修改:
AADciphertextlengthtag接收方重新计算 tag 会不一致。
7.3.4 AES-GCM 为什么 nonce 不能复用
如果同一个 key 下复用 nonce,CTR 会生成相同密钥流:
C1 = P1 XOR KSC2 = P2 XOR KS两者 XOR:
C1 XOR C2 = P1 XOR P2这会泄露明文关系。
对 GCM 来说,nonce 复用还可能破坏认证安全,导致 tag 可伪造风险。
所以 TLS 通过 sequence number 构造 nonce,避免重复。
7.3.5 AES-GCM 的安全本质嵌入总结
AES-GCM 的安全来自:
1. AES 在未知 key 下像伪随机置换2. CTR 生成不可预测密钥流3. GHASH 绑定 AAD、ciphertext 和长度4. tag 阻止篡改5. nonce 不复用是必要条件它不是公钥陷门函数,而是:
对称密钥控制的认证加密7.4 ChaCha20-Poly1305:ARX 流加密 + Poly1305 认证
ChaCha20-Poly1305 是 TLS 1.3 的另一种主流 AEAD。
它特别适合没有 AES 硬件加速的环境。
7.4.1 ChaCha20 输入
ChaCha20 输入:
256-bit key96-bit nonce32-bit counter构造 4×4 的 32-bit word 状态矩阵:
constant | constant | constant | constantkey | key | key | keykey | key | key | keycounter | nonce | nonce | nonce7.4.2 Quarter Round
ChaCha20 的核心是 quarter round,对四个 32-bit word:
a, b, c, d执行:
a += b; d ^= a; d <<<= 16;c += d; b ^= c; b <<<= 12;a += b; d ^= a; d <<<= 8;c += d; b ^= c; b <<<= 7;其中:
+=:32-bit 加法^=:XOR<<<=:循环左移ChaCha20 属于 ARX 结构:
AdditionRotationXOR它通过多轮 ARX 混合实现扩散和伪随机性。
7.4.3 ChaCha20 如何加密
ChaCha20 经过 20 轮后输出密钥流块:
keystream_block = ChaCha20_Block(key, nonce, counter)加密:
ciphertext = plaintext XOR keystream解密:
plaintext = ciphertext XOR keystream不知道 key,就无法生成同样的 keystream。
7.4.4 Poly1305 如何认证
Poly1305 是一次性消息认证码。
在 ChaCha20-Poly1305 中:
poly1305_key = ChaCha20_Block(key, nonce, counter=0) 的前 256 bit然后用这个 one-time key 对:
AADciphertextlengths计算 tag。
发送:
ciphertext || tag接收方重新计算 tag,只有 tag 一致才接受。
7.4.5 ChaCha20-Poly1305 为什么 nonce 也不能复用
如果同一 key 下 nonce 复用,ChaCha20 会生成相同密钥流:
C1 = P1 XOR KSC2 = P2 XOR KS所以:
C1 XOR C2 = P1 XOR P2这直接泄露明文关系。
同时 Poly1305 one-time key 也会复用,破坏认证安全。
7.4.6 ChaCha20-Poly1305 的安全本质嵌入总结
ChaCha20-Poly1305 的安全来自:
1. ChaCha20 在未知 key 下输出不可预测 keystream2. Poly1305 在 one-time key 下提供消息认证3. nonce 不复用保证 keystream 和 one-time MAC key 不重复4. tag 防止密文和 AAD 被篡改它也是:
对称 AEAD不是非对称陷门函数。
8. RSA-OAEP:现代可用的公钥加密方案,但不是 TLS 1.3 主线
RSA-OAEP 仍是现代安全的 RSA 公钥加密方案之一。
但它不是 TLS 1.3 中协商会话密钥的主线。
TLS 1.3 主线是:
ECDHE + HKDFRSA-OAEP 可作为理解 RSA 公钥加密/私钥解密的现代方案,也可用于某些应用层密钥封装场景。
8.1 RSA-OAEP 解决什么问题
它解决:
发送方想把一个短明文 K 安全发给持有 RSA 私钥的一方例如:
K = 随机对称密钥公钥加密:
C = Encrypt(publicKey, K)私钥解密:
K = Decrypt(privateKey, C)8.2 RSA-OAEP 中的陷门原理
RSA 公钥:
(n, e)RSA 私钥:
(n, d)加密核心:
C = M^e mod n解密核心:
M = C^d mod n陷门是:
d而 d 的来源是:
p, q → φ(n) → d公开 n 和 e 不足以高效得到 d,因为需要分解:
n = p × q这就是 RSA 的单向陷门本质。
8.3 为什么需要 OAEP,不直接加密 K
裸 RSA 是确定性的。
如果直接:
C = K^e mod n同一个 K 每次加密结果相同。
这会带来安全问题。
OAEP 会先把 K 编码成带随机性的块 M:
K + seed + padding + hash → M然后 RSA 加密的是:
M而不是裸 K。
8.4 OAEP 编码结构
OAEP 大致流程:
DB = lHash || PS || 0x01 || K
seed = random bytes
dbMask = MGF(seed)
maskedDB = DB XOR dbMask
seedMask = MGF(maskedDB)
maskedSeed = seed XOR seedMask
M = 0x00 || maskedSeed || maskedDB加密:
C = M^e mod n解密:
M = C^d mod n然后反向恢复:
maskedSeed, maskedDB ↓seed ↓DB ↓K8.5 OAEP 的安全本质嵌入总结
RSA-OAEP 的安全来自:
1. RSA 陷门函数: 无 d 难以从 C 恢复 M。
2. OAEP 随机编码: 同一个 K 每次生成不同 M,避免裸 RSA 确定性问题。
3. Hash + MGF: 让编码块结构可校验,防止构造攻击。它仍是现代可用的 RSA 加密方案,但在现代 HTTPS/TLS 1.3 里,它不是密钥交换主线。
9. 现代推荐与弃用技术边界
9.1 当前主讲/推荐关注
| 模块 | 当前主流/推荐 |
|---|---|
| 协议版本 | TLS 1.3,兼容 TLS 1.2 安全套件 |
| 密钥协商 | ECDHE,X25519、P-256、P-384 |
| 密钥派生 | HKDF + SHA-256/SHA-384 |
| 对称 AEAD | AES-GCM、ChaCha20-Poly1305 |
| 签名 | RSA-PSS、ECDSA、EdDSA/Ed25519 视生态支持 |
| 证书 | X.509、SAN、CA 证书链、OCSP/CRL |
| 哈希 | SHA-256、SHA-384 |
9.2 不推荐/弃用/不作为主线
| 技术 | 状态 | 原因 |
|---|---|---|
| SSLv2 / SSLv3 | 废弃 | 存在严重协议安全问题 |
| TLS 1.0 / TLS 1.1 | 废弃 | 已被正式弃用,缺少现代算法机制 |
| RSA Key Exchange | TLS 1.3 移除 | 不具备前向安全性 |
| 静态 DH / 静态 ECDH | 不推荐 | 不具备临时密钥带来的前向安全性 |
| RC4 | 禁用 | 存在严重偏差和攻击 |
| 3DES | 淘汰 | 64-bit block 风险,性能和安全性落后 |
| CBC TLS 套件 | 不推荐 | 历史上多次 padding oracle 类攻击 |
| MD5 / SHA-1 签名 | 不推荐 | 碰撞风险 |
| DSA | 基本退出主流 Web TLS | 现代生态由 RSA/ECDSA/EdDSA 主导 |
| EXPORT 套件 | 禁用 | 人为弱化加密,历史攻击严重 |
| TLS 压缩 | 不推荐 | CRIME 类压缩侧信道风险 |
10. 最终总结
现代 HTTPS 的安全不是靠某一个算法,而是一整套密码学结构:
ECDHE: 正向 a → aG 容易 反向 aG → a 困难 双方利用 a(bG)=b(aG)=abG 协商共享秘密
证书链: 上级 CA 私钥签下级证书 浏览器用上级公钥逐层验签 最终确认服务器公钥属于目标域名
CertificateVerify: 服务器用证书对应私钥签握手 transcript 浏览器用服务器公钥验签 防止中间人替换 ECDHE 参数
HKDF: 从 ECDHE shared secret 和 transcript_hash 派生多把隔离密钥 把密钥和握手上下文绑定
AES-GCM / ChaCha20-Poly1305: 用对称密钥加密 HTTP 数据 用 tag 防篡改 nonce 不能复用
RSA-PSS / ECDSA / EdDSA: 用于证书签名和服务器签名 依赖 RSA 陷门或椭圆曲线离散对数困难一句话:
现代 HTTPS = 椭圆曲线单向困难问题协商密钥 + CA 签名链认证身份 + HKDF 派生密钥 + AEAD 保护数据。再压缩一点:
ECDHE 解决“怎么安全得到同一个秘密”证书链解决“这个服务器公钥是不是真的”签名解决“服务器是否真的持有私钥”HKDF 解决“怎么从秘密变出多把密钥”AEAD 解决“后续数据怎么加密且防篡改”11. 参考文献
-
Rescorla, E. RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3. IETF, 2018.
https://datatracker.ietf.org/doc/html/rfc8446 -
Sheffer, Y., Saint-Andre, P., Fossati, T. RFC 9325: Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS). IETF, 2022.
https://datatracker.ietf.org/doc/html/rfc9325 -
Langley, A., Hamburg, M., Turner, S. RFC 7748: Elliptic Curves for Security. IETF, 2016.
https://datatracker.ietf.org/doc/html/rfc7748 -
Barker, E. et al. NIST SP 800-56A Rev. 3: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography. NIST, 2018.
https://csrc.nist.gov/pubs/sp/800/56/a/r3/final -
National Institute of Standards and Technology. FIPS 186-5: Digital Signature Standard (DSS). NIST, 2023.
https://csrc.nist.gov/pubs/fips/186-5/final -
Cooper, D. et al. RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List Profile. IETF, 2008.
https://datatracker.ietf.org/doc/html/rfc5280 -
Moriarty, K. et al. RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2. IETF, 2016.
https://datatracker.ietf.org/doc/html/rfc8017 -
Krawczyk, H., Eronen, P. RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF). IETF, 2010.
https://datatracker.ietf.org/doc/html/rfc5869 -
National Institute of Standards and Technology. FIPS 197: Advanced Encryption Standard (AES). NIST, updated 2023.
https://csrc.nist.gov/pubs/fips/197/final -
McGrew, D. RFC 5116: An Interface and Algorithms for Authenticated Encryption. IETF, 2008.
https://datatracker.ietf.org/doc/html/rfc5116 -
Nir, Y., Langley, A. RFC 8439: ChaCha20 and Poly1305 for IETF Protocols. IETF, 2018.
https://datatracker.ietf.org/doc/html/rfc8439 -
Josefsson, S., Liusvaara, I. RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA). IETF, 2017.
https://datatracker.ietf.org/doc/html/rfc8032 -
Turner, S., Polk, T. RFC 8996: Deprecating TLS 1.0 and TLS 1.1. IETF, 2021.
https://datatracker.ietf.org/doc/html/rfc8996 -
CA/Browser Forum. Baseline Requirements for the Issuance and Management of Publicly-Trusted TLS Server Certificates.
https://cabforum.org/working-groups/server/baseline-requirements/requirements/