0

I'm trying to read private and public RSA keys in Java for a JWS-based event signing, but somehow I am unable to read the public key. Note that I cannot change the commands to generate the keys since they're generated by a third-party.

I generated RSA private and public keys using:

ssh-keygen -t rsa -P "" -b 4096 -m PEM -f jwtRS256.key
ssh-keygen -e -m PEM -f jwtRS256.key > jwtRS256.key.pub

Trying to load private key which works fine:

       java.security.Security.addProvider(
                new org.bouncycastle.jce.provider.BouncyCastleProvider()
        );

        String privateKeyPEM = Files.readString(Path.of("jwtRS256.key"), Charset.defaultCharset());
        String privateKey = privateKeyPEM
                .replace("-----BEGIN RSA PRIVATE KEY-----", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END RSA PRIVATE KEY-----", "");
        byte[] decodedPrivateKey = Base64.decodeBase64(privateKey);
        KeyFactory keyFactoryPrivate = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpecPrivate = new PKCS8EncodedKeySpec(decodedPrivateKey);
        RSAPrivateKey privateKeyRSA = (RSAPrivateKey) keyFactoryPrivate.generatePrivate(keySpecPrivate);

Trying to load public key using:

        String publicKeyPEM = Files.readString(Path.of("jwtRS256.key.pub"), Charset.defaultCharset());
        String publicKey = publicKeyPEM
                .replace("-----BEGIN RSA PUBLIC KEY-----", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END RSA PUBLIC KEY-----", "");
        byte[] decodedPublicKey = Base64.decodeBase64(publicKey);
        KeyFactory keyFactoryPublic = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpecPublic = new X509EncodedKeySpec(decodedPublicKey);
        PublicKey finalKeyPublic = keyFactoryPublic.generatePublic(keySpecPublic);

which throws:

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
    at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:241)
    at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:351)
    at Main.jwstest(Main.java:65)
    at Main.main(Main.java:73)
Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:397)
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:402)
    at java.base/sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:151)
    at java.base/sun.security.rsa.RSAPublicKeyImpl.newKey(RSAPublicKeyImpl.java:78)
    at java.base/sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:327)
    at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:237)
    ... 3 more

I've tried the Bouncy Castle PEMReader as well, and that throws the same error.

Note that I cannot change the commands to generate the keys since they're generated by a third-party.

Can someone please help?

UPDATE:

I was able to get it working using this answer mentioned in the comments.

        PEMParser pemParser = new PEMParser(new FileReader("jwtRS256.key.pub"));
        Object object = pemParser.readObject();
        SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) object;
        RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(subjectPublicKeyInfo);
        RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
        KeyFactory kf = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
        PublicKey finalKeyPublic = kf.generatePublic(rsaSpec);

I needed to add the following dependencies to my pom.xml to use BouncyCastle methods.

        <dependency>
            <groupId>org.bitbucket.b_c</groupId>
            <artifactId>jose4j</artifactId>
            <version>0.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>

Thanks guys! :)

  • 2
    For public and private keys, https://stackoverflow.com/q/41934846/238704 and https://stackoverflow.com/q/58166071/238704. – President James K. Polk Feb 03 '23 at 17:27
  • 1
    Yep, the public key is not in X509 / SPKI form but PKCS#1 encoded. The hint for that is that it reads **RSA PUBLIC KEY** rather than **PUBLIC KEY**. – Maarten Bodewes Feb 03 '23 at 19:57
  • This refers to *private* keys, but it might provide some insight: [**Getting RSA private key from PEM BASE64 Encoded private key file**](https://stackoverflow.com/questions/7216969/getting-rsa-private-key-from-pem-base64-encoded-private-key-file/55339208) – Andrew Henle Feb 03 '23 at 22:23
  • Thank you so much guys! This worked for me: https://stackoverflow.com/q/58166071/238704. I will post the updated code soon! :) – Chinmay Chandak Feb 06 '23 at 05:01

0 Answers0