加密技术基础回顾:对称加密与非对称加密
这章咱们不讲新东西,而是把地基夯一夯。说句实话,我见过不少同学一上来就冲信封加密,结果对称和非对称的概念都没整明白,后面越学越乱。好,我们从头捋一遍。
加密这件事,说白了就是把明文变成别人看不懂的密文。反过来,能解密的人再变回明文。那密钥是什么呢?你想想看,密钥就是开锁的钥匙——有了它,才能解开密文。
对称加密:一把钥匙开一把锁
对称加密是最直白的方案。加密和解密用同一把密钥。就像你家里的大门钥匙,你用它锁门,也用同一把开门。
个人习惯:我在项目中做小数据量加密时,首选对称加密——速度快,代码简单。
常用算法
- AES — 当今最主流的对称算法。我个人习惯用 AES-256-GCM,自带认证,不怕篡改。
- ChaCha20 — 移动端或 IoT 设备上常用,软件实现效率更高。
- 3DES / DES — 别用了,太老,它俩已经过时。我曾经在一个遗留系统里看到还在用 DES,果断要求升级。
优势与劣势
| 优势 | 劣势 |
|---|---|
| 加解密速度快,适合大块数据 | 密钥分发困难——怎么把密钥安全地给对方? |
| 算法成熟,硬件加速好 | 每对通信方需要独立密钥,N 方通信就需要 N-1 个密钥 |
| 密钥长度相对短(256位就够) | 密钥泄露后,整个通信被破解 |
我经常跟团队说:对称加密解决的是「加密」问题,但不解决「密钥交换」问题。你想想,如果两个人想用对称加密通话,必须先偷偷见一面把密钥换好——这不现实。
我曾经踩过一个坑:在项目早期,我用对称加密存储用户敏感数据,密钥硬编码在代码里。后来代码仓库泄露,所有用户数据全废。嗯,千万别硬编码密钥。
非对称加密:公钥锁,私钥开
非对称加密就聪明多了。它用一对密钥:公钥和私钥。公钥公开给所有人,私钥自己藏好。你用公钥加密的数据,只有对应的私钥能解开;反过来,用私钥签名,公钥可以验签。
这解决了啥问题?——你不需要事先交换密钥。我只需要把你的公钥拿来,加密后传给你,只有你能用私钥解开。中间人就算拿到公钥和密文,也没法解密。
常用算法
- RSA — 最经典的非对称算法。我在项目中遇到的 HTTPS 证书基本都是 RSA。
- ECC / ECDH / ECDSA — 椭圆曲线,密钥更短,性能更好。我个人建议新项目优先考虑 ECC。
- DSA / ElGamal — 现在用得少了,除非是某些老旧协议。
优势与劣势
| 优势 | 劣势 |
|---|---|
| 无需预先交换密钥,公钥公开没问题 | 加解密速度比对称加密慢几个数量级 |
| 支持数字签名,实现不可否认性 | 密文长度比明文长(RSA 加密块有大小限制) |
| 适合密钥分发和身份认证 | 密钥长度长(RSA 推荐 2048 位以上) |
实际经验:我做过一个文件同步工具,一开始傻乎乎用 RSA 直接加密大文件——慢到没法用。后来改成用混合加密(后面会讲),才解决问题。
对称 vs 非对称:一张表看懂
| 对比维度 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个 | 2 个(公钥+私钥) |
| 加解密速度 | 快(硬件加速可到 Gbps) | 慢(通常 Kbps 级别) |
| 密钥分发难度 | 难 | 易(公钥公开) |
| 常用算法 | AES、ChaCha20 | RSA、ECC、ECDH |
| 主要用途 | 数据加密 | 密钥交换、签名 |
| 典型密钥长度 | 128-256 位 | 2048-4096 位(RSA) |
混合加密?已经有人在这么做了
你肯定猜到了——对称加密快但无法安全交换密钥,非对称加密安全交换密钥但慢。怎么办?把两者结合。
混合加密:用非对称加密传输一个「会话密钥」,然后用这个对称密钥加密实际数据。这正是 HTTPS、PGP 和——你猜对了——信封加密的核心思路。
我记得刚开始学密码学那会儿,觉得混合加密是天才设计。后来自己做项目才明白,这背后全是工程妥协的结果。没有完美的加密方案,只有最适合场景的组合。
避坑指南:千万不要自己实现混合加密协议!我曾经手写过一套密钥交换逻辑,结果因为随机数生成器没种好种子,密钥空间直接缩水——差点捅大篓子。用业界标准吧,比如 TLS 或 Noise 协议。
知识体系总览
下面这张图把对称加密、非对称加密和混合加密的关系理清了。你看完后应该对整个密码学分类有个直观印象。
一个小代码示例:感受一下两种加密
我用 Python 的 cryptography 库演示一下最基本的用法。不多解释,你看完就有体感了。
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
import os
# 对称加密:AES-GCM
key = os.urandom(32) # 256位密钥
nonce = os.urandom(12) # GCM 推荐 96位
cipher = Cipher(algorithms.AES(key), modes.GCM(nonce))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(b"Hello Envelope Encryption!") + encryptor.finalize()
print(f"AES密文: {ciphertext.hex()[:32]}...")
# 非对称加密:RSA-OAEP
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
ciphertext_rsa = public_key.encrypt(
b"short message",
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
plaintext_rsa = private_key.decrypt(
ciphertext_rsa,
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
print(f"RSA解密正确: {plaintext_rsa == b'short message'}")
一个小提醒:上面的 RSA 示例只能加密 190 字节以内的小数据。为什么?因为 2048 位的 RSA 加密块最多能容纳那么多。这就是为什么非对称加密不适合加密大文件。