RSA根据已有的公私钥参数 E D N 求 p q invQ dp dQ,可转pkcs#8密钥文件格式base64编码
前几天领导找我要一个base64编码的RSA密钥(之前某个项目的),即pkcs#1或pkcs#8密钥格式,解析密钥格式的der编码后,发现需要 e n d p q dQ dp invQ 共八个参数,而我只有 e n d 三个参数,一下子有点束手无策,今天突发奇想,之前在python应用rsa密码算法时,我不也只给了 e n d 就能计算么,是否就说明我遗漏了解题的重要部分,于是,随着这一灵感进行摸索,最终我实现了领导的需求。
准备RSA密钥对
利用网站工具生成 RSA 密钥对,http://web.chacuo.net/netrsakeypair
pubkey:30819f300d06092a864886f70d010101050003818d0030818902818100cd39d6697f1f09b44663065ab02fa8693e80df3cc42682494f43d48b54bd3d8b9439bfaf93f84ecd9938359f355a7e1d50e0de9144813b7402299793e11e1a8eb8ae78a62c94827fb648244aa5ebb62d6b5e1d297379147e4484bf882457404351a3791405d0d1627eff035f82fd79bf15cef4b00cfc1e92e5787937e5d3f1c70203010001
prikey:30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100cd39d6697f1f09b44663065ab02fa8693e80df3cc42682494f43d48b54bd3d8b9439bfaf93f84ecd9938359f355a7e1d50e0de9144813b7402299793e11e1a8eb8ae78a62c94827fb648244aa5ebb62d6b5e1d297379147e4484bf882457404351a3791405d0d1627eff035f82fd79bf15cef4b00cfc1e92e5787937e5d3f1c702030100010281804fed5aa833ae2ee55b146e011be533bde96ddf8397113864bcce3a1519a7aa349641f779b6335add8ff2e84f5d442521ddc1f66cb5356fa63ac1601b63ed8981a1b94f0e5295362309ecc8a698d66a491392b60984d810f3efce4803c89c391a1b22afd2bfefc41d2b4b25fde10130f50e02a069e9053c14cee7bd9d2a9a4081024100e5e8e966a5f8e0c8dea885ad5a46919694f86a25a1d6b3b2c035084ed7da37c8b45a5b75c378ecbb4b9d269deec9c1c84f67ed10a77045f6ea06346ea273c537024100e483d62eb31088135b3748b9c3df343da25325e9e9c524b2507ed13d8b8e3a1f806453af311b649faa0d28735b528cef0ad94e06baa5c08471454a3bb8877ff1024100874854c66cd51457be04c59beaa9e993049763c63f0399fb8d73e72e957eb72267555fc9dcba73fa0595341aec5e55a36b6e08a5ab10ba6a7eec25c00fe1356302406fd8ab638e17605301096d1a2769bf3b0f915cf4418c51aac945590aa39cc88c149e866b3040f51e44f04dc5308496208611d863e8c52a16690e7e07ff08ab31024006e310c6765f86e53cbf05d0db79a9e28e12c1737152650acb7963d9660193b97daf96d1e4b545d5754b8d34a708016a23399a99e1cb811d2e6f4c204ae218c6
解析 pkcs#8 得到 e n d p q u dp dq qp u
30 820276
0201 // Version
00
300d // PrivateKeyAlgorithmIdentifier
06092a864886f70d0101010500
04820260 // PrivateKey
3082025c
0201
00
028181 // n
00cd39d6697f1f09b44663065ab02fa8693e80df3cc42682494f43d48b54bd3d8b9439bfaf93f84ecd9938359f355a7e1d50e0de9144813b7402299793e11e1a8eb8ae78a62c94827fb648244aa5ebb62d6b5e1d297379147e4484bf882457404351a3791405d0d1627eff035f82fd79bf15cef4b00cfc1e92e5787937e5d3f1c7
0203 // e
010001
028180 // d
4fed5aa833ae2ee55b146e011be533bde96ddf8397113864bcce3a1519a7aa349641f779b6335add8ff2e84f5d442521ddc1f66cb5356fa63ac1601b63ed8981a1b94f0e5295362309ecc8a698d66a491392b60984d810f3efce4803c89c391a1b22afd2bfefc41d2b4b25fde10130f50e02a069e9053c14cee7bd9d2a9a4081
0241 // q
00e5e8e966a5f8e0c8dea885ad5a46919694f86a25a1d6b3b2c035084ed7da37c8b45a5b75c378ecbb4b9d269deec9c1c84f67ed10a77045f6ea06346ea273c537
0241 // p
00e483d62eb31088135b3748b9c3df343da25325e9e9c524b2507ed13d8b8e3a1f806453af311b649faa0d28735b528cef0ad94e06baa5c08471454a3bb8877ff1
0241 // dq
00874854c66cd51457be04c59beaa9e993049763c63f0399fb8d73e72e957eb72267555fc9dcba73fa0595341aec5e55a36b6e08a5ab10ba6a7eec25c00fe13563
0240 // dp
6fd8ab638e17605301096d1a2769bf3b0f915cf4418c51aac945590aa39cc88c149e866b3040f51e44f04dc5308496208611d863e8c52a16690e7e07ff08ab31
0240 // Qinv(u)
06e310c6765f86e53cbf05d0db79a9e28e12c1737152650acb7963d9660193b97daf96d1e4b545d5754b8d34a708016a23399a99e1cb811d2e6f4c204ae218c6
根据 e n d 生成 p q u
依赖 pycrypto 库
from Crypto.PublicKey import RSA
key_para = (int('cd39d6697f1f09b44663065ab02fa8693e80df3cc42682494f43d48b54bd3d8b9439bfaf93f84ecd9938359f355a7e1d50e0de9144813b7402299793e11e1a8eb8ae78a62c94827fb648244aa5ebb62d6b5e1d297379147e4484bf882457404351a3791405d0d1627eff035f82fd79bf15cef4b00cfc1e92e5787937e5d3f1c7', 16),
int('010001', 16),
int('4fed5aa833ae2ee55b146e011be533bde96ddf8397113864bcce3a1519a7aa349641f779b6335add8ff2e84f5d442521ddc1f66cb5356fa63ac1601b63ed8981a1b94f0e5295362309ecc8a698d66a491392b60984d810f3efce4803c89c391a1b22afd2bfefc41d2b4b25fde10130f50e02a069e9053c14cee7bd9d2a9a4081', 16))
a = RSA.construct(key_para)
print('p = ' + hex(a.key.p))
print('q = ' + hex(a.key.q))
print('u = ' + hex(a.key.u))
输出结果
p = 0xe483d62eb31088135b3748b9c3df343da25325e9e9c524b2507ed13d8b8e3a1f806453af311b649faa0d28735b528cef0ad94e06baa5c08471454a3bb8877ff1
q = 0xe5e8e966a5f8e0c8dea885ad5a46919694f86a25a1d6b3b2c035084ed7da37c8b45a5b75c378ecbb4b9d269deec9c1c84f67ed10a77045f6ea06346ea273c537
u = 0x6e310c6765f86e53cbf05d0db79a9e28e12c1737152650acb7963d9660193b97daf96d1e4b545d5754b8d34a708016a23399a99e1cb811d2e6f4c204ae218c6
总结
(1)通过该接口生成 p q 后(原理后续再研究),再通过两个公式即可生成 dp dq,这样一来,就可以实现仅有 e d n 的情况下,组装为 pkcs#8 格式的key文件了。
dp=d(mod(p-1))
dq=d(mod(q-1))
(2)我是属于误打误撞实现的,在撰写该文章的过程中,在谷歌搜索 rsa dp dq 发现一个名为《Key Recovery Method for CRT Implementation of RSA》的pdf文档,在里面看到计算 dp dq 的公式,这才解决了最终的转pkcs#8的问题,说明我在遇到问题的时候没有先整理头绪的习惯,这样不好,会浪费时间,因为我能遇到的问题基本都已有前辈遇到甚至解决,在密码学中,我遇到的问题其实是涉及了密钥恢复的研究,之所以叫恢复而不是攻击,是根据我是否拥有私钥为准,没有私钥,那就是密钥攻击。