前言
公钥和私钥都是一串字符,长得也没有什么关联性,那么当拿到一个公钥和一个私钥后怎么验证它们两个是一对呢?先说说为什么会有这个疑问,最近在对接一些SDK时经常需要做签名和验证签名的工作,双方要相互提供公钥来完成后续的身份验证,测试过程中生成了多个密钥对,当时就在想如果我用错了怎样才能发现呢?有没有什么方法可以验证公钥和私钥是一对呢?再寻找方法的过程中发现 ssh-keygen
和 openssl
生成的密钥对差别居然这么大,但后来又发现他们居然还有联系,所以本文将刚刚提到的问题都总结一下,方便日后查阅。
解决这个问题的思路我么可以从密钥使用的方式入手,私钥加密公钥解密可以验证身份,公钥加密私钥解密可以秘密传递数据,也就是说公钥和私钥是配合工作的,如果我们用私钥加密一个数据,公钥可以解开就说明他们两个是一对的的。
其实还有一个更简单的办法,公钥是可以从私钥中提取出来的,反之则不行。在公钥密码学中,私钥和公钥之间的关系是一种数学上的单向函数。这种函数的特性使得从私钥生成公钥是可行的,而从公钥还原私钥是非常困难的,这被称为一个单向函数或单向映射,因此被认为是安全的。
有了这个前提我们就可以这样做,从私钥中提取出公钥,然后和要比对的公钥进行比较,如果一致就说明原来的公钥和私钥是一对啦。
ssh-keygen 和 openssl
ssh-keygen
和 openssl
是两个不同的工具,它们分别用于生成和处理不同类型的密钥和证书。以下是它们的一些主要区别:
功能和用途:
ssh-keygen
:主要用于生成和管理SSH密钥对,包括RSA、DSA、ECDSA和Ed25519密钥。openssl
:是一个通用的密码学工具,可以用于生成和管理多种密码学对象,包括SSL/TLS证书、密钥、摘要和数字签名等。
支持的算法:
ssh-keygen
:专注于SSH密钥生成,支持多种SSH密钥算法。openssl
:支持广泛的密码学算法,包括RSA、DSA、ECDSA、Diffie-Hellman、AES、SHA等,用于生成和操作各种密码学对象。
密钥格式:
ssh-keygen
:生成的SSH密钥通常以OpenSSH格式存储。openssl
:支持多种密钥格式,例如PEM、DER等,可以处理不同类型的密钥和证书。
具体应用场景:
ssh-keygen
:主要用于SSH连接,生成用于身份验证的密钥对。openssl
:更广泛地用于TLS/SSL证书、数字签名、加密和其他与通用密码学相关的应用。
具体命令和用法:
ssh-keygen
:用于生成SSH密钥对的常见命令包括:1
ssh-keygen -t rsa -b 2048 -f myid_rsa
openssl
:用于生成RSA密钥对的常见命令包括:1
2openssl genpkey -algorithm RSA -out private-key.pem
openssl rsa -pubout -in private-key.pem -out public-key.pem
以上的ChatGPT提供的内容,还是对比的挺全面的,从 openssl
生成密钥对的过程可以看出,确实可以从私钥中提取出公钥。
ssh-keygen
是我接触的最多的生成密钥对的命令,不管是github还是gitlab,或者一些其他的托管平台都会提到SSH Keys,所以每次我都会用 ssh-keygen
来生成,它是用于生成SSH连接密钥对最直接的选择,如果是想要使用更广泛的密码学操作,包括证书生成、签名和加密等,那么 openssl
提供了更大的灵活性。
两种证书的内容对比
前面说了两种命令生成的证书、格式、算法和用途都有区别,我们来看看利用上面的命令生成的证书内容有什么不同,先看 ssh-keygen
生成的私钥 myid_rsa
和公钥 myid_rsa.pub
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [17:58:47] |
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [19:22:03] |
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [19:22:10] |
接着看看 openssl
生成的私钥 private-key.pem
和公钥 public-key.pem
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [19:23:01] |
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [19:26:18] |
1 | # demo @ demo-ThinkPad-X390 in ~/tmp/rsa [19:26:21] |
从私钥提取公钥
使用 openssl
命令从私钥提取公钥,上面已经展示过程了,它的公钥就是这样生成的
1 | openssl rsa -pubout -in private-key.pem -out public-key.pem |
使用 ssh-keygen
命令从私钥提取公钥可以这样做
1 | ssh-keygen -y -f myid_rsa > compare_myid_rsa.pub |
结果文件 compare_myid_rsa.pub 和 myid_rsa.pub 的内容一模一样,所以从私钥提取公钥可以作为检验密钥是否匹配的方法
OPENSSH和PEM两种密钥格式相互转化
之前说了ssh-keygen
和 openssl
两个命令及生成的密钥区别,现在讲讲两种密钥的联系,OpenSSH 和 OpenSSL 使用的密钥对虽然有一些格式上的差异,但可以相互转换。OpenSSH 使用自己的私钥和公钥格式, 而 OpenSSL 通常使用 PEM 格式,可以通过下列命令转化
OpenSSH 格式私钥转换成 OpenSSL PEM 格式私钥
1 | ssh-keygen -p -N "" -f myid_rsa -m PEM |
$ file myid_rsa
myid_rsa: PEM RSA private key
OpenSSL PEM 格式私钥转换成 OpenSSH 格式私钥
1 | ssh-keygen -p -N "" -f myid_rsa |
$ file myid_rsa
myid_rsa: OpenSSH private key
OpenSSH 格式公钥生成 OpenSSL PEM 格式公钥
1 | ssh-keygen -e -m PEM -f myid_rsa.pub > new-public-key.pem |
$ file new-public-key.pem
new-public-key.pem: ASCII text
OpenSSL PEM 格式公钥生成 OpenSSH 格式公钥
1 | ssh-keygen -i -m PKCS8 -f new-public-key.pem > compare_myid_rsa.pub |
$ file compare_myid_rsa.pub
compare_myid_rsa.pub: OpenSSH RSA public key
公钥和私钥的匹配使用
匹配使用公钥和私钥之前先准备一个测试文件
1 | echo "Hello World" > data.txt |
加密和解密
使用公钥加密
1 | openssl rsautl -in data.txt -out data_enc.txt -inkey public-key.pem -pubin -encrypt |
使用私钥解密
1 | openssl rsautl -in data_enc.txt -out data_dec.txt -inkey private-key.pem -decrypt |
两个命令执行后都没有任何控制台输出,文件 data_enc.txt
中是加密后的内容,文件 data_dec.txt
是解密后的内容,成功解密后内容与 data.txt
文件内容一样
签名和验证
使用私钥签名
1 | openssl dgst -sha256 -sign private-key.pem -out signature.bin data.txt |
使用公钥验证签名
1 | openssl dgst -sha256 -verify public-key.pem -signature signature.bin data.txt |
验证通过后,会在命令行输出 “Verified OK” 字样,若不通过则输出 “Verification Failure” 字样
总结
- 验证公钥私钥是否匹配的最便捷的方法是通过私钥提取公钥来和原公钥进行对比
- 公钥加密私钥解密,私钥签名公钥验证签名,需要把公钥发给别人,私钥自己要保留好
- 公钥和私钥常用的有OpenSSH和PEM两种格式,这两种格式的密钥可以相互转化
ssh-keygen
和openssl
是两个不同的工具,前者用于管理SSH密钥更具体,后者使用范围更广更灵活
事情一件件去办就好了,『没什么大不了的』,希望你长大后还可以经常乐观的说这句话,一副俾睨天下的姿态