D
开发工具箱

RSA 加密原理:从大数分解到 HTTPS 的基石

加密解密 2026年6月15日 约 1 分钟阅读

什么是 RSA?

RSA 是目前应用最广泛的非对称加密算法。非对称的意思是:加密和解密用两把不同的钥匙——公钥加密,私钥解密。公钥可以随便分发,私钥必须死守。

打个比方:RSA 就像街边的公共邮筒。任何人都能把信投进去(公钥加密),但只有邮递员手里的钥匙能打开取信(私钥解密)。这个比喻虽然老套,但确实抓到了 RSA 最核心的设计意图。

我第一次真正理解 RSA 是在配置 GitHub SSH 密钥的时候。当时照着教程生成了一个 id_rsa 文件和一个 id_rsa.pub 文件,把 .pub 上传到 GitHub 就行了。我心想:这不就等于把钥匙的一半公开了吗?后来才明白——私钥在我电脑里,公钥在 GitHub 上,我拿私钥签名,GitHub 拿公钥验证。整个过程里私钥从来没出过我的机器。

RSA 这个名字取自三位发明者的姓氏首字母:Ron Rivest、Adi Shamir 和 Leonard Adleman。1977 年,他们在 MIT 实验室里提出了这个方案。值得一提的是,英国 GCHQ 的数学家 Clifford Cocks 其实在 1973 年就独立发现了等价的算法,但因为军事保密直到 1997 年才解密——密码学史上这类”被埋没的第一发现者”故事还有很多。

RSA 的工作原理

坦白讲,RSA 背后的数学不算浅。但如果你愿意花十分钟跟着我走一遍下面这个小数字的例子,你会发现核心思路其实就一句话:两个大素数相乘容易,把乘积分解回去难,这个不对称性就是 RSA 的全部根基。

先用小数字走一遍完整流程

假设我们选了这两个素数(专业术语:p 和 q):

p = 3, q = 11

下面这五步就是上面这行数学生成密钥的全过程,点「播放」可以一步步看:

p = 3 q = 11 随机挑选的两个素数(实际各 1024 位) n = p × q = 33公钥和私钥共用的模数 这个可以公开 φ(n) = (p-1)(q-1) = 201 到 32 中与 33 互质的数的个数 ⚠ 必须严格保密 e = 31 < e < φ(n) 且与 φ(n) 互质 实际通用取值 65537 d = 7e × d ≡ 1 (mod φ(n)) 3 × 7 = 21 ≡ 1 (mod 20) 公钥 (n=33, e=3)可以公开发布 私钥 (n=33, d=7)必须严格保密 实际使用中 p、q 各约 1024 位,n 是 2048 位的大整数
图 1:RSA 密钥生成。两个素数相乘得到模数 n,由 n 推出欧拉函数 φ(n)(必须保密),再选公钥指数 e 并求出它的模逆元 d。公钥 (n, e) 公开,私钥 (n, d) 保密。点上面的「播放」可以看每一步。

第一步:算 n。 n = p × q = 3 × 11 = 33。这个 33 会成为公钥和私钥的公共部分。

第二步:算 φ(n)。 这是欧拉函数值,对于两个素数的乘积,φ(n) = (p-1) × (q-1) = 2 × 10 = 20。它的含义是:1 到 33 之间有多少个数和 33 互质。这个 20 不能公开。

第三步:选公钥指数 e。 e 要满足两个条件:1 < e < φ(n),且 e 和 φ(n) 互质。φ(n) = 20,我们选 e = 3(3 和 20 互质,满足条件)。公钥就是 (n=33, e=3)。

第四步:算私钥指数 d。 d 是 e 关于模 φ(n) 的乘法逆元,也就是 e × d ≡ 1 (mod φ(n))。3 × d ≡ 1 (mod 20),穷举一下 d=7 成立(3×7=21 ≡ 1 mod 20)。私钥就是 (n=33, d=7)。

加解密验证: 假设我们要加密的消息 m = 8(要求 m < n):

加密:c = m^e mod n = 8^3 mod 33 = 512 mod 33 = 17
解密:m = c^d mod n = 17^7 mod 33

17^7 手动算有点大,但你可以拿工具验证:17^7 = 410338673,410338673 / 33 的余数等于 8。解密成功!

把上面这串计算画成图,就是一次完整的 RSA 加解密:

接收方生成密钥对公钥 (n=33, e=3) 公开 私钥 (n=33, d=7) 自留 明文 m = 8 要求 m < n(本例 8 < 33) 加密 c = m^e mod nc = 8^3 mod 33 = 17 公钥 (n=33, e=3)公开给全世界 密文 c = 17 在不安全信道上传输 解密 m = c^d mod nm = 17^7 mod 33 = 8 私钥 (n=33, d=7)只有接收方持有 明文 m = 8(还原成功) 窃听者知道 n=33、e=3、c=17,但要求出 d 必先分解 n = 3 × 11 n 若是 2048 位,分解它需要的时间比宇宙年龄还长
图 2:RSA 的一次完整加解密。发送方用公开的公钥做加密,密文即使被截获也无妨,只有持有私钥的接收方能还原。点上面的「播放」可以看数据是怎么变化的。

为什么别人破解不了?

你公开发布了 n=33 和 e=3。攻击者想要算出 d=7,唯一的办法是先算出 φ(n) = 20。要算 φ(n) 就得知道 p 和 q——而要知道 p 和 q,就必须把 33 分解成 3 × 11。

33 当然一秒钟就分解了。但如果 p 和 q 是两颗各 300 多位的素数呢?它们的乘积 n 是一个 600 多位的大整数。以目前已知最好的分解算法(数域筛法)和全球算力总和,分解一个 2048 位的 RSA 模数需要的时间比宇宙年龄还长。这就是 RSA 安全性的全部底气。

这个”单向性”是整个 RSA 的地基,值得单独画一张图:

p1024 位大素数 q1024 位大素数 n = p × q(2048 位)相乘:毫秒级,计算机最擅长的事 ✓ 容易,这就是 RSA 的正向 p = ? q = ? ✗ 极难:数域筛法 + 全球算力 也要数万亿年 攻击者已知公钥 (n, e) 想求私钥 d 需先求φ(n) 需先分解n → p, q 结论走不通 RSA 的全部安全性,就建立在「大数分解在计算上不可行」这一条假设上 算法完全公开,攻击者知道你在用什么数学,就是解不开 768 位:2009 年被分解 1024 位:已不建议使用 2048 位:目前安全
图 3:RSA 依赖的单向性。两个大素数相乘只要毫秒,反过来把乘积分解回素数却要数万亿年——这个不对称就是全部安全性的来源。点上面的「播放」可以看攻击者为什么走投无路。

说白了,RSA 的安全性不来自任何”巧妙隐藏”,而完全建立在”大数分解在计算上不可行”这一条假设上。这很反直觉——一个外人完全知道你在用什么数学做加密,他就是解不开。这也是密码学和日常”秘密”最大的区别。

数学灵魂:欧拉定理

上面 d 的求法不是随便来的。RSA 的正确性依赖欧拉定理:如果 m 和 n 互质,则 m^φ(n) ≡ 1 (mod n)。

加密是 m^e mod n,解密是再对密文做 d 次幂:(m^e)^d = m^(ed) = m^(kφ(n) + 1) = (m^φ(n))^k × m ≡ 1^k × m ≡ m (mod n)。严谨的证明要处理 m 和 n 不互质的情况,但借助中国剩余定理可以证明那个场景下照样成立。

说实话,我第一次看到这个证明的时候也感觉像变魔术——明明是做了模指数运算,绕了一圈又回到了原点。但把 e 和 d 代入那个等式中一步步化简之后,就觉得这设计真的特别干净。

上面那段推导拆成一步步,是这样走的:

1 加密 c = m^e mod n本例:c = 8^3 mod 33 = 17 2 解密 c^d = (m^e)^d = m^(e·d) mod n指数相乘:e·d = 3 × 7 = 21 3 关键:e·d = k·φ(n) + 121 = 1 × 20 + 1,即 k = 1、φ(n) = 20 4 m^(e·d) = m^(k·φ(n)+1) = (m^φ(n))^k × m本例:8^21 = (8^20)^1 × 8 5 欧拉定理:m^φ(n) ≡ 1 (mod n)8^20 ≡ 1 (mod 33),于是 (1)^1 × 8 = 8 ≡ 1^k × m ≡ m (mod n),明文还原绕了一圈回到原点:m = 8 ✓
图 4:RSA 正确性的推导。加密解密合起来是 m^(e·d),而 e·d = k·φ(n) + 1,拆开后由欧拉定理 m^φ(n) ≡ 1 (mod n) 消掉多余项,明文就回到了原点。点上面的「播放」可以看这个化简过程。

核心特性

特性说明
类型非对称加密(公钥密码)
安全性基础大整数因数分解的计算困难性
常用密钥长度2048 位、3072 位、4096 位
速度比 AES 慢 100-1000 倍,不适合加密大量数据
密钥对公钥 (n, e) + 私钥 (n, d)
应用密钥交换、数字签名、证书体系
标准化PKCS#1、RFC 8017、FIPS 186-4

有一回我在一个低配 VPS 上用纯软件 RSA(没有硬件加速)加密一个 1MB 的文件,等了快两分钟才跑完。再用 AES-256-GCM 试试同一台机器——不到 0.01 秒。从那以后我对”RSA 只用来加密会话密钥”这件事有了血肉层面的理解。

实际应用场景

1. HTTPS / TLS 握手

这是 RSA 最常见的出场舞台。你在浏览器里打开 https:// 网站时,TLS 握手阶段浏览器拿到服务器的 RSA 公钥(写在证书里),然后随机生成一个临时的对称加密密钥(会话密钥),用 RSA 公钥加密后传给服务器。服务器用私钥解密拿到这个会话密钥,之后双方切 AES-GCM 高速通信。

不过话说回来,TLS 1.3 已经逐步废弃了 RSA 密钥交换(改用 ECDHE 做前向保密),RSA 在 TLS 1.3 里主要剩下签名证书这一项职责。

2. SSH 免密登录

生成过 SSH 密钥的人都不会陌生。你本地的 ~/.ssh/id_rsa 是私钥,~/.ssh/id_rsa.pub 是公钥。公钥上传到服务器后,每次登录时服务端发一段随机数据让你用私钥签名,服务端拿公钥验证。私钥全程留在本地。

我同事的私钥权限设成了 644(所有人可读),SSH 直接拒绝使用——这个报错其实是在保护你,不是刁难你。

3. 数字签名

RSA 加密和签名是同一对数学操作的两种用法:加密是用公钥加密、私钥解密;签名是用私钥签名、公钥验证。签名时对消息的哈希值(比如 SHA-256 输出)做一次”私钥加密”,验证方用公钥”解密”得到哈希值然后比对。

代码签名(Windows 的 .exe 签名)、JWT 的 RS256 算法、PDF 电子签章,底层都是 RSA 签名。

4. PGP / GPG 邮件加密

你在 Thunderbird 里装上 Enigmail,或者直接用 gpg 命令行,就能给邮件做端到端加密。发件人拿收件人的 RSA 公钥加密邮件内容,只有收件人的私钥能解开。这跟邮筒模式的比喻严丝合缝。

5. 硬件安全模块与智能卡

银行卡芯片、U 盾、YubiKey 这些硬件里大多内置了 RSA 密钥对。私钥从出厂起就锁在芯片里,连操作系统都读不到。外部只能请芯片”帮我签一下这段数据”,芯片在内部完成签名运算后只返回结果。

常见误区

误区一:RSA 密钥越长就一定越安全

对暴力分解来说,是的。但密钥长度不能无限堆——4096 位 RSA 的运算量是 2048 位的约 8 倍(不是 2 倍),解密延迟在移动设备上会非常感人。对绝大多数场景,2048 位足够。NIST 的建议是 2030 年之前 2048 位都算安全,2030 年之后建议迁移到 3072 位。

老实说,如果你的私钥管理不合规(比如硬编码在代码仓库里),密钥再长也没用。安全事故里泄露和弱密码占了绝大多数,真正被别人分解 RSA 模数反而不是最常见的攻击路径。

误区二:RSA 可以替代 AES 直接加密大文件

不行,而且永远不应该这么做。RSA 能加密的消息长度有严格的数学限制:明文必须小于模数 n,实际中还要减去填充开销,2048 位 RSA 最多加密约 245 字节的数据。RSA 的正确用途是加密对称密钥(所谓”混合加密”),让 AES 去做大数据量的实际加解密。

误区三:RSA 签名和 RSA 加密是同一回事

操作上看似一样,但语义完全不同。加密是为了机密性,签名是为了认证和不可否认性。更关键的是,现实中不能直接把”私钥加密”当签名用——没有填充的 RSA 签名(教科书式 RSA)极其脆弱,必须用 PSS 或 PKCS#1 v1.5 签名方案。我早年写过一个”签名”功能直接拿裸 RSA 操作拼接,被做安全的朋友一顿批评——那段代码如果上生产环境,攻击者可以轻松伪造签名。

同一对密钥,两个方向,目的完全相反:

RSA 密钥对公钥 (n, e) · 私钥 (n, d) 加密方向 签名方向 明文 m 公钥加密任何人都能做 密文 c 私钥解密只有持有者能做 还原明文 消息哈希 h 私钥签名只有持有者能做 签名值 s 公钥验证任何人都能验 一致则通过 加密 = 公钥加密、私钥解密 → 保证机密性 签名 = 私钥签名、公钥验证 → 保证身份认证与不可否认性
图 5:RSA 加密与签名用的是同一对密钥,但方向完全相反。加密是公钥进私钥出,为的是不让别人看懂;签名是私钥进公钥出,为的是证明是谁签的。点上面的「播放」可以看两条路径的差异。

RSA vs ECC vs AES

RSAAESECC (ECDSA/ECDH)
类型非对称对称非对称
密钥长度2048-4096 位128/256 位256 位
速度极快比 RSA 快(同等安全强度)
主要用途签名、密钥协商数据加密签名、密钥协商
安全基础大数分解混淆扩散椭圆曲线离散对数
量子抗性弱(Shor 算法可多项式破解)中等(Grover 减半)弱(Shor 同样适用)

ECC 的崛起是个值得说的话题:达到 128 位安全强度,RSA 需要 3072 位密钥,而 ECC 只需要 256 位。在存储空间和带宽都紧张的移动端,ECC 的优势非常明显。但 RSA 胜在基础设施成熟——目前互联网证书里有半数以上还是 RSA 签名的。

不过说回正题,无论是 RSA 还是 ECC,后量子密码(PQC)的标准化都在推进中了。NIST 在 2024 年正式发布了第一批后量子标准(CRYSTALS-Kyber 等),未来 RSA 的江湖地位大概率会逐步让渡给这些新算法。

常见问题

Q: “2048 位 RSA” 的 2048 指的是什么?

指的是模数 n 的长度,也就是两个大素数的乘积有多少个二进制位。2048 位约等于 617 个十进制位——你可以脑补一下一个 617 位的整数有多大。p 和 q 各占一半,大概各 1024 位。

Q: 公钥里的 e 为什么大家都用 65537?

因为 65537 = 2^16 + 1,二进制是 10000000000000001,只有两个 1 位。用这个数做模幂运算时乘法次数最少,加密和验证签名都很快。同时 65537 是一个素数,满足和 φ(n) 互质。3 也曾经流行过,但后来发现有低指数攻击的风险,65537 成了通用的默认值。

Q: RSA 公钥和私钥可以互换使用吗?

数学上 e 和 d 确实是对称的——拿 d 加密的东西用 e 可以解开。但实践中绝不推荐这样做:私钥文件里往往包含了 CRT 加速参数(p、q、d mod(p-1) 等)可以加速解密,公钥文件不包含这些;直接拿私钥加密还会引入安全漏洞(没有正确的填充方案)。签名和加密请用各自规范定义的流程。

Q: 如果我丢了私钥,能从公钥推导出来吗?

不能。从公钥 (n, e) 推导私钥 d,唯一的已知路径是分解 n 得到 p 和 q。这恰好是大数分解难题——没法绕过。私钥丢了,加密数据等同于消失了。

Q: RSA 和 RSA-PSS、RSA-OAEP 是什么关系?

RSA 是核心数学运算(模幂),RSA-PSS 和 RSA-OAEP 是填充方案:OAEP(Optimal Asymmetric Encryption Padding)用于加密,PSS(Probabilistic Signature Scheme)用于签名。填充的目的有三:加入随机性保证语义安全、防御选择密文攻击、适配不同长度的消息。简单说,你永远不应该用”裸 RSA”——必须套上一个经过验证的填充方案。

Q: 中国国密 SM2 和 RSA 相比怎么样?

SM2 基于椭圆曲线,非对称结构类似 ECDSA。安全强度上 SM2(SM2 是 256 位曲线)和 RSA-3072 大致同级。主要区别是 SM2 采用了国产密码标准,在国内政务、金融系统里有合规要求。性能上 SM2 作为 ECC 族算法明显快于同安全强度的 RSA。