现代加密技术入门

现代加密技术是保障信息安全的基石,主要包括三种核心技术:哈希函数对称加密非对称加密

本文结合 openssl 命令,通过实际操作来介绍这三种技术的工作原理和使用场景,帮助你建立对现代加密技术的完整认识。

对称加密

对称加密比较容易理解,就是加密和解密使用同一个秘钥

最古老的对称加密算法是凯撒密码(Caesar Cipher):

我们用英文字母交流,但是每个字母都向后移动 3 位,这样就能一定程度上隐藏明文内容。

比如 hello 加密后变成了 khoor。在这个例子中,hello 是明文,khoor 是密文,秘钥是 3

古老的凯撒密码很容易被破解,现代有很多更安全的对称加密算法,比如 AES、DES 等,它们更加复杂,但依然需要加密方和解密方共享秘钥。

我们可以用 openssl 命令快速体验一下 AES 加密:

# 创建一个测试文件
echo "This is a secret message" > secret.txt

# 使用 AES-256-CBC 算法加密,密码是 mypassword
openssl enc -aes-256-cbc -salt -in secret.txt -out secret.enc -k mypassword

# 解密文件
openssl enc -aes-256-cbc -d -in secret.enc -out decrypted.txt -k mypassword

# 查看解密后的内容
cat decrypted.txt
  • enc -aes-256-cbc: 使用 AES-256-CBC 算法进行加密。
  • -salt: 添加随机盐值,增加安全性。
  • -k mypassword: 指定加密密码为 mypassword
  • -d: 执行解密操作。
什么是盐值(Salt)?

盐值是一个随机生成的字符串,在加密前会和密码混合在一起。

为什么需要盐值?假设你用同一个密码 mypassword 加密同一个文件 secret.txt 两次,如果不加盐值,两次生成的密文会完全相同。攻击者可以利用这个特性进行彩虹表攻击(预先计算大量密码的密文,然后比对)。

加了盐值后,即使密码和明文都相同,每次加密都会生成不同的密文,大大增加了破解难度。

openssl 会把盐值直接存储在密文文件的开头(通常是前 8 个字节)。解密时,openssl 会自动从密文中读取盐值,所以从用户的视角,并不需要额外保存盐值。

你可以试试去掉 -salt 参数,多次加密同一个文件,会发现密文完全相同;而加上 -salt 后,每次密文都不同。

加密和解密使用的是同一个密码 mypassword,这就是对称加密的特点。

对称加密的优势有:

  • 速度快:对称加密算法的计算效率很高,适合加密大量数据。
  • 实现简单:相比其他加密方式,对称加密的算法相对简单。

一些本地加密的场景,比如磁盘加密,文件加密等,常使用对称加密算法。

对称加密的缺点是:

  • 密钥分发问题:这是对称加密最大的问题。加密方和解密方必须共享同一个秘钥,但在信道不安全的情况下,我们无法将密文和秘钥同时安全地传递给解密方。窃听者完全可以同时截获密文和秘钥,使得加密形同虚设。
  • 密钥管理困难:如果有 NN 个人需要两两加密通信,就需要管理 N×(N1)/2N \times (N-1)/2 个不同的秘钥,管理成本很高。

密钥分发问题催生了非对称加密技术,但在介绍非对称加密之前,我们先看另一个重要的密码学工具:哈希函数。

哈希与数据指纹

哈希函数虽然不是加密算法,但它是密码学中的重要工具,特别是在数字签名中起关键作用。

哈希函数(Hash Function)可以把任意长度的数据转换成一个固定长度的字符串,这个字符串就是数据的指纹(也叫哈希值)。

哈希函数有几个重要特性:

  1. 单向性:从数据可以轻松计算出哈希值,但无法从哈希值反推出原始数据。
  2. 固定长度:无论原始数据多大,哈希值长度都固定。比如 SHA256 算法生成的哈希值永远是 256 位(64 个十六进制字符)。
  3. 雪崩效应:原始数据哪怕只改动一个字节,哈希值也会完全不同。
  4. 唯一性:不同的数据几乎不可能产生相同的哈希值(虽然理论上存在 哈希冲突 的可能,但概率极低)。

我们用 openssl 来计算一个文件的 SHA256 哈希值:

# 创建一个测试文件
echo 'Hello World' > test.txt

# 计算 SHA256 哈希值
openssl dgst -sha256 test.txt

输出为:

SHA256(test.txt)= d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26

这个 64 位的十六进制字符串就是 test.txt 的 SHA256 指纹。如果你修改文件内容,哪怕只改一个字母:

echo 'Hello World!' > test.txt
openssl dgst -sha256 test.txt

你会发现哈希值完全变了:

SHA256(test.txt)= 03ba204e50d126e4674c005e04d82e84c21366780af1f43bd54a37816b6ab340

哈希函数在密码学和软件工程中有广泛应用:

  • 数据完整性验证:下载软件时,网站会提供文件的 SHA256 哈希值,你下载后计算哈希值对比,就能确认文件是否被篡改。
  • 数字签名:对一个大文件进行签名时,通常先计算哈希值,然后对哈希值签名,这样效率更高(后面会详细讲解)。
  • 密码存储:一般后端数据库不会直接明文存储用户密码,而是存储密码的哈希值。一方面,可以通过比对哈希值来验证密码是否正确;另一方面,如果数据库不幸泄露,攻击者也无法直接获取原始密码。
  • 版本控制:Git 使用 SHA-1 哈希值作为 commit ID,确保代码历史的完整性。
  • 数据去重:通过比较文件的哈希值快速判断文件是否重复。

需要注意的是,哈希函数只能用来计算指纹,不能加密数据,也不能防止数据被篡改

比如你把一个文件和它的哈希值一起发送给别人,攻击者可以同时篡改文件和哈希值,接收方无法发现问题。

要解决这个问题,需要结合非对称加密的数字签名功能。

非对称加密

非对称加密的思路就是,加密和解密使用不同的秘钥

类比生活中的场景:

对称加密就像使用密码锁的保险箱,密码和锁是一体的,发送方给接收方寄出密码保险箱,也必然要寄出密码,在信道不安全的情况下就等于没有加密。

非对称加密的思路是,改用使用锁 + 钥匙的保险箱,加密(锁)和解密(钥匙)并不是一体的。接收方可以先自制一把锁和对应的钥匙,然后把锁寄给发送方,发送方用这把锁锁住保险箱,把保险箱寄回。

这样一来,由于钥匙本身始终在接收方手里,也就可以保证其他人无法打开保险箱窃取信息了。

非对称加密算法能生成一个秘钥对(Key Pair),包含一个公钥(Public Key)和一个私钥(Private Key)。

其中公钥可以发布到任何地方,而私钥则需要自己保留。这样互联网上的任何人都可以用公钥加密数据,但只有持有私钥的人才能解密数据。

除了加密场景外,非对称秘钥的另一个重要用途是数字签名。私钥可以用来对数据生成签名,公钥可以用来验证签名。

如果私钥持有者想发布一份声明,那么他可以用私钥对声明进行签名,然后同时发布声明和签名。其他人可以用公钥验证签名,从而确定声明确实是由私钥持有者发布的。

这样说可能还是有点抽象,我们来实操一把。

openssl 生成秘钥对

我们使用 openssl 命令来生成秘钥对,主流的操作系统应该都会预装这个工具。

我们首先要生成一个独一无二的私钥,公钥是从私钥中提取出来的。

# 生成私钥
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
  • genpkey: 生成密钥的命令。
  • -algorithm RSA: 指定使用 RSA 算法,这是最经典的非对称加密算法。
  • -out private_key.pem: 将生成的私钥保存到名为 private_key.pem 的文件中。
  • -pkeyopt rsa_keygen_bits:2048: 指定密钥长度为 2048 位,这是当前推荐的安全长度。

执行后,当前目录下会多出一个 private_key.pem 文件。这个就是私钥文件,一定要保管好,不能泄露!

接下来,我们从私钥中生成对应的公钥:

# 生成公钥
openssl rsa -pubout -in private_key.pem -out public_key.pem
  • rsa: 处理 RSA 密钥的命令。
  • -pubout: 表示要输出公钥。
  • -in private_key.pem: 指定输入的私钥文件。
  • -out public_key.pem: 将生成的公钥保存到名为 public_key.pem 的文件中。

现在,你拥有了 public_key.pem 文件,这个就是你的公钥,你可以把它分发给任何人。

提示

你可能会有疑问:为什么是先生成私钥,然后从私钥生成公钥呢?直觉上似乎应该同时生成公钥和私钥才对?

其实非对称加密算法的关键就是几个数字。比如 RSA 算法来说,私钥文件包含了两个巨大的质数和私钥指数等数字。

而所谓公钥,就是把私钥中的某些数字拿出来进行一些数学运算,得到几个新的数字。这些数字是可以公开的,因为无法通过这些数字反推出私钥中的数字。

所以说,实际上公钥是通过私钥演算出来的。

场景一:加密与解密

数据发送方想发给你一条机密消息:

echo "My name is Bob." > message.txt

那么他可以用你的公钥来加密消息:

# 公钥加密
openssl pkeyutl -encrypt -pubin -inkey public_key.pem -in message.txt -out encrypted_message.bin
  • -encrypt: 执行加密操作。
  • -pubin -inkey public_key.pem: 使用公钥 (public_key.pem) 进行加密。
  • -in message.txt: 对 message.txt 文件加密。
  • -out encrypted_message.bin: 将加密后的内容输出到 encrypted_message.bin 文件。

现在目录中多了一个 encrypted_message.bin 文件,其内容是乱码,这就是加密后的密文。

你可以用私钥解密密文:

# 私钥解密
openssl pkeyutl -decrypt -inkey private_key.pem -in encrypted_message.bin -out decrypted_message.txt
  • -decrypt: 执行解密操作。
  • -inkey private_key.pem: 使用私钥 (private_key.pem) 进行解密。
  • -in encrypted_message.bin: 对加密文件进行解密。
  • -out decrypted_message.txt: 将解密后的明文输出到 decrypted_message.txt 文件。

检查解密后的内容:

cat decrypted_message.txt

你会看到,原始消息 My name is Bob. 完美地还原了!

场景二:签名与验证

假设你要发布一份公开声明,例如一份合同条款:

echo "I agree." > contract.txt

为了证明这份合同确实是你本人签署的,可以使用你的私钥对 contract.txt 生成一个数字签名。

# 私钥签名
openssl dgst -sha256 -sign private_key.pem -out signature.bin contract.txt
  • dgst -sha256: 表示先用 SHA256 算法对文件内容计算指纹(哈希值),然后再对这个指纹进行签名。
  • -sign private_key.pem: 使用你的私钥 (private_key.pem) 进行签名。
  • -out signature.bin: 将生成的签名保存到 signature.bin 文件。
  • contract.txt: 要签名的原始文件。
提示

实际场景中一般不会直接对原始数据签名,而是先用 SHA256 算法计算哈希值,然后对哈希值签名。这样做有两个好处:一是效率高(哈希值长度固定,签名速度快),二是能确保数据完整性(前面讲过,哈希值可以唯一代表原始数据)。

接下来,你可以把 contract.txt(原文)和 signature.bin(签名)这两个文件一起公开发布。任何拥有你的公钥 (public_key.pem) 的人,都可以验证这份声明的真伪:

# 公钥验证签名
openssl dgst -sha256 -verify public_key.pem -signature signature.bin contract.txt
  • -verify public_key.pem: 使用你的公钥 (public_key.pem) 进行验证。
  • -signature signature.bin: 指定要验证的签名文件。
  • contract.txt: 指定要验证的原始文件。

如果命令成功执行,终端会输出:

Verified OK

验证成功说明了:

  • 身份真实性:这个签名确实是由与该公钥配对的私钥生成的。
  • 数据完整性contract.txt 的内容从签名之后,一个字都没有被改动过。

你可以尝试修改 contract.txt 文件的内容,或使用其他的私钥文件来生成 signature.bin,重新执行验证命令,就会得到验证失败的提示:

Verification Failure

总结

现在我们已经了解了现代密码学的三种核心技术,让我们做一个简单的对比:

技术秘钥特点主要用途速度典型算法
对称加密加密和解密用同一个秘钥大量数据加密AES, DES
哈希函数无秘钥,单向计算数据完整性验证、密码存储很快SHA256, MD5
非对称加密公钥加密,私钥解密;私钥签名,公钥验证密钥交换、数字签名RSA, ECC

加下来,我们将介绍一些常见的认证和鉴权技术,这些技术就是依托于这些密码学算法实现的。