RSA加密的两个密钥可以交换使用么?

576 阅读5分钟

“我正在参加「掘金·启航计划」”

我们都知道RSA是一种常用的非对称的加密算法,其中涉及到一对密钥,分别被称为公钥和私钥。使用公钥加密的信息只有使用私钥才能解密,使用私钥加密的信息也只有公钥才能解密。一般私钥由密钥的生成方保存,公钥任何人都能持有。

由此衍生出RSA的两种用法:加密解密、数字签名

加密解密通常使用公钥进行加密使用私钥进行解密。例如在TLS中,客户端使用RSA公钥加密密钥块,并把密文传输给服务端,服务端使用私钥来进行解密得到密钥块。在这个过程中,只有服务端拥有私钥,所以即使被拦截了密文,由于拦截者没有私钥所以没有办法解密。

加密过程

下面我们来验证一下这个流程,生成两个pem格式的私钥key.pem和公钥pubkey.pem

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsK6DjGM1f+nWneUqjblW
CASv2qCMjc6offfofXyHnfwMSg7hLuegFsuYw+WUKviMDJAvMlUduenzCIs4TzgE
53DfuIY29QgJhkUeW38Gt/CNMUH6V4HbpkT38BoV6oU3gB35DR/TaunTsTiUShdA
ii4XSbEAeeKgCtsV0QXJWUsdwGK+zwqi5JiadORK2iFcDC3H2eTYuYUVksXhQ7pO
2C/DbZ4xuFmRrykNOohz3/91coJIcPP6c8iQjI5LgvfubFTNYhBJVpYl5Gc+1Efe
Nk/w8R+L1XwVb/5Yh7AgXpG9ZtBg9eo38GOUOuiHjDXtfFs4uzboGcgrEPuFdr/G
ZwIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwroOMYzV/6dad
5SqNuVYIBK/aoIyNzqh99+h9fIed/AxKDuEu56AWy5jD5ZQq+IwMkC8yVR256fMI
izhPOATncN+4hjb1CAmGRR5bfwa38I0xQfpXgdumRPfwGhXqhTeAHfkNH9Nq6dOx
OJRKF0CKLhdJsQB54qAK2xXRBclZSx3AYr7PCqLkmJp05EraIVwMLcfZ5Ni5hRWS
xeFDuk7YL8NtnjG4WZGvKQ06iHPf/3Vygkhw8/pzyJCMjkuC9+5sVM1iEElWliXk
Zz7UR942T/DxH4vVfBVv/liHsCBekb1m0GD16jfwY5Q66IeMNe18Wzi7NugZyCsQ
+4V2v8ZnAgMBAAECggEBAJQCvmU/PzRXOtmvf4SWvMGe24r1cInjlDdjFTr6tcnd
upXX/UED/ZLbILELhKKy8PAdYcxyjaKPoG+J4bRLo6AXaPP2S9fd0czP3myb747s
T/vx37yrJs0VffeAgteinioP8fHStZQdKqCOW3vuGr0ne47aXyG8foJZot8mT9Ui
udVrX+wx2Tr0+/R/1+BFZxSf/aJ7i4MWDUax7DKm+2Ig05qJ46x5pd+AZpoWE2Ht
ny50DovdcSLxNOyUMRsoGW/DJ8QrfEEtrkto2frEPmqJvCX0O+VLVfA+aGuLV/B1
5gKu/rriuHf3BnOGRDsqa6us8zgsL7wck8izWJdpPhECgYEA2818xK83OeGxMoC5
r2APwCwkbqWNwbzXlTGlJSLBkOV+8VYZC2q6oewnHg/cyF/W5nJtI8yVWVrwo7UZ
oBxw0njNtr93TTrKyq5PJmuN50FbNg45Or6rTxpaqxbK4dwDjknp14/w/Cxi01XI
YD1/vSAhj3CN05TRQcp5b3N1f00CgYEAzcceKuGRhtmP464rKkWDMJBom/4y7x3e
tihDcOVIGCG6hUnOg5PFoJcoJCTNMsUeCxjftiRiOW5Bihe7jkK9Se17W99SHeR7
4DDZBORkwm5KxAut4NZ4wyWoMCQZcUx3kSa+aTJ9KG4kvU1T5MozHLhJJanSoGm2
nGgv9TExKoMCgYBGGkWe3Vs5xLelKdUPEA419l4wQ/DwR3BijxDixTEDK47PHeyi
7YlUt2LKfbim15pMqVYRwuAnPY/eRpZDsI5zMkA59trv8L5Y4jswP8Fkbj3PAb5S
9BjjA77DLmPKoUcpDH3eWHQ9mVJzoLplp3ekNCk//F/fiWksGI2edC6XSQKBgBlV
Hf2hb0zuk6wv0NiPXisoW/h4PsT5JGXAZy0KzOlLna6y+11vX7D5atOoRCqv4Zb0
JPZDXGQ9kovxiAFnbe4f8kPJJk7PxgA/gzf69fyJn2KrHWjEfnFnvWDP0OIFy+Ju
pppEwOutQ5CaaG2OBuTOOxML6QYefYCbwuuodqkJAoGBAL3cReg8obiAOBDjKerU
Mipn95n0ihzr5by57/LYnl61GLNVsBo2ZL2m2p0vBwXZAlNHjeMdlyzBu1V179Zz
9WRGfJ14l4VQ6prPEkGwKqr7FiEhFF1ucGjEgXQ0INQyWRIp1L5FbPMs9OYGhiAa
uiQ5+6K8OqETVYf2OJhr1NT9
-----END PRIVATE KEY-----

使用公钥进行加密,可以看到已经被加密了

$ echo "hello world" >> hello.txt
$ openssl rsautl -encrypt  -pubin  -inkey pubkey.pem -in hello.txt -out cipher.txt

使用私钥进行解密

$ openssl rsautl -decrypt -inkey key.pem -in cipher.txt
hello world

我们知道使用私钥加密之后的密文,也只有公钥才能解密。两个密钥看似是等价的,如果我交换两个密钥,把密钥key.pem(之前的私钥)公布出去,保留密钥pubkey.pem(之前的公钥),能正确的加解密并保证安全么?

RSA加密的两个密钥可以交换使用么?

先说结论:在纯理论上可以,RSA两个密钥是等价的,无论公布哪一个都可以。在工程上不可以,既做不到正确加解密又做不到安全

先说说理论上可以的原因

简单来说RSA基于大质数分解的基本原理,而两个密钥分别和两个质数有关,两者并没有什么不同,可以互换使用,到底哪个是私钥哪个是公钥取决于哪个保密哪个任意分发

再来说说工程上不能的原因

🌲 第一点:私钥和公钥的文件格式是不一样的

可以试一下,我们用key.pem(之前的私钥)是没法加密的,所以我们公布出去私钥其他人是根本用不了的

$ openssl rsautl -encrypt  -pubin  -inkey key.pem -in hello.txt -out cipher.txt
unable to load Public Key

为什么私钥和公钥文件格式不一样?实际的私钥文件里除了包含密钥值以外,还记录了用于产生私钥的原始值。这也是为什么私钥的文件看起来字符更多的原因,利用这些原始值可以把公钥重新推导出来。

使用openssl就可以做到

// 通过私钥推导出公钥
$ openssl rsa -in key.pem -pubout -out pubkey.pem

🌲第二点:不安全

假设我们统一工程上的私钥和公钥文件的格式,去掉私钥文件中的原始信息,都只包含数学密钥本身,是否就可以任意互换使用了呢?答案是仍然不能

在原始的 RSA 原理定义里,质数 e 应该是随机选取的。但是实际工程应用中,固定为了 3 或者 65537

当解析pubkey.pem就可以看到Exponent: 65537

$ openssl rsa -pubin -in pubkey.pem -text
RSA Public-Key: (2048 bit)
Modulus:
    00:e3:d5:f0:46:26:b2:20:ae:b7:10:39:5b:c4:47:
    a9:27:d6:5e:7d:db:f0:04:c3:ba:ed:7c:6e:f6:9d:
    31:ac:b2:3d:7a:bc:65:02:1f:ff:e4:16:85:0a:82:
    cd:8d:29:dc:32:0d:e7:54:75:0f:58:6b:f2:32:4e:
    c5:3c:9d:d8:b3:7f:41:6e:74:3a:90:7b:71:4b:ad:
    5c:15:f3:3e:90:6b:58:ba:11:17:bb:b4:64:1a:48:
    94:5f:65:f0:1c:c8:a3:c7:ee:0b:23:82:0b:48:a9:
    02:3b:f1:fb:67:51:ea:96:96:53:9c:d3:3c:9d:f7:
    61:64:a6:c0:d8:80:fa:56:f2:6d:58:37:3a:f6:3d:
    74:50:db:d3:95:f8:80:98:07:15:c4:c8:93:76:f5:
    6c:fe:51:94:14:ac:55:15:41:ba:06:0c:d3:b6:cf:
    2d:27:46:dd:57:02:7d:03:9b:e4:6e:05:df:88:cb:
    6c:bb:cc:91:29:93:21:76:e3:21:c9:e4:d6:bd:93:
    4f:44:46:10:91:a9:ba:89:6d:37:53:da:79:de:a2:
    22:98:01:f1:2c:0c:9d:8a:52:f2:75:2a:c6:9d:bd:
    85:14:31:4a:6d:2f:3b:9f:f6:c4:21:5a:5a:9e:3b:
    fb:90:c5:c9:03:9e:22:98:4f:d6:87:07:23:dc:b3:
    bf:1b
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA49XwRiayIK63EDlbxEep
J9ZefdvwBMO67Xxu9p0xrLI9erxlAh//5BaFCoLNjSncMg3nVHUPWGvyMk7FPJ3Y
s39BbnQ6kHtxS61cFfM+kGtYuhEXu7RkGkiUX2XwHMijx+4LI4ILSKkCO/H7Z1Hq
lpZTnNM8nfdhZKbA2ID6VvJtWDc69j10UNvTlfiAmAcVxMiTdvVs/lGUFKxVFUG6
BgzTts8tJ0bdVwJ9A5vkbgXfiMtsu8yRKZMhduMhyeTWvZNPREYQkam6iW03U9p5
3qIimAHxLAydilLydSrGnb2FFDFKbS87n/bEIVpanjv7kMXJA54imE/Whwcj3LO/
GwIDAQAB
-----END PUBLIC KEY-----

所以如果你把实际的私钥当成了公钥分发出去,有心人如果看到里面的 e 值不是 3 或 65537,就可以猜测你用反了,并且尝试用 3 或 65537 来生成对应的密码,就不再安全

总结

再总结一次

在数学上,RSA私钥和公钥是轮换对称的,可以互换使用,到底哪个是私钥哪个是公钥取决于哪个保密哪个任意分发。但是在实际工程上由于两点原因,生成出来的密钥对就已经明确了哪一个是公钥,哪一个是私钥,不能互换使用。

所以在使用RSA千万不要发错密钥哦~


✨ 微信公众号【凉凉的知识库】同步更新,欢迎关注获取最新最有用的后端知识 ✨

参考