4、密钥交换算法(一):RSA密钥交换原理、Pre-Master Secret的生成与解密流程

做TLS握手的人都知道,RSA密钥交换曾经是的主流。你打开十年前的开源项目,全是RSA。为什么?因为它简单、成熟,你只需要一把公钥就能完成密钥协商。但后来大家发现它有个要命的短板——没有前向安全性。这个坑,我后面会细说。

4.1 RSA密钥交换的核心思想

说白了,RSA密钥交换就是客户端用服务器的RSA公钥加密一个随机值,服务器用自己的私钥解密出来。这个随机值就是Pre-Master Secret,后续所有会话密钥都源于它。

我记得刚接触TLS时,总觉得这不就是普通的公钥加密吗?有什么好讲的?后来真去抓包分析才发现,细节全在填充和随机数生成里。嗯,这里要注意。

核心原则:RSA不能直接加密大量数据,所以只用来传递一个48字节的Pre-Master Secret。密钥交换完成后,对称加密接管后续通信。

4.2 Pre-Master Secret的生成

Pre-Master Secret只有48字节。它的结构非常固定:

字段 长度 说明
Client Version 2 字节 客户端支持的TLS最高版本号(例如 TLS 1.2 为 0x0303)
Random Data 46 字节 由密码学安全随机数生成器产生的随机值

你看,版本号只有2字节,剩下的46字节必须纯随机。我曾经在一个项目中遇到过底层随机数生成器被截断的Bug——每次握手的前10个字节都一样。那真是噩梦,排查了三天才发现是OpenSSL的FIPS模块初始化顺序问题。所以,随机数的质量,我建议你用/dev/urandom或者系统的CryptGenRandom,别再信那些“自定义伪随机”了。

4.3 加密与解密流程

整个过程分两步走。我习惯用下图来帮助理解:

RSA 密钥交换流程(Pre-Master Secret 传递) 客户端 1. 生成 48 字节 Pre-Master Secret (Client Version + 46 随机) 2. 用服务器公钥加密 (PKCS#1 v1.5 / OAEP 填充) 3. 发送 ClientKeyExchange 包含 EncryptedPreMasterSecret 4. 客户端计算 Master Secret → 会话密钥 服务器 1. 收到 EncryptedPreMasterSecret 2. 用自己的私钥解密 3. 提取 Pre-Master Secret 4. 校验 Client Version 5. 计算 Master Secret 6. 生成会话密钥 ClientKeyExchange (加密后的 PMS) 服务器解密后必须验证 Client Version,防止版本号回滚攻击

解密流程中,服务器端会做这几件事:

  1. 私钥解密:用RSA私钥把EncryptedPreMasterSecret还原成48字节明文。
  2. 版本校验:取出前2字节与ClientHello中声明的版本比对。如果不一致,很多实现会直接终止握手。
  3. 提取随机数据:后46字节就是随机种子,与客户端生成的Client Random、服务器生成的Server Random一起,通过PRF(伪随机函数)生成Master Secret。
// 示意:OpenSSL 中的解密处理(极简)
// EVP_PKEY_decrypt 会自动处理填充
int decrypt_pre_master(EVP_PKEY *pkey, const unsigned char *enc, size_t enc_len,
                       unsigned char *pms, size_t *pms_len) {
    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
    EVP_PKEY_decrypt_init(ctx);
    // 设置填充模式,通常为 PKCS1_OAEP_PADDING
    EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
    EVP_PKEY_decrypt(ctx, pms, pms_len, enc, enc_len);
    EVP_PKEY_CTX_free(ctx);
    return 0;
}

填充模式之争:老协议(SSL 3.0 / TLS 1.0)常用 PKCS#1 v1.5 填充,但这个模式被Bleichenbacher攻击锤了十几年。TLS 1.2 开始推荐使用 RSAES-OAEP。我的建议——新项目一律用OAEP。

4.4 为什么RSA密钥交换逐渐被替代?

你想想看,RSA密钥交换最大的问题是什么?没有前向安全性(Perfect Forward Secrecy, PFS)。服务器私钥如果泄露,攻击者可以解密以前记录的所有会话。因为Pre-Master Secret是用公钥加密的,只要私钥在手,就能还原所有旧的Master Secret。

我曾经帮一家银行做安全审计,他们所有的HTTPS流量还是RSA密钥交换。我建议他们马上切到ECDHE。对方CTO还犹豫:“RSA用得好好的,换什么?”直到我演示了私钥泄露模拟——一个抓包文件里六个月的会话全被解密。第二天,排期就上了。

⚠️ 严重警告:截止2025年,主流浏览器和服务器已经默认禁用 RSA 密钥交换(TLS 1.3 直接移除)。如果你还在用 TLS_RSA_WITH_AES_128_GCM_SHA256 这类套件,请立即清理。它能帮你兼容老设备,但代价是你的会话没有PFS保障。

总结一下RSA密钥交换的优缺点:

优势 劣势
实现简单,所有TLS库都支持 无前向安全性(私钥泄露=所有会话泄露)
客户端无需生成密钥对 不支持临时密钥协议,无法抵抗被动窃听
兼容性极好(旧设备、旧浏览器) RSA密钥长度增加会加大计算开销