介绍
在密码学领域,我们经常面临速度与安全之间的权衡。像 AES 这样的对称加密算法速度非常快,非常适合加密大量数据,但它们需要一个必须安全地分发给发送方和接收方的共享密钥。像 RSA 这样的非对称加密算法非常适合使用公钥/私钥对进行安全的密钥交换,但它们计算量大,加密大量数据时速度太慢。
混合加密通过结合这两种方法的优点来解决这个问题。它采用了“兼得两者之长”的方法:
- 使用非对称加密来安全地加密和共享一个临时的、一次性的对称密钥(通常称为“会话密钥”)。
- 然后使用这个会话密钥通过对称加密快速有效地加密实际的、较大的消息数据。
在这个 Lab 中,你将使用 openssl 命令行工具从头开始实现一个完整的混合加密方案。你将生成一个 RSA 密钥对,创建一个随机的 AES 会话密钥,使用 RSA 来加密会话密钥,使用 AES 来加密消息,最后,反转该过程来解密消息。
混合加密概述
在这一步中,我们将简要回顾使混合加密成为强大且广泛使用技术的核心概念。此步骤中没有需要执行的命令;目标是在我们开始动手操作之前,建立一个坚实的概念基础。
对称加密(例如 AES)
- 工作原理: 使用单个、共享的密钥进行加密和解密。
- 优点: 速度非常快且高效,非常适合加密大文件或数据流。
- 缺点: 密钥分发。你如何安全地将共享密钥发送给接收方?如果攻击者截获了密钥,他们就可以解密所有通信内容。
非对称加密(例如 RSA)
- 工作原理: 使用一对密钥:一个用于加密的公钥和一个用于解密的私钥。公钥可以自由共享,而私钥必须由其所有者保密。
- 优点: 解决了密钥分发问题。任何人都可以使用你的公钥向你加密消息,但只有你能用你的私钥解密它。
- 缺点: 它在数学上很复杂,因此比对称加密慢得多。它不适合加密大量数据。
混合解决方案
混合加密结合了这两种方法,以获得非对称加密的安全性和对称加密的速度。以下是典型的工作流程:
- 发送方(Alice)想向接收方(Bob)发送一条安全消息。
- Alice 生成一个新的、随机的对称会话密钥。
- Alice 使用这个快速的对称会话密钥加密她的实际消息。
- Alice 获取 Bob 的公钥。她使用它来加密仅那个小的对称会话密钥。
- Alice 将经过对称加密的消息和经过非对称加密的会话密钥一起发送给 Bob。
- Bob 接收这两个部分。他首先使用他的私钥来解密加密后的会话密钥。
- 现在 Bob 获得了原始的对称会话密钥,他使用它来快速解密实际的消息。
这个过程确保了大量数据被高效加密,而用于该加密的密钥则以最大的安全性进行交换。在接下来的步骤中,我们将实现这个确切的工作流程。
生成 RSA 和 AES 密钥
在这一步中,我们将生成混合加密方案所需的两组密钥:用于非对称部分的 RSA 密钥对(公钥和私钥),以及用于对称部分(AES)的随机会话密钥。所有操作都将在 ~/project 目录下执行。
首先,我们生成一个 2048 位的 RSA 私钥。这个密钥必须由接收方保密。
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
在密钥生成过程中,你将看到一些输出。接下来,我们需要从刚刚创建的私钥中提取相应的公钥。这个公钥可以分享给任何想给你发送加密消息的人。
openssl rsa -pubout -in private_key.pem -out public_key.pem
该命令将输出 writing RSA key。
现在,我们创建一个随机的 256 位(32 字节)会话密钥。这个密钥将与 AES 算法一起用于加密我们的实际数据。我们使用 openssl rand 生成密码学上安全的随机数据,并将其 Base64 编码以便于处理。
openssl rand -base64 32 > session_key.key
让我们列出当前目录中的文件,查看我们生成的密钥。
ls -l
你应该能看到你刚刚生成的三个密钥文件,以及在设置过程中创建的 message.txt 文件。
-rw-rw-r-- 1 labex labex 57 Oct 20 15:12 message.txt
-rw------- 1 labex labex 1704 Oct 20 15:14 private_key.pem
-rw-rw-r-- 1 labex labex 451 Oct 20 15:14 public_key.pem
-rw-rw-r-- 1 labex labex 45 Oct 20 15:14 session_key.key
使用 RSA 加密会话密钥
在这一步中,我们将执行混合加密过程中的一个关键部分:加密对称会话密钥。为了确保只有目标接收方才能使用会话密钥,我们将使用他们的 RSA 公钥对其进行加密。
我们将使用 openssl pkeyutl 命令,这是一个用于公钥操作的工具。我们将使用它来使用 public_key.pem 加密 session_key.key 文件。
执行以下命令:
openssl pkeyutl -encrypt -pubin -inkey public_key.pem -in session_key.key -out encrypted_session_key.bin
我们来分解一下这个命令:
pkeyutl: 公钥实用工具。-encrypt: 指定我们要执行加密操作。-pubin: 表明输入密钥 (-inkey) 是一个公钥。-inkey public_key.pem: 指定用于加密的公钥。-in session_key.key: 要加密的输入文件(我们的 AES 会话密钥)。-out encrypted_session_key.bin: 存储加密密钥的输出文件。
此命令会创建一个新文件 encrypted_session_key.bin,其中包含加密格式的会话密钥。现在可以安全地传输此文件,因为只有拥有相应私钥的所有者才能解密它。
让我们检查新创建的文件:
ls -l encrypted_session_key.bin
你将看到包含加密密钥的二进制文件。
-rw-rw-r-- 1 labex labex 256 Oct 20 15:14 encrypted_session_key.bin
使用 AES 加密数据
现在我们已经保护了会话密钥,我们可以使用原始的、未加密的会话密钥来快速加密我们的主数据文件 message.txt。对于此任务,我们将使用 AES-256-CBC 对称密码算法。
openssl enc 命令要求以十六进制格式提供密钥(Key)和初始化向量(Initialization Vector, IV)。我们的 session_key.key 是 Base64 格式的,所以我们首先需要将其解码并转换为十六进制。我们还将生成一个随机 IV。为了方便起见,我们将密钥和 IV 都存储在环境变量中。
首先,转换会话密钥并将其存储在 AES_KEY 变量中:
export AES_KEY=$(cat session_key.key | base64 -d | xxd -p -c 32)
接下来,生成一个 128 位(16 字节)的随机 IV 并将其存储在 AES_IV 变量中。IV 用于确保对同一明文进行多次加密会产生不同的密文。
export AES_IV=$(openssl rand -hex 16)
密钥和 IV 准备就绪后,我们现在可以使用 openssl enc 来加密 message.txt:
openssl enc -aes-256-cbc -in message.txt -out encrypted_message.dat -K $AES_KEY -iv $AES_IV
我们来回顾一下命令选项:
-aes-256-cbc: 指定 CBC 模式下的 AES-256 密码算法。-in message.txt: 输入数据文件。-out encrypted_message.dat: 加密数据的输出文件。-K $AES_KEY: 十六进制格式的加密密钥(大写 K)。-iv $AES_IV: 十六进制格式的初始化向量。
至此,发送方应该将 encrypted_message.dat、encrypted_session_key.bin 和 IV ($AES_IV) 打包发送给接收方。对于本次实验(Lab),我们将所有文件都保留在当前目录中,为解密步骤做好准备。
让我们验证加密数据文件是否已创建:
ls -l encrypted_message.dat
-rw-rw-r-- 1 labex labex 64 Oct 20 15:14 encrypted_message.dat
解密消息
在最后一步中,我们将模拟接收方的操作。接收方已经收到了加密数据 (encrypted_message.dat)、加密的会话密钥 (encrypted_session_key.bin) 以及 IV。他们将使用其秘密私钥来逆转过程并检索原始消息。
首先,接收方必须使用其 private_key.pem 解密会话密钥。
openssl pkeyutl -decrypt -inkey private_key.pem -in encrypted_session_key.bin -out decrypted_session_key.key
此命令使用带有 -decrypt 标志和私钥的 pkeyutl 来恢复原始 AES 会话密钥,并将其保存到 decrypted_session_key.key。
我们可以快速验证解密后的密钥与我们在步骤 2 中创建的原始密钥是否相同。如果文件相同,diff 命令将不会产生任何输出。
diff session_key.key decrypted_session_key.key
现在我们有了会话密钥,就可以解密主消息了。与加密步骤一样,我们需要首先将密钥转换为十六进制格式。
export DECRYPTED_AES_KEY=$(cat decrypted_session_key.key | base64 -d | xxd -p -c 32)
最后,使用带有 -d(解密)标志的 openssl enc,提供用于加密的相同密钥和 IV。($AES_IV 变量在上一实验步骤中仍保留在我们的 shell 中)。
openssl enc -d -aes-256-cbc -in encrypted_message.dat -out decrypted_message.txt -K $DECRYPTED_AES_KEY -iv $AES_IV
过程完成!原始消息已恢复并保存到 decrypted_message.txt 中。让我们查看其内容以确认我们的成功。
cat decrypted_message.txt
你应该会在终端上看到打印出的原始秘密消息:
This is a secret message that needs to be sent securely.
总结
在这个实验(Lab)中,你成功地使用 OpenSSL 实现了一个完整的混合加密和解密工作流程。你获得了关于保护我们大部分数字通信的基本概念的实践经验。
你学会了如何:
- 生成用于非对称加密的 RSA 密钥对。
- 创建用于对称加密的随机 AES 会话密钥。
- 使用 RSA 公钥安全地加密会话密钥。
- 使用 AES 会话密钥高效地加密大量数据。
- 通过使用 RSA 私钥解密会话密钥,然后解密数据来逆转该过程。
这种“兼顾两者之长”的方法,它结合了非对称密码学在密钥交换方面的安全性和对称密码学在数据加密方面的速度,是现代安全协议(如 TLS/SSL)的基石,这些协议每天都在保护你在互联网上的数据安全。



