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。

相关推荐
维尔切39 分钟前
Linux中基于Centos7使用lamp架构搭建个人论坛(wordpress)
linux·运维·架构
会飞的小蛮猪1 小时前
Prometheus运维(Prometheus基础结构组件)
自动化运维
tan77º1 小时前
【项目】分布式Json-RPC框架 - 项目介绍与前置知识准备
linux·网络·分布式·网络协议·tcp/ip·rpc·json
正在努力的小河4 小时前
Linux设备树简介
linux·运维·服务器
荣光波比4 小时前
Linux(十一)——LVM磁盘配额整理
linux·运维·云计算
LLLLYYYRRRRRTT5 小时前
WordPress (LNMP 架构) 一键部署 Playbook
linux·架构·ansible·mariadb
轻松Ai享生活5 小时前
crash 进程分析流程图
linux
大路谈数字化6 小时前
Centos中内存CPU硬盘的查询
linux·运维·centos
luoqice7 小时前
linux下查看 UDP Server 端口的启用情况
linux
倔强的石头_8 小时前
【Linux指南】动静态库与链接机制:从原理到实践
linux