OpenSSL 使用 pkcs#8 格式来封装密钥

加密回顾

我们前面的文章介绍过如何使用 OpenSSL 对私钥进行密码保护,主要是 AES-256-CBC 算法配合 Salt 以及 PBKDF2, 或 Argon 等 KDF 来实施。

比如,我们有一个自建 CA 证书的私钥是 FactTrust_Root_CA.key,我们这样对它添加密码保护:

vbnet 复制代码
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 -in FactTrust_Root_CA.key -out FactTrust_Root_CA.key.enc

加密方式和算法都是目前比较流行且安全性得到较好保障的。

不过,这种方式依然有几个小缺陷:

  • (1) 输出的文件是二进制的,没法直接打印查看
  • (2) 输出的文件不是 PKI 体系中的标准化格式(符合 ASN.1 标准的结构化数据),这导致我们没法用标准化工具查看细节。
  • (3) 由于不是标准化格式,每次我们要使用它都得先手动解密,操作上很不方便。

为了解决上面几个缺点,最佳实践是把私钥转换成 pkcs8 标准所指定的格式(可以选择对私钥加密或不加密),如下:

vbnet 复制代码
openssl pkcs8 -topk8 -v2 aes256 -in FactTrust_Root_CA.key -out FactTrust_Root_CA_PKCS8_AES256.key

解释:

-topk8 选项就是转换成 pkcs#8 格式,它比 pkcs#1 格式多 20 字节,主要用于描述算法类型等 metadata 信息。pkcs#1 只支持 RSA 密钥算法,而 pkcs#8 更加通用,支持多种密钥算法。对称加密算法是在 pkcs#5 中定义的,pkcs#5 v1.5 只支持 DES 算法,

而 v2 则支持 AES 等算法。具体来说,pkcs#5 v2 采用的是一种叫 PBES2 (Password-Based Encryption Scheme 2) 的算法,它允许指定两个特征:

    1. 加密算法:比如 AES-256-CBC
    1. 密钥派生函数(KDF):默认使用 PBKDF2。

它还支持自定义下面的参数:

  • 迭代次数: 增加 PBKDF2 中的迭代次数,以增加暴力破解的难度。(默认是 2048 次)
  • 摘要算法:为 PBKDF2 选择一个强大的哈希函数,(默认是 SHA-256)

另外,我们无须显示地指定 salt,因为默认是会自动生成的。

现在我们再看一下指定了 -iter 选项的命令:

vbnet 复制代码
openssl pkcs8 -topk8 -v2 aes256 -iter 100000 \
  -in FactTrust_Root_CA.key -out FactTrust_Root_CA_PKCS8_AES256.key

输出结果:

指定摘要算法(伪随机函数)

默认情况下,openssl pkcs8 使用 HMAC-SHA1 作为 PBKDF2 中的伪随机函数(PRF)。您可以使用 -v2prf 选项指定更强的哈希函数(比如 hmacWithSHA512)。

示例

vbnet 复制代码
openssl pkcs8 -topk8 -v2 aes256 -v2prf hmacWithSHA256 -iter 100000 \
  -in FactTrust_Root_CA.key -out FactTrust_Root_CA_PKCS8_AES256.key

下面是一个包含所有安全参数的完整命令:

vbnet 复制代码
openssl pkcs8 -topk8 -v2 aes256 -v2prf hmacWithSHA256 -iter 100000 \
  -in FactTrust_Root_CA.key -out FactTrust_Root_CA_PKCS8_AES256.key

成功转换后,我们可以用 asn1parse 来查看密钥信息,如下:

复制代码
openssl asn1pars

输出结果:

或者

vbnet 复制代码
openssl pkey -in FactTrust_Root_CA_PKCS8_AES256.key -text -noout

或者

bash 复制代码
cat FactTrust_Root_CA_PKCS8_AES256.key

输出结果:

vbnet 复制代码
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIGjMF8GCSqGSIb2DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBAIFhGijjsNRUzkvePr
5jmTAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQKo9YE0C2EB5TH85n
EcOuHwRAXJdqwqy4IcPGBE1N33tgZMorbgHJUwFkxuzh3OJYPYCUFeQxk15RMh5T
R6ClqXglmbRMnqjIBUGDxF2hTQOiyA==
-----END ENCRYPTED PRIVATE KEY-----

它是 PEM 格式的。注意它跟使用 ssh-keygen 命令所生成的私钥的格式不太一样,如下:

bash 复制代码
cat ~/.ssh/id_rsa

输出结果:

vbnet 复制代码
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZoktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBlH2sG/nHzARzWNMVUb1+Wdb90l8+K4IDvS5SPNfHfpAAAAJim9bjmpvW4
5gAAAAtzc2gtZWQyNTUxOQAAACBlH2sG/nHzARzWNMVUb1+Wdb90l8+K4IDvS5SPNfHfpA
AAAEBgEnAgP4mUcXyGdfLNtcFiPz3kaPVmrjs0C7YmIw69HmUfawb+cfMBHNY0xVRvX5Z1
v3SXz4rggO9LlI818d+kAAAAFHdpbmtlZTAxQG91dGxvb2suY29tAQ==
-----END OPENSSH PRIVATE KEY-----

这个不是 PEM 格式,我们可以用下列命令把它转换成 PEM 格式:

javascript 复制代码
ssh-keygen -p -f ~/.ssh/id_rsa -m pem

输出结果:

vbnet 复制代码
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAw7R7zjMCLoKIT7L7bd3TvOHYGbc8tkO3zgP0/eqX5kiRlfoR
...
GRfahB+a0pOBqFQ0NRWZ8x94nP1IRngHdiYE43uO+oAt3Vfx5+nRY2FiMHthXvdY
nk36bsjy2AA3ZW4wjOmye8Pp/wVsuNFl/CMOUBpPTXuQCgSFKEPny5Kt+KQF
-----END RSA PRIVATE KEY-----

小知识:pkcs#8 是专门针对私钥处理的,不是一般情况下的加密工具。

下面的命令展示了如何创建私钥,安全加密私钥并创建 CA 证书的完整过程:

vbnet 复制代码
openssl genpkey -algorithm ed25519 -out FactTrust_Root_CA.key

openssl pkcs8 -topk8 -v2 aes256 -v2prf hmacWithSHA256 -iter 100000 \
    -in FactTrust_Root_CA.key -out FactTrust_Root_CA_PKCS8_AES256.key

shred -u FactTrust_Root_CA.key

openssl asn1parse -in FactTrust_Root_CA_PKCS8_AES256.key

openssl req -x509 -key FactTrust_Root_CA_PKCS8_AES256.key -days 7300 \
    -out FactTrust_Root_CA.crt -subj \
    "/C=US/ST=TX/L=DAL/O=Security/OU=IT Department/CN=FactTrust Root CA"

注:OpenSSL 在需要时会提示您输入密码。

如果想要非交互式的(不想输入密码),我们可以把密码保存在文件中,然后作为参数传递给命令,如下:

使用文件中的密码进行加密:

vbnet 复制代码
openssl pkcs8 -topk8 -v2 aes256 -v2prf hmacWithSHA256 -iter 100000 \
  -in FactTrust_Root_CA.key -out FactTrust_Root_CA-PKCS8-AES256.key \
  -passout file:passphrase.txt

使用加密后的密钥:

vbnet 复制代码
openssl req -x509 -key FactTrust_Root_CA_PKCS8_AES256.key -days 7300 \
  -out FactTrust_Root_CA.crt -passin file:passphrase.txt \
  -subj "/C=US/ST=TX/L=DAL/O=Security/OU=IT Department/CN=FactTrust Root CA"

解密

如果在某些自动化场景或者云环境中(无法访问我们的密码文件),那么我们可能需要用到非加密的 Private Key,

也就是把 Encrypted Private Key 转换成 Unencrypted Private Key。 如下:

vbnet 复制代码
openssl pkcs8 -in encrypted_private.key -out unencrypted_private.key \
  -passin "pass:your_password"

全文完!

如果你喜欢我的文章,欢迎关注我的微信公众号 deliverit。

相关推荐
HLC++13 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室14 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy16 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
尽兴-17 小时前
企业业务系统架构选型与渐进式演进
运维·系统架构·devops
通信小小昕17 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫18 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生19 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1120 小时前
linux基础IO
linux·运维·服务器
BelongPanda1 天前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯1 天前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算