RSA:在给定公钥的情况下获取指数和模数
Posted
技术标签:
【中文标题】RSA:在给定公钥的情况下获取指数和模数【英文标题】:RSA: Get exponent and modulus given a public key 【发布时间】:2011-03-08 05:03:54 【问题描述】:我需要在 javascript 中使用 RSA 加密一些数据。周围的所有库都要求提供指数和模数,但我从对手那里得到了一个 public.key
文件。
如何从 RSA 文件中检索公共 exponent
和 modulus
部分?
【问题讨论】:
您找到解决方案了吗? 【参考方案1】:这取决于您可以使用的工具。我怀疑是否有一个 JavaScript 也可以直接在浏览器中完成。这还取决于它是一次性的(总是相同的键)还是您是否需要编写脚本。
命令行/OpenSSL
如果您想在 unix 命令行上使用 OpenSSL 之类的东西,您可以执行以下操作。 我假设您的 public.key 文件包含这样的内容:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmBAjFv+29CaiQqYZIw4P
J0q5Qz2gS7kbGleS3ai8Xbhu5n8PLomldxbRz0RpdCuxqd1yvaicqpDKe/TT09sR
mL1h8Sx3Qa3EQmqI0TcEEqk27Ak0DTFxuVrq7c5hHB5fbJ4o7iEq5MYfdSl4pZax
UxdNv4jRElymdap8/iOo3SU1RsaK6y7kox1/tm2cfWZZhMlRFYJnpoXpyNYrp+Yo
CNKxmZJnMsS698kaFjDlyznLlihwMroY0mQvdD7dCeBoVlfPUGPAlamwWyqtIU+9
5xVkSp3kxcNcNb/mePSKQIPafQ1sAmBKPwycA/1I5nLzDVuQa95ZWMn0JkphtFIh
HQIDAQAB
-----END PUBLIC KEY-----
然后,命令将是:
PUBKEY=`grep -v -- ----- public.key | tr -d '\n'`
然后,您可以查看 ASN.1 结构:
echo $PUBKEY | base64 -d | openssl asn1parse -inform DER -i
这应该给你这样的东西:
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING
模数和公共指数在最后一个 BIT STRING 中,偏移量 19,所以使用-strparse
:
echo $PUBKEY | base64 -d | openssl asn1parse -inform DER -i -strparse 19
这将为您提供十六进制的模数和公共指数(两个整数):
0:d=0 hl=4 l= 266 cons: SEQUENCE
4:d=1 hl=4 l= 257 prim: INTEGER :98102316FFB6F426A242A619230E0F274AB9433DA04BB91B1A5792DDA8BC5DB86EE67F0F2E89A57716D1CF4469742BB1A9DD72BDA89CAA90CA7BF4D3D3DB1198BD61F12C7741ADC4426A88D1370412A936EC09340D3171B95AEAEDCE611C1E5F6C9E28EE212AE4C61F752978A596B153174DBF88D1125CA675AA7CFE23A8DD253546C68AEB2EE4A31D7FB66D9C7D665984C951158267A685E9C8D62BA7E62808D2B199926732C4BAF7C91A1630E5CB39CB96287032BA18D2642F743EDD09E0685657CF5063C095A9B05B2AAD214FBDE715644A9DE4C5C35C35BFE678F48A4083DA7D0D6C02604A3F0C9C03FD48E672F30D5B906BDE5958C9F4264A61B452211D
265:d=1 hl=2 l= 3 prim: INTEGER :010001
如果它总是相同的键,那可能没问题,但这可能不太方便放入脚本中。
或者(这可能更容易放入脚本中),
openssl rsa -pubin -inform PEM -text -noout < public.key
将返回:
Modulus (2048 bit):
00:98:10:23:16:ff:b6:f4:26:a2:42:a6:19:23:0e:
0f:27:4a:b9:43:3d:a0:4b:b9:1b:1a:57:92:dd:a8:
bc:5d:b8:6e:e6:7f:0f:2e:89:a5:77:16:d1:cf:44:
69:74:2b:b1:a9:dd:72:bd:a8:9c:aa:90:ca:7b:f4:
d3:d3:db:11:98:bd:61:f1:2c:77:41:ad:c4:42:6a:
88:d1:37:04:12:a9:36:ec:09:34:0d:31:71:b9:5a:
ea:ed:ce:61:1c:1e:5f:6c:9e:28:ee:21:2a:e4:c6:
1f:75:29:78:a5:96:b1:53:17:4d:bf:88:d1:12:5c:
a6:75:aa:7c:fe:23:a8:dd:25:35:46:c6:8a:eb:2e:
e4:a3:1d:7f:b6:6d:9c:7d:66:59:84:c9:51:15:82:
67:a6:85:e9:c8:d6:2b:a7:e6:28:08:d2:b1:99:92:
67:32:c4:ba:f7:c9:1a:16:30:e5:cb:39:cb:96:28:
70:32:ba:18:d2:64:2f:74:3e:dd:09:e0:68:56:57:
cf:50:63:c0:95:a9:b0:5b:2a:ad:21:4f:bd:e7:15:
64:4a:9d:e4:c5:c3:5c:35:bf:e6:78:f4:8a:40:83:
da:7d:0d:6c:02:60:4a:3f:0c:9c:03:fd:48:e6:72:
f3:0d:5b:90:6b:de:59:58:c9:f4:26:4a:61:b4:52:
21:1d
Exponent: 65537 (0x10001)
Java
这取决于输入格式。如果它是密钥库中的 X.509 证书,请使用 (RSAPublicKey)cert.getPublicKey()
:此对象有两个用于模数和指数的 getter。
如果它的格式如上,您可能需要使用BouncyCastle 及其PEMReader
来阅读它。我没有尝试过下面的代码,但这看起来或多或少是这样的:
PEMReader pemReader = new PEMReader(new FileReader("file.pem"));
Object obj = pemReader.readObject();
pemReader.close();
if (obj instanceof X509Certificate)
// Just in case your file contains in fact an X.509 certificate,
// useless otherwise.
obj = ((X509Certificate)obj).getPublicKey();
if (obj instanceof RSAPublicKey)
// ... use the getters to get the BigIntegers.
(您也可以在 C# 中类似地使用 BouncyCastle。)
【讨论】:
+1 不错的答案。查看 PEMReader.java 的源代码,它是一个真正的主力。它将检测和读取各种变体并返回适当的对象。另一种可能的格式是 X509EncodedKeySpec,它由 java 中的 RSAPublicKey.getEncoded() 返回 RSAPublicKey.getEncoded()(即使使用 Sun 提供程序实现)将返回一个 byte[] 数组,其内容与 PEM 中 --BEGIN/END PUBLIC KEY-- 之间的内容相同格式,除了它是 base64 编码的文本呈现在那里。实际上,您可以在没有 BouncyCastle 的情况下使用 X509EncodedKeySpec,但您必须进行 base64 解码,然后使用 java.security.KeyFactory 来构建实际的 RSAPublicKey。可行,但我更喜欢用BC。 非常感谢布鲁诺。我将使用命令行版本... 你能对私钥做类似的事情吗?得到指数?谢谢! (1)openssl asn1parse
不需要自己解码PEM,它可以处理PEM(这甚至是默认的);它甚至可以处理 PEM body(带有换行符的 DER 的 base64,但没有 BEGIN/END 行)。只是不要在 PEM 块外部包含任何“cmets”;许多其他openssl
命令可以处理这个问题,但不是asn1parse
(2) BouncyCastle 从 2012 年的 1.47 开始在bcpkix
而不是 bcprov
中使用 PEMReader,并且从 2013 年的 1.50 开始,它被重命名为 PEMParser;对于证书,它返回X509CertificateHolder
而不是X509Certificate
,对于公钥,它返回SubjectPublicKeyInfo
【参考方案2】:
使用时注意模数中可能出现的前导00:
openssl rsa -pubin -inform PEM -text -noout < public.key
示例模数包含 257 个字节而不是 256 个字节,因为 00 包含在内,因为 98 中的 9 看起来像一个负符号数。
【讨论】:
【参考方案3】:主要是为了我自己的参考,下面是你如何从 ssh-keygen 生成的私钥中获取它
openssl rsa -text -noout -in ~/.ssh/id_rsa
当然,这只适用于私钥。
【讨论】:
不适用于自 2014 年 6.5 起由ssh-keygen -o
生成的私钥,或自 2018 年 7.8 起默认(无 -m pem
)生成的私钥;那些使用 OpenSSH 专有格式 openssl
无法读取。 OpenSSH 的 id_xxx.pub
也无法被 OpenSSL 读取,但 ssh-keygen -e -m pkcs8
因为大约 6.0 输出了 openssl rsa -pubin -text -noout
可读的 PEM 公钥(如布鲁诺很久以前的回答)【参考方案4】:
如果您需要在脚本中解析 ASN.1 对象,可以使用一个库:https://github.com/lapo-luchini/asn1js
为了做数学,我发现 jsbn 很方便:http://www-cs-students.stanford.edu/~tjw/jsbn/
遍历 ASN.1 结构并提取 exp/mod/subject/etc。由你决定——我从来没有走到那一步!
【讨论】:
【参考方案5】:除了上面的答案,我们可以使用asn1parse
来获取值
$ openssl asn1parse -i -in pub0.der -inform DER -offset 24
0:d=0 hl=4 l= 266 cons: SEQUENCE
4:d=1 hl=4 l= 257 prim: INTEGER :C9131430CCE9C42F659623BDC73A783029A23E4BA3FAF74FE3CF452F9DA9DAF29D6F46556E423FB02610BC4F84E19F87333EAD0BB3B390A3EFA7FB392E935065D80A27589A21CA051FA226195216D8A39F151BD0334965551744566AD3DAEB53EBA27783AE08BAAACA406C27ED8BE614518C8CD7D14BBE7AFEBE1D8D03374DAE7B7564CF1182A7B3BA115CD9416AB899C5803388EE66FA3676750A77AC870EDA027DC95E57B9B4E864A3C98F1BA99A4726C085178EA8FC6C549BE5EDF970CCB8D8F9AEDEE3F5CFDE574327D05ED04060B2525FB6711F1D78254FF59089199892A9ECC7D4E4950E0CD2246E1E613889722D73DB56B24E57F3943E11520776BC4F
265:d=1 hl=2 l= 3 prim: INTEGER :010001
现在,为了得到这个偏移量,我们尝试使用默认的 asn1parse
$ openssl asn1parse -i -in pub0.der -inform DER
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING
我们需要到达 BIT String 部分,所以我们添加大小
depth_0_header(4) + depth_1_full_size(2 + 13) + Container_1_EOC_bit + BIT_STRING_header(4) = 24
这可以在ASN.1 Parser 更好地显示,如果你将鼠标悬停在标签上,你会看到偏移量
另一个惊人的资源:@987654322@
【讨论】:
【参考方案6】:我设法找到了这个solution 的答案,必须为此进行 javascript 注入才能安装 atob
const atob:any = require('atob');
asn1(pem: any)
asn1parser.Enc.base64ToBuf = function (b64:any)
return asn1parser.Enc.binToBuf(atob(b64));
;
const dertest = asn1parser.PEM.parseBlock(pem).der;
var hex = asn1parser.Enc.bufToHex(asn1parser.PEM.parseBlock(pem).der)
var buf = asn1parser.ASN1.parse(dertest);
var asn1 = JSON.stringify(asn1parser.ASN1.parse(dertest), asn1parser.ASN1._replacer, 2 );
【讨论】:
以上是关于RSA:在给定公钥的情况下获取指数和模数的主要内容,如果未能解决你的问题,请参考以下文章
在 Objective-c 中从模数和指数以字节为单位生成 RSA 公钥
如何验证 Apple 登录的 Jwt 令牌(后端验证)。如何从 Java 中的模数和指数 (n,e) 生成 RSA 公钥