密码应用实验三 —RSA 非对称加密与混合加密实战
一、概述
|
项目 |
说明 |
|
实验名称 |
RSA 非对称加密与混合加密实战 |
|
实验平台 |
天枢一体化虚拟仿真平台 |
|
终端环境 |
openEuler 24.03 LTS |
|
核心算法 |
RSA-2048(非对称)、AES-256-CBC(对称)、SM2(国密非对称) |
|
前置实验 |
建议先掌握 AES 对称加密 |

二、实验目的
- 理解非对称加密的“一对钥匙”:公钥可以公开分发,私钥必须自己保密;
- 掌握核心原则——“用谁的公钥加密,只有谁的私钥能解”,并通过错误配对验证;
- 动手完成公钥生成、公钥公告板交换、公钥加密、私钥解密的完整流程;
- 理解混合加密:RSA 安全地递会话密钥(慢、数据小),AES 高速加密聊天内容(快、数据大);
- 通过中间人替换公钥的攻击演示,理解“公钥归属认证”为什么是必需的。
三、实验原理(RSA 与混合加密)
信箱比喻:公钥就像公开的投信口——谁都能把信投进去;私钥就像只有你本人持有的开箱钥匙——只有你能取信。所以公钥可以随便发,私钥绝不外泄。
RSA 用法:用对方的公钥加密 → 只有对方的私钥能解密。连发送者自己都解不开——因为他没有接收方的私钥。RSA-2048 的密文固定为 256 字节,与明文长短无关。
为什么要混合加密:RSA 运算量大、速度慢,而且单次加密明文长度有限(2048 位密钥配合 PKCS#1 填充最多加密约 245 字节);AES 速度极快但绕不开密钥分发。真实系统(微信、Signal、HTTPS)的做法是:① 发送方生成一把临时随机会话密钥 K;② 用接收方公钥 RSA 加密 K 发过去;③ 之后双方用 K 做 AES 高速加密通信。非对称负责“递钥匙”,对称负责“锁内容”,兼得两者之长。
PEM 文件:公钥、私钥在磁盘上都保存为 PEM 文本格式,以 BEGIN PUBLIC KEY或BEGIN PRIVATE KEY开头。公钥文件可以公开发布,私钥文件是绝密资产。
公钥归属问题:公钥虽然可以公开,但你必须确认拿到的公钥确实属于对方。如果公告板上的公钥被攻击者偷偷替换,加密就形同虚设——这就是中间人攻击,本实验步骤 9 会演示。
四、实验环境准备
4.1 确认工具
|
openssl version # 预期 OpenSSL 3.0.x which openssl |
|
说明:openEuler 24.03 LTS 默认集成 OpenSSL 3.0+,完整支持 RSA 非对称加密与 AES 对称加密,无需额外安装。 |
4.2 创建工作目录与“公钥公告板”
|
mkdir -p ~/crypto_lab/alice ~/crypto_lab/bob ~/crypto_lab/board
# alice = 爱丽丝(发送方),bob = 鲍勃(接收方) # board = 公钥公告板(模拟公钥目录 / 共享文件夹) |
|
提示:只有一台机器时,开两个终端窗口分别扮演爱丽丝和鲍勃即可;本指导书命令都在同一台机器上用目录模拟,路径已写全。 |
五、详细实验步骤
步骤 1 · 爱丽丝生成 RSA 密钥对
|
cd ~/crypto_lab/alice
# 生成 RSA-2048 私钥 openssl genpkey -algorithm RSA -out alice_private.pem -pkeyopt rsa_keygen_bits:2048
# 从私钥中提取公钥 openssl rsa -pubout -in alice_private.pem -out alice_public.pem | |
|
预期输出(类似) ....+...+.+...++....(生成密钥时的随机数进度点) writing RSA key | |
|
参数 |
含义 |
|
genpkey |
通用密钥生成命令(OpenSSL 3.x 推荐,替代旧的 genrsa) |
|
-algorithm RSA |
指定生成 RSA 算法密钥 |
|
-pkeyopt rsa_keygen_bits:2048 |
密钥长度 2048 位(安全基线,密文固定 256 字节) |
|
rsa -pubout |
从私钥文件导出对应的公钥 |
|
安全纪律:alice_private.pem 是私钥,绝不发给任何人、不上传公告板!一旦私钥泄露,所有用对应公钥加密的消息都可被解密。 | |
查看公钥内容和密钥参数:
|
cat alice_public.pem openssl rsa -in alice_private.pem -text -noout | head -10 |
|
预期输出(公钥,可公开) ![]() ![]() |
步骤 2 · 鲍勃生成 RSA 密钥对
|
cd ~/crypto_lab/bob openssl genpkey -algorithm RSA -out bob_private.pem -pkeyopt rsa_keygen_bits:2048 openssl rsa -pubout -in bob_private.pem -out bob_public.pem cat bob_public.pem |
步骤 3 · 交换公钥(公钥公告板)
双方把公钥发布到公告板,再各自取回对方的公钥(实际系统中这一步对应“添加好友时交换公钥”):
|
# 爱丽丝发布公钥、取回鲍勃公钥 cp ~/crypto_lab/alice/alice_public.pem ~/crypto_lab/board/ cp bob_public.pem ~/crypto_lab/board/ cd ~/crypto_lab/alice cp ~/crypto_lab/board/bob_public.pem ./ # 鲍勃发布公钥、取回爱丽丝公钥 cp ~/crypto_lab/bob/bob_public.pem ~/crypto_lab/board/ cp ~/crypto_lab/board/alice_public.pem ~/crypto_lab/bob/
# 双方各自验证拿到了对方公钥 ls -l ~/crypto_lab/alice/bob_public.pem ls -l ~/crypto_lab/bob/alice_public.pem ![]() |
|
观察:公钥在公告板上谁都能看到——但这没关系。公钥的设计初衷就是可以公开,攻击者拿到公钥只能“锁信”,不能“开箱”。 |
步骤 4 · 爱丽丝用鲍勃公钥加密消息
|
cd ~/crypto_lab/alice echo "今晚7点老地方见" > msg.txt cat msg.txt
# 用鲍勃的公钥加密(-pubin 表示输入是公钥) openssl pkeyutl -encrypt -pubin -inkey bob_public.pem -in msg.txt -out msg.enc | |
|
参数 |
含义 |
|
rsautl -encrypt |
RSA 加密操作 |
|
-pubin |
告诉 OpenSSL -inkey 指向的是公钥(默认按私钥读取) |
|
-inkey bob_public.pem |
用鲍勃的公钥加密 |
|
-in / -out |
输入明文 / 输出密文 |
观察密文——二进制乱码,长度固定 256 字节:
|
od -v -An -t x1 msg.enc ls -l msg.txt msg.enc |
|
预期输出(密文每次不同,以下为某次真实结果)
明文 msg.txt 23 字节 → 密文 msg.enc 256 字节 |
|
结论:RSA-2048 密文长度恒等于密钥长度(2048 ÷ 8 = 256 字节),与明文长短无关;明文只有 23 字节,密文也是 256 字节。 |
步骤 5 · 鲍勃用自己的私钥解密
|
# 模拟网络传输:把密文送到鲍勃目录 cp ~/crypto_lab/alice/msg.enc ~/crypto_lab/bob/ cd ~/crypto_lab/bob
# 用鲍勃自己的私钥解密 openssl pkeyutl -decrypt -inkey bob_private.pem -in msg.enc -out msg_decrypted.txt cat msg_decrypted.txt diff ~/crypto_lab/alice/msg.txt msg_decrypted.txt && echo "消息完全一致" |
|
预期输出 |
|
核心结论:用鲍勃公钥锁的消息,只有鲍勃私钥能开——连爱丽丝自己都解不开,因为他没有鲍勃的私钥。注意 diff 比较时要写全爱丽丝原始文件的路径(爱丽丝的 msg.txt 在 alice 目录下)。 |
步骤 6 · 反向通信与错误配对验证
鲍勃用爱丽丝的公钥加密回复,爱丽丝用自己的私钥解密:
|
cd ~/crypto_lab/bob echo "好的,准时到" > reply.txt openssl pkeyutl -encrypt -pubin -inkey alice_public.pem -in reply.txt -out reply.enc cp reply.enc ~/crypto_lab/alice/
cd ~/crypto_lab/alice openssl pkeyutl -decrypt -inkey alice_private.pem -in reply.enc -out reply_decrypted.txt cat reply_decrypted.txt # 预期:好的,准时到 |
错误配对验证(选做):鲍勃尝试用自己的私钥去解“用爱丽丝公钥加密”的密文——密钥不配对:
|
cd ~/crypto_lab/bob openssl pkeyutl -decrypt -inkey bob_private.pem -in reply.enc -out wrong.txt |
|
预期现象(两种都属正常,都证明解密失败) |
|
结论:公钥和私钥必须配对:用谁的公钥加密,就只能用谁的私钥解密。判断解密是否成功,要看输出内容是不是预期明文,而不能只看命令有没有报错。 |
步骤 7 · 混合加密:RSA 递钥匙 + AES 锁内容
RSA 单次最多加密约 245 字节、速度慢,真实聊天都用混合加密。
7.1 爱丽丝生成随机会话密钥并用鲍勃公钥封装:
|
cd ~/crypto_lab/alice
# 生成 32 字节(256 位)密码学随机密钥,Base64 编码 openssl rand -base64 32 > session_key.key cat session_key.key
# 用鲍勃公钥加密这把会话密钥 openssl pkeyutl -encrypt -pubin -inkey bob_public.pem -in session_key.key -out session_key.enc |
|
预期输出(会话密钥每次不同,某次真实结果) |
7.2 爱丽丝用会话密钥做 AES-256 加密真正的消息:
|
echo "银行卡号是 6222 8888 6666 1234,密码是 123456" > secret_msg.txt
openssl enc -aes-256-cbc -a -salt -pbkdf2 -pass file:./session_key.key -in secret_msg.txt -out secret_msg.enc |
|
说明:-pass file:路径 表示口令从文件内容读取(即把会话密钥当口令);-pbkdf2 为 OpenSSL 3.x 推荐派生方式,加解密两边都要加。 |
7.3 发送:只有两个文件出网——加密的会话密钥 + 加密的消息:
|
cp session_key.enc ~/crypto_lab/bob/ cp secret_msg.enc ~/crypto_lab/bob/ |
7.4 鲍勃先解出会话密钥,再用它解消息:
|
cd ~/crypto_lab/bob
# 私钥解开会话密钥 openssl pkeyutl -decrypt -inkey bob_private.pem -in session_key.enc -out session_key_decrypted.key cat session_key_decrypted.key
# 用会话密钥 AES 解密消息 openssl enc -d -aes-256-cbc -a -pbkdf2 -pass file:./session_key_decrypted.key -in secret_msg.enc -out secret_msg_decrypted.txt cat secret_msg_decrypted.txt diff ~/crypto_lab/alice/secret_msg.txt secret_msg_decrypted.txt && echo "消息完整还原" |
|
预期输出 ![]() |
|
总结:网络上传输的始终是两个密文,明文会话密钥从未出网;即使攻击者截获全部流量,没有鲍勃私钥就拿不到会话密钥,也就解不开消息。这就是微信、Signal、HTTPS 的通用模式:非对称递钥匙,对称锁内容。 |
步骤 8 · RSA 的长度限制(为什么必须混合加密)
亲手验证 RSA 单次加密的数据上限(2048 位密钥、PKCS#1 v1.5 填充:256 − 11 = 245 字节)。这里用新版 pkeyutl 命令,超限会直接报错:
|
cd ~/crypto_lab/alice
# 造一个 300 字节的文件 head -c 300 /dev/zero | tr '\0' 'A' > big.txt
# 尝试直接 RSA 加密(pkeyutl 为 OpenSSL 3.x 推荐命令) openssl pkeyutl -encrypt -pubin -inkey bob_public.pem -in big.txt -out big.enc |
|
预期输出(加密失败) ![]() |
|
对照验证:把文件截成 245 字节再加密则成功(密文仍是 256 字节、解密完全还原);246 字节起失败。 |
对比:同样的 300 字节文件用 AES 加密毫无压力。这就是混合加密的根本原因——RSA 只适合加密会话密钥这种“小数据”。
步骤 9 · 中间人攻击演示(公钥被替换)
|
实验授权提示:本步骤是授权教学环境中的攻击演示,仅用于理解公钥认证的重要性,请勿对真实系统操作。 |
9.1 攻击者 Mallory 生成自己的密钥对:
|
mkdir -p ~/crypto_lab/mallory && cd ~/crypto_lab/mallory openssl genpkey -algorithm RSA -out mallory_private.pem -pkeyopt rsa_keygen_bits:2048 openssl rsa -pubout -in mallory_private.pem -out mallory_public.pem
# 偷偷把公告板上“鲍勃的公钥”换成自己的 cp mallory_public.pem ~/crypto_lab/board/bob_public.pem |
9.2 爱丽丝不知情,下载到假公钥并加密:
|
cd ~/crypto_lab/alice cp ~/crypto_lab/board/bob_public.pem bob_public_fake.pem echo "银行卡号是 6222 8888 6666 1234" > bank.txt openssl pkeyutl -encrypt -pubin -inkey bob_public_fake.pem -in bank.txt -out bank.enc cp bank.enc ~/crypto_lab/mallory/ # 攻击者截获密文 |
9.3 攻击者用自己的私钥轻松解密:
|
cd ~/crypto_lab/mallory openssl pkeyutl -decrypt -inkey mallory_private.pem -in bank.enc -out bank_stolen.txt cat bank_stolen.txt |
|
预期输出(攻击成功) |
|
核心教训:消息被攻击者完整窃取——算法没有被破解,是爱丽丝认错了公钥。仅有公钥还不够,必须能证明“这个公钥确实属于鲍勃”,即公钥归属认证。 |
现实中的三种解法(后续实验展开):
- 数字签名:可信方对公钥签名,验签确认归属;
- 数字证书 / CA:可信第三方为“公钥属于谁”签发证书;
- 公钥指纹比对:通过电话、当面等带外渠道核对公钥哈希。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐





所有评论(0)