📚 网络安全Kali学习系列 · 模块0-3 密码学基础
已完成:模块0-1 Linux系统深度(6篇) ✅ | 模块0-2 计算机网络(4篇) ✅
11 密码学基础:对称加密与非对称加密(当前篇)
12 哈希算法与编码:从 MD5 到 SHA-256
13 数字证书与 PKI:X.509 与 TLS 握手

密码学基础:对称加密与非对称加密

难度:基础 | 模块0-2你已掌握网络协议栈从应用到链路层的通信原理,本篇进入密码学世界,学习保护通信内容的两大加密体系
读完本篇你将能:用 openssl enc 执行 AES 对称加解密,用 openssl genpkey + pkeyutl 生成 RSA 密钥并执行非对称加解密,理解 ECB/CBC/GCM 三种分组模式的安全差异,并用 Python cryptography 库(v46+)实现 Fernet 对称加密。
📑 本文目录
01密码学入门:明文、密文与密钥
02对称加密:AES 与分组模式
03对称加密实战:openssl 与 Python
04非对称加密:RSA 与公钥密码
05密钥交换:Diffie-Hellman
06混合加密:HTTPS 的加密策略

01 密码学入门:明文、密文与密钥

在模块0-2中,你学了 HTTP、DNS、ARP 等协议。这些协议负责"把数据从 A 送到 B",但送的过程中数据是明文的——任何人截获流量就能直接读取内容。密码学解决的是另一个问题:即使数据被截获,攻击者也无法读懂。

加密的核心概念很简单:把可读的明文(plaintext)通过算法变成不可读的密文(ciphertext),接收方再用密钥(key)把密文还原成明文。整个过程像把信件放进一个带锁的铁箱子里寄送——只有持有钥匙的人能打开。

密码学有一条铁律叫 Kerckhoffs 原则:加密算法应该是公开的,安全性只依赖于密钥的保密。也就是说,即使攻击者知道你用的是 AES-256-CBC 加密、知道算法的每一行代码,只要他不知道你的密钥,就无法解密。这就是为什么 AES、RSA 等算法可以公之于众而仍然安全——反过来,依赖"算法保密"来保证安全的系统(所谓 security through obscurity)迟早会被攻破。

💡 小贴士
加密(encryption)和编码(encoding)是两回事。Base64 编码只是换了一种数据表示方式,任何人都能解码,没有密钥可言。编码不提供安全性,加密才提供。这个区别在模块0-3的下一篇会详细展开。

02 对称加密:AES 与分组模式

对称加密是最古老的加密方式:加密和解密用同一把密钥。就像你家大门的钥匙——同一把钥匙锁门、同一把钥匙开门。通信双方必须事先共享这把密钥,所以叫"对称"。

历史上 DES(Data Encryption Standard)曾是对称加密的标准,但其 56 位密钥在现代算力下几小时内即可暴力破解。2001 年 NIST 发布 AES(Advanced Encryption Standard),支持 128/192/256 位密钥,至今未被有效破解。AES 是当前全世界最广泛使用的对称加密算法——你的 Wi-Fi(WPA2)、HTTPS(TLS)、手机磁盘加密(FileVault/File-Based Encryption)底层都在用它。

分组密码与工作模式

AES 是分组密码(block cipher),每次加密一块固定大小的数据(AES 的块大小是 128 位/16 字节)。但实际要加密的数据可能远超 16 字节,这就需要"工作模式"来定义如何把长数据切分成块逐个加密:

模式 原理 安全性
ECB 每块独立加密,相同明文块→相同密文块 🔴 不安全,泄露模式
CBC 每块与前一块密文异或后再加密,需 IV 🟡 安全,但无完整性验证
GCM CBC 变体 + 自带认证标签(AEAD) 🟢 推荐,加密+完整性

ECB 的问题在于:如果两块明文相同,加密后的密文也相同。假设你加密一张图片,ECB 模式下图片的轮廓仍然清晰可见——著名的"ECB 企鹅"就是最好的例子。CBC 通过引入初始向量(IV)和链式异或解决了这个问题。GCM 在 CBC 基础上增加了认证标签,能检测密文是否被篡改,是当前 TLS 1.3 的首选模式。

⚠️ 常见错误
openssl enc -aes-256-cbc -in file.txt -out enc.bin — 不加 -salt 参数时,相同密码每次生成相同密文,易受字典攻击
✓ 正确:openssl enc -aes-256-cbc -salt -pbkdf2 -in file.txt -out enc.bin — 加盐 + PBKDF2 密钥派生

03 对称加密实战:openssl 与 Python

你已经理解对称加密的原理和分组模式。现在动手实践。先准备一个测试文件,然后用 openssl 进行 AES-256-CBC 加解密:

Bash
# 准备测试文件
echo "This is a secret message" > plain.txt
# AES-256-CBC 加密,-pbkdf2 使用密钥派生函数
openssl enc -aes-256-cbc -salt -pbkdf2 -in plain.txt -out cipher.bin
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
# 查看密文(二进制乱码)
xxd cipher.bin | head -2
00000000: 5361 6c74 6564 5f5f 2a21 0f8b 3c4e a2f1  Salted__*!..<N..

密文以 Salted__ 开头——openssl 的 -salt 参数在密文头部嵌入了 8 字节随机盐值,保证相同密码每次加密产生不同密文。解密时输入相同密码即可:

Bash
openssl enc -aes-256-cbc -d -pbkdf2 -in cipher.bin -out decrypted.txt
enter aes-256-cbc decryption password:
cat decrypted.txt
This is a secret message

Python 实现:Fernet 对称加密

Python 的 cryptography 库(v46+)提供了 Fernet 高级接口,底层使用 AES-128-CBC + HMAC-SHA256,自动处理 IV 生成和完整性验证:

Python
1
2
3
4
5
6
7
8
9
from cryptography.fernet import Fernet
# 生成密钥(务必安全保管)
key = Fernet.generate_key()
f = Fernet(key)
# 加密 → 解密
token = f.encrypt(b"Attack at dawn")
print(f.decrypt(token))
b'Attack at dawn'

generate_key() 每次生成不同的随机密钥。Fernet 自动在密文中嵌入时间戳和 HMAC 标签,解密时会验证完整性——如果密文被篡改哪怕一个字节,decrypt() 会抛出 InvalidToken 异常。

04 非对称加密:RSA 与公钥密码

对称加密有一个致命问题:双方必须事先共享密钥。如果 Alice 和 Bob 从未见过面,如何在不安全的信道上安全地传递密钥?非对称加密(又称公钥密码)解决了这个问题。

非对称加密用两把钥匙:公钥(public key)和私钥(private key)。公钥可以公开给任何人,私钥只有所有者保管。用公钥加密的数据只能用对应的私钥解密。这就像一个信箱——任何人都能把信从投信口塞进去(公钥加密),但只有持有信箱钥匙的主人能打开取信(私钥解密)。

RSA 是最著名的非对称加密算法,由 Rivest、Shamir、Adleman 三人于 1977 年提出。其安全性基于大数分解的数学难题:把两个大质数相乘很容易,但把乘积分解回两个质数极其困难。RSA 使用 2048 位或更长的密钥,目前没有已知的实际破解方法。

生成 RSA 密钥对

用 openssl 生成 RSA 密钥对。注意:OpenSSL 3.x 推荐使用 genpkey 替代旧版 genrsa,使用 pkeyutl 替代已废弃的 rsautl:

Bash
# 生成 RSA 2048 位私钥
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
# 从私钥提取公钥
openssl rsa -pubout -in private.pem -out public.pem
writing RSA key
# 查看公钥内容
cat public.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyY7v...
-----END PUBLIC KEY-----

公钥加密、私钥解密

现在用公钥加密一段消息,只有持有私钥的人才能解密。注意 OpenSSL 3.x 使用 pkeyutl 而非已废弃的 rsautl:

Bash
# 用公钥加密
echo "Top Secret" > msg.txt
openssl pkeyutl -encrypt -pubin -inkey public.pem -in msg.txt -out msg.enc
# 用私钥解密
openssl pkeyutl -decrypt -inkey private.pem -in msg.enc -out msg.dec
cat msg.dec
Top Secret
⚠️ 常见错误
openssl rsautl -encrypt -pubin -inkey public.pem ... — OpenSSL 3.0 起 rsautl 已废弃,执行时会输出警告
✓ 正确:openssl pkeyutl -encrypt -pubin -inkey public.pem ... — 使用 pkeyutl,支持所有非对称算法

RSA 有一个限制:加密数据长度不能超过密钥长度减去填充开销。2048 位 RSA 最多加密约 190 字节(OAEP 填充后)。这就是为什么 RSA 不直接用于加密大文件——它太慢了,而且有长度限制。实际应用中 RSA 用于加密对称密钥,而非加密数据本身(见第六章混合加密)。

05 密钥交换:Diffie-Hellman

你已经会生成 RSA 密钥对并用公钥加密了。但非对称加密不是唯一解决密钥分发的方法。Diffie-Hellman(DH)密钥交换协议另辟蹊径:让两个人在完全公开的信道上协商出一个共享密钥,即使窃听者记录了所有通信内容也无法推算出这个密钥。

DH 的原理用颜色混合来理解最直观:Alice 和 Bob 公开约定一个基础颜色(比如黄色)。各自选一个秘密颜色(Alice 选红色,Bob 选蓝色),把秘密颜色和基础颜色混合后公开交换(Alice 传出橙色,Bob 传出绿色)。然后各自把自己的秘密颜色加到收到的混合色里——Alice 把红色加到绿色里,Bob 把蓝色加到橙色里——两人最终得到相同的颜色(黄+红+蓝=棕褐色)。窃听者看到了黄色、橙色、绿色,但无法"分离"混合色来还原红色或蓝色。

Alice
秘密: 红色
⇄
公开信道
基础: 黄色
⇄
Bob
秘密: 蓝色
交换混合色后:Alice 得到 黄+红+蓝 = 棕褐,Bob 得到 黄+蓝+红 = 棕褐 ✓
窃听者只看到黄色、橙色(黄+红)、绿色(黄+蓝),无法分离出红色或蓝色

数学上,DH 使用离散对数问题代替颜色分离:给定质数 p、生成元 g 和公开值 g^a mod p,反推 a 在计算上不可行。DH 是 TLS、SSH、IPSec 等协议中密钥协商的核心——每次你访问 HTTPS 网站时,浏览器和服务器就在用 DH(或其椭圆曲线版本 ECDH)协商会话密钥。

06 混合加密:HTTPS 的加密策略

你已经掌握了对称加密(快但密钥分发难)和非对称加密(解决分发但慢且有长度限制)。实际系统不会二选一,而是取长补短——这就是混合加密。

特性 对称加密 非对称加密
速度 极快(AES ~1GB/s) 慢(RSA 约慢 1000 倍)
密钥分发 困难(需事先共享) 简单(公钥可公开)
加密长度 无限制 有限(RSA ≤190字节)

混合加密的策略是:用非对称加密协商/传递一个对称密钥,然后用对称密钥加密实际数据。HTTPS(TLS)就是这样做的:

① 客户端连服务器,获取服务器公钥(含在证书中)
↓
② 用 DH/ECDH 协商出共享的对称会话密钥
↓
③ 双方用 AES-GCM 对称加密所有后续通信

非对称加密只在握手阶段使用一次(慢但只传少量数据),之后全部用对称加密(快且无长度限制)。你在模块0-2第09篇学的 TLS 握手过程,本质上就是这个混合加密策略的实现。

💡 小贴士
在 Kali 上用 openssl speed aes-256-cbc rsa2048 可以直观对比 AES 和 RSA 的性能差异。AES 通常在每秒 GB 级别,RSA 2048 位每秒只能处理几百次操作——这就是为什么 HTTPS 只在握手阶段用 RSA。
📖 知识回顾
Kerckhoffs 原则 AES 对称加密 ECB/CBC/GCM 分组模式 openssl enc 加解密 Python Fernet RSA 公钥/私钥 openssl pkeyutl Diffie-Hellman 密钥交换 混合加密策略

动手练习

🟢 基础验证(5分钟)
在 Kali 终端创建一个文本文件,用 openssl enc -aes-256-cbc -salt -pbkdf2 加密,然后用相同密码解密验证内容一致。尝试不加 -salt 加密两次,对比密文是否相同。
参考解法:加 -salt 时每次密文不同(Salted__ 后跟随机盐),不加 -salt 时相同密码+相同明文产生完全相同的密文,容易被彩虹表攻击。
🟡 组合应用(10分钟)
生成 RSA 2048 位密钥对,用公钥加密一段消息,然后用私钥解密。接着用 openssl speed rsa2048 测试 RSA 性能,再运行 openssl speed aes-256-cbc 测试 AES 性能,计算两者速度差。
参考方向:用 openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048 生成密钥,openssl rsa -pubout -in private.pem -out public.pem 提取公钥。speed 测试会显示 AES 每秒处理数百 MB,RSA 每秒仅几百次操作。
🔴 开放挑战(30分钟+)
用 Python 实现一个混合加密 demo:生成 AES 密钥加密一段较长文本(>1KB),然后用 RSA 公钥加密这个 AES 密钥,把 RSA 加密的密钥 + AES 加密的密文一起保存。解密时先用 RSA 私钥恢复 AES 密钥,再用 AES 密钥解密文本。思考:这个方案相比纯 RSA 加密有什么优势?
提示:使用 from cryptography.fernet import Fernet 处理 AES 部分,from cryptography.hazmat.primitives.asymmetric import rsa, padding 处理 RSA 部分。RSA 加密的 AES 密钥通常只有 32 字节,远低于 RSA 的 190 字节上限。这就是 TLS/HTTPS 的核心设计思路。
下一篇:哈希算法与编码
本篇你掌握了对称与非对称加密。下一篇进入哈希算法的世界:MD5 为什么不安全、SHA-256 如何工作、bcrypt 如何安全存储密码。同时搞清编码与加密的本质区别——Base64 不是加密,URL 编码也不是加密。这些知识是理解数字签名和密码存储的基础。
关注 · 点赞 · 在看 持续获取系列更新