无法解析Java中的RSA publicKey

问题描述

我正在使用以下代码块来解析任何要加密的RSA公钥。

    static byte[] encrypt(byte[] publicKey,byte[] inputData) throws Exception {

    PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));

    Cipher cipher = Cipher.getInstance(ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE,key);

    byte[] encryptedBytes = cipher.doFinal(inputData);

    return encryptedBytes;
}

public static String getEncrypted(String data,String key) throws Exception {
    byte[] keyBytes = Base64.getDecoder().decode(key);
    return new String(Base64.getEncoder().encode(encrypt(keyBytes,data.getBytes())));
}

但是对于以下RSA公钥

MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFdpl+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2lIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB

解析时出现以下异常

Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error,not a sequence
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
    at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
Caused by: java.security.InvalidKeyException: IOException: algid parse error,not a sequence
    at sun.security.x509.X509Key.decode(X509Key.java:397)
    at sun.security.x509.X509Key.decode(X509Key.java:402)
    at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:86)
    at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)

任何想法都是失败的,以及如何制作通用的RSA公钥解析代码

解决方法

您的问题与InvalidKeySpecException : algid parse error,not a sequence中的问题类似,尽管不尽相同。就像PKCS8是(几乎)任何算法中私钥的通用格式一样,Java既包含标识算法 又包含算法专用数据,Java使用通用格式SubjectPublicKeyInfo(SPKI){{ 3}}用于公共密钥,Java称之为X509EncodedKeySpec,其中包含AlgId加上算法专用数据。 (请参阅Javadoc中的java.security.Key;由于某种原因,我当前无法访问docs.oracle.com来获取链接。)您只有算法特定的数据defined by X.509/PKIX

您可以defined by PKCS1 RSAPublicKeyparse and use it 'manually' with BouncyCastle。或者(给定BC或另一个ASN.1库),您可以使用与#31941413中相同的方法,只是省略Integer版本(0)并将数据包装在DERBitString中而不是DEROctetString中,或者我展示的是更简单,更直接的方法在convert it to SPKI and use that中。

请注意,这不是“通用”。您的格式与一般算法相反,如前所述,这是SPKI和PCKS8的目的。它也不是通用的;除其他外,OpenSSH,PGP,Microsoft,PKCS11,JWK和XML都使用与此不同的公钥格式,并且不容易与Java兼容。

,

您的公钥(这里只是Base64编码的部分)似乎是“ RSA公钥” 而不是“公钥”。后者是Java能够使用的格式。

要阅读“ RSA公钥”,您需要Bouncy Castle库和其他7行代码。当您拥有没有“包装”页眉和页脚的键时,我将两者添加 手动排线。

请记住,以下代码没有适当的异常处理,仅用于教育目的。

结果:

key: Sun RSA public key,2048 bits
  params: null
  modulus: 22678610734153400983507431374302231631648011897672768754638644005690558018788055145838420912495825001883497816406549666369767766949853573723573636289962789479998547620264293389522975840594912755684410510779642046063268111520844008640320545114702934792800828432077361704284837605938354936920018742130341245366517474980128047515437565419306561322350155414838564407700303406271838590880852369997316303577351737008942081641382006211591786506015023574950120763293965668830106827392978781367691242570394862298000041087969687942746452359360224223895623579995775734139473237799095359767270215802792812274542667250920043135261
  public exponent: 65537

代码:

import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

public class MainSO {
    public static void main(String[] args) throws IOException,NoSuchAlgorithmException,InvalidKeySpecException {
        System.out.println("https://stackoverflow.com/questions/63454577/failed-to-parse-rsa-publickey-in-java");
        Security.addProvider(new BouncyCastleProvider());
        String rsaPublicKeyHeader = "-----BEGIN RSA PUBLIC KEY-----\n";
        String rsaPublicKeyFooter = "\n-----END RSA PUBLIC KEY-----";
        String rsaPublicKeyString = "MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB";
        PEMParser pemParser = new PEMParser(new StringReader(rsaPublicKeyHeader +
                rsaPublicKeyString + rsaPublicKeyFooter));
        SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
        byte[] publicKey = subjectPublicKeyInfo.getEncoded();
        // original code starts here
        PublicKey key = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey));
        // check key
        System.out.println("key: " + key);
    }
}