文章目录
  1. 1. 生成随机文件
  2. 2. 生成一个密钥文件
  3. 3. 去除密钥文件的密码
  4. 4. 根据私钥生成公钥
  5. 5. 使用公钥加密
  6. 6. 使用私钥解密
  7. 7. 使用私钥签名
  8. 8. 使用公钥校验

本文介绍 OpenSSL 命令行进行 RSA 加密、解密、签名、验证的操作,但不涉及 RSA 算法原理解析,如有兴趣,可以阅读阮一峰的《RSA算法原理》。如果你只想知道 RSA 是什么,那么你只要记住:RSA 是一种加密算法,使用两个密钥,一个叫公钥,一个叫私钥,使用公钥加密的密文只有使用私钥才可以解密,反之亦然。

生成随机文件

由于 OpenSSL 创建密钥文件是随机生成的,因此有必要为之提供一份随机数据源。

可以用 openssl 的 rand 命令创建一个 64MB 的随机文件,保存为文件 randSrc.bin

1
openssl rand -out ./randSrc.bin 67108864

还可以使用 -base64 或者 -hex 两个参数之一指定输出格式为 BASE64 或者 HEX。

生成一个密钥文件

小贴士:

  1. 根据目前的普遍需求,应当使用 AES256 为加密标准。
  2. 通常 RSA 私钥文件命名为 name.pem,公钥文件名为 name_pub.pem
  3. OpenSSL 生成的密钥文件默认是 PEM 格式的。
1
2
3
4
openssl genrsa \
-rand randSrc.bin \
-aes256 \
-out rsa.pem 2048

这个命令的意思是:

  • genrsa: 生成 RSA 密钥文件。
  • -aes256: 使用 AES256 算法加密生成的密钥文件,因此你需要输入加密用的密码(并记住)。
  • -rand randSrc.bin 使用文件 randSrc.bin 作为随机数来源。
  • -out rsa.pem: 将生成的密钥文件保存为 rsa.pem
  • 2048: 生成 2048 Bits 的 RSA 密钥文件。

2048 Bits 是指 RSA 算法里 N 的长度,而不是说公钥和私钥都是 2048 Bits。

生成文件样例:

1
2
3
4
5
6
7
8
9
10
11
12
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,A6F8DD9D1D994363907C278CDF9B644C

MfsPjXK6izOmmzMseG3M2aBKque20ao13+oFg/JdJtlCK0Vb11hLqq8h/ICnY3lI
z1xuBKiXVykl521YumeTS6C+WtSkb71cy1u6lHBwdO44tWxklEqcl1sLYIWKyNaB
VgKmS4BhfuUq8XlSt3LnuQT/BJWPP7+GUUaZG6/stMWAx+XBg9mMahxGCqo7aRcz
...............
nLGRE27iklwGgSagaK40FDiSe69HcIBkHCUQYaYtXQzHNgjoQRkcotzo+vxM7XcL
5y5DHwA8IFwt9c5f14lxZ2cXF9p54JA3UMy+T7XggINDgBFuOPR/U3eBS2x6hHW6
eoGX+khw+s5atpNJaF4s6n2ViDseQsW+b8NfSdlX0j5f5xSasFcYgFsDZtBy/FqZ
-----END RSA PRIVATE KEY-----

这是一个密钥文件,而不是一个纯粹的私钥文件,它包含了完整的密钥信息,即是说,里面既有公钥也有私钥。但是只能把它当成私钥使用,公钥部分请参考 Section 3

去除密钥文件的密码

Section 1 生成的密钥文件中提取没有密码的密钥文件,以便给 Nginx 等服务器使用。

1
openssl rsa -in rsa.pem -out rsa_pri.pem

根据私钥生成公钥

Section 1 生成的私钥文件中提取公钥文件。

1
openssl rsa -in rsa.pem -pubout -out rsa_pub.pem

使用公钥加密

RSA 加密和解密都是使用 openssl 的 rsautl 命令。

Section 3 里面生成了公钥文件 rsa_pub.pem,下面使用它进行加密。(先生成个数据文件)

1
2
3
4
5
6
7
8
echo 1234567890 > test.txt
md5sum test.txt
openssl rsautl \
-encrypt \
-in test.txt \
-out test.secret \
-pubin \
-inkey rsa_pub.pem

可以看到源文件 test.txt 的 MD5 值为 7c12772809c1c0c3deda6103b10fdfa0

源文件 test.txt 只有 10 个字节大小,但是加密结果文件 test.secret* 居然有256 字节(2048 位长),这是因为 RSA 密钥是 2048 位长度的,而 RSA 加解密算法的操作单位必须和密钥长度一致。所以加密结果的大小一定和密钥长度的一致。所以加密长度必须小于 密钥长度 - 填充长度

关于填充数据,默认使用 PKCS#1 v1.5 填充格式。

使用私钥解密

Section 1 里面生成了密钥文件 rsa.pem,下面使用它进行加密。

1
2
openssl rsautl -decrypt -in test.secret -out test.raw -inkey rsa.pem
md5sum test.raw

这里使用的是带密码的密钥文件,因此需要输入 AES 密码先把密钥文件解密出来。如果使用的是 Section 2 中生成的无密码密钥文件,那么则不需要输入密码了。

可以看到解密出来的文件 test.raw 的 MD5 值为 7c12772809c1c0c3deda6103b10fdfa0

使用私钥签名

加解密是使用公钥加密,私钥解密,因为公钥是公开的,私钥是保密的。签名和校验则反过来,私钥签名,公钥校验。

这里假设你要发送消息给你朋友,消息存在文件 test.txt 中,你已经拥有了你朋友的公钥文件 fr_pub.pem

那么先用他的公钥对文件进行加密:

1
openssl rsautl -encrypt -in test.txt -out test.msg -pubin -inkey fr_pub.pem

得到了加密后的文件 test.msg,下面使用你自己的私钥进行签名。

先用 SHA256 算法生成文件的哈希校验码:

1
openssl sha256 -out test.hash test.msg

得到了哈希校验文件 test.hash,内容如下:

1
SHA256(test.msg)= ************************

下面使用 RSA 私钥对其进行签名:

1
2
3
4
5
openssl pkeyutl \
-sign \
-in test.hash \
-out test.sign \
-inkey rsa_raw.pem

或者

1
2
3
4
5
openssl rsautl \
-sign \
-in test.hash \
-out test.sign \
-inkey rsa_raw.pem

RSA 私钥签名的实质是:使用 RSA 私钥对数据的哈希校验码进行加密,这样就可以用对应的 RSA 公钥解密得到数据的哈希校验码。

得到了签名后的文件 test.sign,将它和 test.msgrsa_pub.pem 一起发给你的朋友。

使用公钥校验

现在你的朋友收到了你发给他的三个文件,分别是:公钥、签名、消息。现在他怎么确定消息是发给他的呢?当然是使用公钥校验啦。

首先,他同样使用 openssl 生成文件 test.msg 的哈希校验码。

1
openssl sha256 -out test.hash test.msg

然后使用你的公钥文件对其进行校验:

1
2
3
4
5
6
openssl pkeyutl \
-verify \
-in test.hash \
-sigfile test.sign \
-pubin \
-inkey rsa_pub.pem

如果校验通过,则会看到提示:Signature Verified Successfully

然后他再使用他的私钥解密 test.msg 文件即可得到你发给他的消息了。

这里不使用 openssl rsautl -verify 命令,因为 rsautl-verify 指令仅仅是将输入的文件用公钥解密,但不与计算出来的哈希校验码进行比较,不如 pkeyutl 的 -verify 方便:

openssl rsautl \
    -verify \
    -in test.sign \
    -pubin \
    -inkey rsa_pub.pem

前面说了,rsa.pem 里面既包含私钥又包含公钥,这里可以小小地证明一下。
直接使用 rsa_raw.pem 文件进行签名校验。

openssl pkeyutl \
    -verify \
    -in test.hash \
    -sigfile test.sign \
    -pubin \
    -inkey rsa_raw.pem

如何,结果是不是一样呢?

那么,问题来了。如果传输过程被人拦截了怎么办?这就是下一篇文章的内容了。

文章目录
  1. 1. 生成随机文件
  2. 2. 生成一个密钥文件
  3. 3. 去除密钥文件的密码
  4. 4. 根据私钥生成公钥
  5. 5. 使用公钥加密
  6. 6. 使用私钥解密
  7. 7. 使用私钥签名
  8. 8. 使用公钥校验