### 非对称加密算法:RSA、ECC原理及实现
#### 为什么我们需要非对称加密?
先问你一个问题吧。
对称加密就像一把钥匙开一把锁。
发消息的人和收消息的人,必须拿同一把钥匙。
这就有个大麻烦——钥匙怎么安全地交到对方手里?
我早年做项目时,就遇到过这种尴尬。
双方约定好了一个密钥,结果传输密钥的网络被截获了。
所有加密数据,瞬间成了明文。
嗯,那感觉,真不好受。
非对称加密的出现,就是为了解决这个“密钥配送”难题。
它用了两把钥匙:一把公开,一把私密。
你拿着公钥加密,只有持有私钥的人能解开。
公钥随便传,不怕人看。
这就是它的核心价值。
#### 非对称加密的核心模型
说白了,非对称加密就是一套数学单向门。
正向走很容易,逆向走几乎不可能。
`加密:明文 + 公钥 → 密文`
`解密:密文 + 私钥 → 明文`
这里面最关键的,是“单向函数”。
比如,两个大素数相乘很容易。
但给你一个大合数,让你找出是哪两个素数相乘——难上加难。
RSA就建立在这个基础上。
ECC(椭圆曲线加密)则是另一条路。
它利用了椭圆曲线上的点加法运算。
给定一个基点G,计算k*G很容易。
但给你G和k*G,让你反推出k——几乎不可能。
这就是所谓的“椭圆曲线离散对数难题”。
我个人偏爱ECC多一些。
因为它在同样的安全强度下,密钥短得多。
你想想看,这对移动端和物联网设备有多友好?
#### RSA算法:原理与实现
##### 密钥生成流程
RSA的密钥生成,大致分几步:
1. **选两个大素数**:p 和 q。越大越安全,但计算也越慢。
2. **计算 n**:n = p * q。这个n就是公钥和私钥的一部分。
3. **计算欧拉函数 φ(n)**:φ(n) = (p-1) * (q-1)。
4. **选公钥指数 e**:通常取 65537。要求 1 < e < φ(n),且 e 与 φ(n) 互质。
5. **计算私钥指数 d**:d 是 e 关于 φ(n) 的模逆元。公式是:e * d ≡ 1 (mod φ(n))。
公钥就是 (n, e),私钥就是 (n, d)。
p、q、φ(n) 这三个东西,必须销毁或严格保密。
##### 加密与解密操作
加密公式:`密文 = 明文^e mod n`
解密公式:`明文 = 密文^d mod n`
数学上,这两个操作互为逆运算。
你可能会问:“那加密后的数据能被暴力破解吗?”
理论上可以,但前提是你得把 n 分解成 p 和 q。
当 n 是2048位或4096位时,分解它需要的算力,现有计算机做不到。
##### 一个简单的RSA实现示例
我用 Node.js 的 crypto 模块演示一下。
这段代码我写在过内部工具里,供团队快速测试用。
```javascript
const crypto = require('crypto');
// 生成RSA密钥对
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
console.log('公钥:', publicKey);
console.log('私钥:', privateKey);
// 加密
const plaintext = 'Hello, Tokenization!';
const encrypted = crypto.publicEncrypt(publicKey, Buffer.from(plaintext));
console.log('密文 (hex):', encrypted.toString('hex'));
// 解密
const decrypted = crypto.privateDecrypt(privateKey, encrypted);
console.log('解密结果:', decrypted.toString());
```
这段代码里,`generateKeyPairSync` 生成密钥对。
`publicEncrypt` 和 `privateDecrypt` 分别做加密和解密。
看起来很简洁,但背后的数学运算非常重。
##### RSA的致命弱点
RSA有一个很明显的短板——**性能**。
我做过基准测试,RSA-2048 的加密速度,比 AES-256 慢几百倍。
如果想要加密大量数据,直接用 RSA 是不现实的。
所以现实中的做法是:用 RSA 加密一个临时对称密钥,然后用这个密钥去加密数据。
这就是“混合加密”的思路,后面章节会细讲。
另一个问题是**密钥长度**。
随着计算能力增长,RSA 需要越来越长的密钥才能保证安全。
现在普遍用 2048 位,但很多安全标准已经开始要求 4096 位。
密钥变长,计算开销跟着涨。
#### ECC算法:原理与实现
##### 椭圆曲线的数学基础
ECC 不是用大整数分解,而是用椭圆曲线。
标准方程是:`y^2 = x^3 + ax + b`
其中 4a^3 + 27b^2 ≠ 0,确保曲线没有奇点。
在这条曲线上,定义了一个“加法”运算。
两个点相加,结果还是曲线上的一个点。
这个运算满足交换律、结合律,存在单位元(无穷远点)。
就这么一个简单的点加法,反复做,就构成了椭圆曲线上的“乘法”。
##### 密钥长度对比
这是我在做方案选型时,常用的一张表。
它直观地告诉人,ECC 在安全性上有多划算。
| 对称加密强度 | RSA密钥长度 | ECC密钥长度 |
|--------------|-------------|-------------|
| 80位 | 1024位 | 160位 |
| 112位 | 2048位 | 224位 |
| 128位 | 3072位 | 256位 |
| 192位 | 7680位 | 384位 |
| 256位 | 15360位 | 521位 |
你看,要达到256位的对称加密强度。
RSA 需要 15360 位的密钥。
而 ECC 只需要 521 位。
这差距,不是一点半点。
##### 一个ECC的实现示例
我更喜欢用 ECC 做签名。
它的签名过程比 RSA 快得多。
```javascript
const crypto = require('crypto');
// 生成ECC密钥对(使用P-256曲线)
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'prime256v1',
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
console.log('ECC公钥:', publicKey);
console.log('ECC私钥:', privateKey);
// 签名
const message = 'Hello, ECC!';
const sign = crypto.createSign('sha256');
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
console.log('签名 (hex):', signature);
// 验签
const verify = crypto.createVerify('sha256');
verify.update(message);
const isValid = verify.verify(publicKey, signature, 'hex');
console.log('验签结果:', isValid);
```
在项目中,我常用 ECC 做数字签名。
比如合同签署、代码签名、证书验证。
它的验签速度比 RSA 快不少,用户体验更好。
##### ECC的陷阱
ECC 虽然好,但坑也不少。
我曾经踩过一个坑:随机数生成器不可靠。
ECC 依赖高质量的随机数来生成私钥。
如果随机数有规律,私钥可以被推导出来。
一定要用硬件随机数或操作系统的 CSPRNG(密码学安全伪随机数生成器)。
不要用 Math.random(),那东西是用来做游戏的,不是用来做密码学的。
另一个问题是**曲线参数**。
不是所有椭圆曲线都安全。
有些曲线有隐藏的后门,或者存在已知的数学攻击。
我个人建议使用 NIST 推荐的曲线(P-256、P-384、P-521),或者 Curve25519。
这些曲线经过了长时间的公开审查。
#### RSA vs ECC:如何选择?
| 维度 |
RSA |
ECC |
| 安全基础 |
大整数分解 |
椭圆曲线离散对数 |
| 密钥长度 |
长(2048位起步) |
短(256位即可) |
| 加密速度 |
慢 |
较快 |
| 签名速度 |
中等 |
快 |
| 验签速度 |
快 |
中等 |
| 资源消耗 |
高 |
低 |
| 标准成熟度 |
非常成熟 |
成熟 |
我的习惯是:
- **需要加密少量数据**(比如传输对称密钥):用 RSA 很稳。
- **需要大量签名/验签**(比如 API 认证、区块链交易):用 ECC。
- **资源受限的设备**(比如 IoT 传感器、智能卡):首选 ECC。
#### 非对称加密的核心应用场景
列出几个我常遇到的场景:
- **数字签名**:保证数据来源的真实性和完整性。
- **密钥交换**:比如 Diffie-Hellman 和 ECDH,用来安全协商对称密钥。
- **证书与 PKI**:X.509 证书基于非对称加密,它是 HTTPS 信任链的根基。
- **身份认证**:SSH 登录、SSL/TLS 握手,都在用非对称加密做身份证明。
#### 避坑指南
一个提升安全的小技巧:
不要直接用公钥加密长数据。
正确的做法是:用对称密钥加密数据,再用非对称密钥加密那个对称密钥。
这叫“混合加密”,兼顾了安全性和性能。
我在第一个令牌化项目中就这么做的,效果很好。
注意密钥生命周期:
非对称密钥不是永不过期的。
企业安全规范通常要求 RSA 密钥每年更换,ECC 密钥每两年更换。
密钥到期后,要安全归档并禁止再用于加密新数据。
私钥泄露后,要立即吊销对应的公钥证书。
#### 本章知识框架图
下面这张图,帮你看清 RSA 和 ECC 的核心原理、差异性以及应用场景。
阅读顺序:从左到右,从上到下。
这张图清晰地展示了 RSA 和 ECC 的两个分支结构。
从核心原理到密钥长度,再到应用场景,一目了然。
你可以看到,ECC 在高安全强度下,密钥长度优势非常明显。
而 RSA 在兼容性和成熟度上更有把握。
#### 最后啰嗦一句
非对称加密不是银弹。
它性能慢,不适合加密大量数据。
但它解决了密钥分发的问题,是混合加密的基石。
你想想看,没有非对称加密,HTTPS 根本跑不起来。
没有 ECC,区块链的签名效率会低到没法用。
理解了 RSA 和 ECC,你就掌握了现代密码学的两根支柱。
后面你还会看到,它们在令牌化方案中是如何协同工作的。