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! :)