一、概述

项目

说明

实验名称

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 KEYBEGIN 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:可信第三方为“公钥属于谁”签发证书;
  • 公钥指纹比对:通过电话、当面等带外渠道核对公钥哈希。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐