使用 Java 将 ASN1 序列解码为 RSA 公钥



我有以下RSA公钥作为ASN1序列:

SEQUENCE(2 elem)
  INTEGER (1024 bit) 14832…
  INTEGER 65537

如何在 Java 中将此序列作为 RSA 公钥导入?实现的KeySpec(例如PKCS8EncodedKeySpec)不起作用(显然)。

此外,我尝试使用BouncyCastle并手动解码序列并自己初始化java.security.spec.RSAPublicKeySpec。然而,这种方法似乎相当笨拙。

有没有更简单的方法?

ASN.1 使用 BouncyCastle 解析并不是那么笨拙。

String key =
"30818902818100cc61f9ef5ad0bc21de5b3ca69ee725d2c504edf99a6e97a0279d9" +
"59f2364ed21aaef8c704552d5d1a3deb2ee1a0be1558e3ca182b11a8c14392b6de5" +
"2346bc7c88bf75e3fb2b9f27fab21f5cf19934e3110ea4ad72a6f073f8ab38b9939" +
"bb639e78ad7f434119d8cc2b1bde4eaf9513b056508c908ed43c99b0ceb222cbbe1" +
"ef0203010001";
byte[] keyBytes = DatatypeConverter.parseHexBinary(key);
// These will throw exception in case of type mismatch
ASN1Sequence sequence = ASN1Sequence.getInstance(keyBytes);
ASN1Integer modulus = ASN1Integer.getInstance(sequence.getObjectAt(0));
ASN1Integer exponent = ASN1Integer.getInstance(sequence.getObjectAt(1));
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus.getPositiveValue(),
        exponent.getPositiveValue());
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(keySpec);
System.out.println(publicKey.toString());

另一种选择是将序列构建为 X509 公钥格式,然后使用 X509EncodedKeySpec 。您需要将编码密钥作为位序列与算法标识符一起放入 ASN.1 序列中。但是,这将导致大致相同的代码量,并且速度较慢,因为要解析的代码更多。这个答案已经很好地解释了格式。

您可以使用 Bouncycastle 库,如以下代码片段所示:

import java.io.IOException;
import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DLSequence;
public class RsaAsn1Example {
// ...
    public static BigInteger [] parseASN1RsaPublicKey(byte [] encoded) throws IOException {
        ASN1InputStream asn1_is = new ASN1InputStream(encoded);
        DLSequence dlSeq = (DLSequence) asn1_is.readObject();
        ASN1Integer asn1_n = (ASN1Integer) dlSeq.getObjectAt(0);
        ASN1Integer asn1_e = (ASN1Integer) dlSeq.getObjectAt(1);
        asn1_is.close();
        return new BigInteger[]{ asn1_n.getPositiveValue(), asn1_e.getPositiveValue()};
    }
// ....
}

或者,作为一个不太吸引人的替代方案,您可以滚动自己的 ASN.1 解码器,如我的一个答案中的此示例所示。但请注意,ASN.1 解码可能非常棘手——这个非常简单的双元素序列是我尝试用自己的代码解析的最复杂的 ASN.1 结构。

最新更新