I want to replace the com.google.api.client.util.Base64
library with the com.google.common.io.BaseEncoding
library since it is deprecated (I am working with Java 11).
I use these libraries to verify an RSA-signed jwt. To create the public key I take the String representation of the n and the e value of my certificate and turn it into a BigInteger.
My solution always throws this exception: com.google.common.io.BaseEncoding$DecodingException: Unrecognized character: -
There are -
characters in the strings I want to decode, but I do not know how to work this out with the BaseEncoding Package.
Did someone encounter this problem and can help me?
Here is the code with the com.google.api.client.util.Base64
decoding:
package com.example;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Calendar;
import com.auth0.jwk.InvalidPublicKeyException;
import com.auth0.jwk.JwkException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.api.client.util.Base64;
public final class App {
public final static String PUBLIC_KEY_ALGORITHM = "RSA";
/**
* Returns a {@link PublicKey} if the {@code 'alg'} is {@code 'RSA'}
*
* @return a public key
* @throws InvalidPublicKeyException if the key cannot be built or the key type is not RSA
*/
public static PublicKey getPublicKey() throws InvalidPublicKeyException {
try {
KeyFactory kf = KeyFactory.getInstance(PUBLIC_KEY_ALGORITHM);
byte[] decodedPubN = Base64.decodeBase64(PUB_N);
byte[] decodedPubE = Base64.decodeBase64(PUB_E);
BigInteger modulus = new BigInteger(1, decodedPubN);
BigInteger exponent = new BigInteger(1, decodedPubE);
return kf.generatePublic(new RSAPublicKeySpec(modulus, exponent));
} catch (InvalidKeySpecException e) {
throw new InvalidPublicKeyException("Invalid public key", e);
} catch (NoSuchAlgorithmException e) {
throw new InvalidPublicKeyException("Invalid algorithm to generate key", e);
}
}
/**
*
*
* @param args The arguments of the program.
* @throws JwkException
*/
public static void main(String[] args) throws JwkException {
DecodedJWT jwt = JWT.decode(TOKEN);
PublicKey publicKey = getPublicKey();
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
algorithm.verify(jwt);
if (jwt.getExpiresAt().before(Calendar.getInstance().getTime())) {
throw new RuntimeException("Expired token!");
}
}
}
I refactored the getPublicKey() function with the com.google.common.io.BaseEncoding
library:
/**
* Returns a {@link PublicKey} if the {@code 'alg'} is {@code 'RSA'}
*
* @return a public key
* @throws InvalidPublicKeyException if the key cannot be built or the key type is not RSA
*/
public static PublicKey getPublicKey() throws InvalidPublicKeyException {
try {
KeyFactory kf = KeyFactory.getInstance(PUBLIC_KEY_ALGORITHM);
BigInteger modulus = new BigInteger(1, BaseEncoding.base64().decode(pubN));
BigInteger exponent = new BigInteger(1, BaseEncoding.base64().decode(pubE));
return kf.generatePublic(new RSAPublicKeySpec(modulus, exponent));
} catch (InvalidKeySpecException e) {
throw new InvalidPublicKeyException("Invalid public key", e);
} catch (NoSuchAlgorithmException e) {
throw new InvalidPublicKeyException("Invalid algorithm to generate key", e);
}
}
Like in the comments mentioned, a JWT uses Base64Url encoding. I just had to change BaseEncoding.base64().decode(pubN)
to BaseEncoding.base64Url().decode(pubN)
.