0

I am using the following code block to parse any RSA public key to encrypt.

    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())));
}

But for the following RSA public Key

MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB

while parsing I am getting the following exception

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)

Any idea what is failing and how to make a generic RSA public key parsing code.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
Raghu K Nair
  • 3,854
  • 1
  • 28
  • 45
  • Does this answer your question? [InvalidKeySpecException : algid parse error, not a sequence](https://stackoverflow.com/questions/31941413/invalidkeyspecexception-algid-parse-error-not-a-sequence) – MWiesner Aug 17 '20 at 16:25
  • @MWiesner I don't think so. The problem there is for Private key not in PKCS8 format. Whereas this is about parsing Public Key. – Raghu K Nair Aug 17 '20 at 16:30

2 Answers2

2

Your public key (here just the Base64-encoded part) seems to be a 'RSA Public Key' and not a 'Public Key'. The later is the format that Java is been able to work with.

To read the 'RSA Public Key' you need the Bouncy Castle library and additional 7 lines of code. As you have the key without the 'wrapping' header and footer I add the two line manually.

Please keep in mind that the following code has no proper exception handling and is for educational purposes only.

result:

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

code:

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);
    }
}
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
2

Your problem is analagous to the problem in InvalidKeySpecException : algid parse error, not a sequence, though not the same. Just like PKCS8 is a generic format for private keys in (almost) any algorithm, by containing both an AlgorithmIdentifier that identifies the algorithm and algorithm-specific data, Java uses the generic format SubjectPublicKeyInfo (SPKI) defined by X.509/PKIX for public keys, which Java calls X509EncodedKeySpec, containing an AlgId plus algorithm-specific data. (See the javadoc for java.security.Key; for some reason I am currently unable to access docs.oracle.com to get a link.) You have only the algorithm-specific data defined by PKCS1 RSAPublicKey.

You can parse and use it 'manually' with BouncyCastle, or convert it to SPKI and use that. Or (given BC or another ASN.1 library) you could use the same approach as in #31941413 except omit the Integer version (0) and wrap the data in a DERBitString instead of a DEROctetString, or the simpler and more direct approach I show in RSA should I use X.509 or PKCS #1 .

Note this is not 'generic'. Your format is the opposite of algorithm-generic, which as noted is the purpose of SPKI and PCKS8. It is also not applciation-generic; among other things OpenSSH, PGP, Microsoft, PKCS11, JWK, and XML all use publickey formats different from this and not easily compatible with Java.

Community
  • 1
  • 1
dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70