【发布时间】:2020-01-28 22:20:42
【问题描述】:
我正在尝试从 kotlin 解析 RSA 格式的公钥。我有一个字符串中的键,其内容如下:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwAzOKC8d0o0dcv1KqILLehASGgOWyjlAc+adazix6ThhX7QeD3Qw
HzxPpbwsJrVPIEMEIN383awIqnCfIL+AbCQPL13XaUCCS74wC5a84X1r6hcI5XO1
9CPAn+jBKmTr4hPaHWKxuhfO3PcXxGfQdXyqNT96bCYnAYaeSECohFjqDbe+RFcL
1lIns2GtQPMh1/uDyhPA+8HSguREWn+Ac3I2c0wtrzZa6R4nruPgIi6XbWRqAskr
tzbO2Xy6O1DcERH9tg+es/pbrWHRHrwEmLXorj3iGqkJJBUmLeW6B5EjmIgiukdJ
dw7bLTNcwf2n0BLJy/bgnhcw4TMOzUadSQIDAQAB
-----END RSA PUBLIC KEY-----
我发现了很多代码示例来执行此操作,其中涉及使用 String.replace() 修剪 BEGIN 和 END,但这对我来说似乎很老套。 BouncyCastle code seems to handle this already 包括为它遇到的不同类型的“文件”创建解析器的能力。我正在尝试这个:
try {
val parser = PEMParser(StringReader(publicKeyString))
val pemObject = parser.readPemObject()
val pemContent = pemObject.content
val key = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(pemContent)
serviceLogger.info("Key object: {}", key)
} catch (e: Exception) {
serviceLogger.error("Could not generate key from keyspec", e)
}
我得到一个 pemContent(一个字节数组)没有问题,但是当我尝试将它实际解析为 RSAPublicKey 时,我得到了这个:
java.lang.IllegalArgumentException: failed to construct sequence from byte[]: DEF length 3 object truncated by 2
我无法弄清楚我是否正确调用 RSAPublicKey.getInstance() - 使用整个 PemObject 的内容 - 还是这个异常告诉我我的密钥有问题。
我在这方面能找到的例子已经很老了,而且 API 似乎已经发展到我不必手动分割字符串的地步了。
我怀疑这真的有助于解决问题,但我正在从 rsa 密钥对生成此文件:
func PublicKeyToPemBytes(prvkey *rsa.PrivateKey) ([]byte, error) {
var pubkey *rsa.PublicKey
pubkey = &prvkey.PublicKey
pubkey_bytes := x509.MarshalPKCS1PublicKey(pubkey)
if pubkey_bytes == nil {
return nil, errors.New("Public key could not be serialized")
}
pubkey_pem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubkey_bytes,
},
)
return pubkey_pem, nil
}
go rsa.PublicKey 对象包含一个 N 和一个 E。它为我提供了上面列出的文件,base64 解码结果完全相同,长度为 270 字节。
【问题讨论】:
-
您是否更改了数据并截断了它?它的一部分可能在一个有效的 PKCS1-RSAPublicKey 中,而不是偶然发生的,但其他部分是完全错误的。这种格式现在很少单独使用,我很惊讶 go 会这样做; Bouncy 支持它只是因为 OpenSSL 支持 - 而 OpenSSL 只是部分支持它,作为上个世纪的遗物。也就是说,如果您有有效数据,Bouncy 应该可以工作。 (也是 OpenSSL。)你能发布一个完整的密钥,甚至是一个测试密钥吗?记住公钥加密的要点是公钥不是秘密的,甚至可以被敌人知道。
-
正确,公平点。我修改了原始帖子以包含完整的密钥。我的密钥生成肯定有问题 - 它正在生成 ASN.1 类型为 0x62 而不是 0x02 的整数。我解决了这个问题,所以上面的例子对于 dumpasn1 和 'openssl asn1parse' 都是可以接受的
-
使用您发布的密钥,并对您的代码进行 Java 化处理(这意味着它几乎是逐字记录的),我没有遇到任何异常并获得预期的输出。
-
戴夫,哪种格式更好?我不想将它存储为实际证书(至少我不这么认为)......我只是想以某种合理的格式存储和传递 RSA 密钥对的公共部分。
-
看起来很笨重,使用 X.509/PKIX 证书——如果你没有一个真正的 CA 颁发的证书,那么一个虚拟的自签名证书——实际上是一种常见且处理公钥的传统方式(重要的是,PGP 和 SSH 除外)。如果您不想这样做,请使用 from X.509 的“SubjectPublicKeyInfo”结构 - 这是 OpenSSL 自 2000 年以来默认使用的结构,以及 Java
Key和KeyFactory(非对称) 直接支持它——在 DER(又名二进制)而不是 PEM 中,但是即使没有 Bouncy,在不需要更改数据的情况下进行转换也很容易。
标签: kotlin bouncycastle