I am currently following this flow to create and use my RSA keys
First I create my RSA keys with the following bash script.
# Generate pem private key in PEM-encoded X.509 format
openssl genrsa -out refresh.pem 4096
# generate public key
openssl rsa -in refresh.pem -out refresh.pub -pubout
# Convert the private key to PKCS#8 format
openssl pkcs8 -topk8 -inform PEM -in refresh.pem -outform PEM -out refresh.key -nocrypt
PRIVATE_KEY=$(sed '1d;$d' refresh.key | tr -d '\n' | base64 -w 0)
PUBLIC_KEY=$(sed '1d;$d' refresh.pub | tr -d '\n' | base64 -w 0)
echo "JWT_BE_PRIVATE_KEY=${PRIVATE_KEY}"
echo "JWT_BE_PUBLIC_KEY=${PUBLIC_KEY}"
Then with the variables in the terminal, I add them to a .env file
JWT_BE_PRIVATE_KEY=MIIJKA...
JWT_BE_PUBLIC_KEY=MIICIjA...
Then in my application.properties I add the following to use the environment variables.
jwt.private.key=${JWT_BE_PRIVATE_KEY}
jwt.public.key=${JWT_BE_PUBLIC_KEY}
Finally I use these variables in my component
@Component
public class JJwtManager {
private final SignatureAlgorithm alg = Jwts.SIG.RS512;
private final RSAPrivateKey privateKey;
private final RSAPublicKey publicKey;
public JJwtManager(@Value("${jwt.private.key}") @NonNull String privateKeyStr,
@Value("${jwt.public.key}") @NonNull String publicKeyStr)
throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
this.privateKey = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec
(Decoders.BASE64.decode(privateKeyStr)));
this.publicKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec
(Decoders.BASE64.decode(publicKeyStr)));
}
}
However, I get the following error:
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: Unable to decode key
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:241) ~[na:na]
at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:351) ~[na:na]
at com.example.security.manager.JJwtManager.<init>(JJwtManager.java:45) ~[classes/:na]
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[na:na]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:209) ~[spring-beans-6.2.0.jar:6.2.0]
... 37 common frames omitted
Caused by: java.security.InvalidKeyException: Unable to decode key
at java.base/sun.security.x509.X509Key.decode(X509Key.java:375) ~[na:na]
at java.base/sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:146) ~[na:na]
at java.base/sun.security.rsa.RSAPublicKeyImpl.newKey(RSAPublicKeyImpl.java:78) ~[na:na]
at java.base/sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:324) ~[na:na]
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:237) ~[na:na]
... 43 common frames omitted
Caused by: java.io.IOException: extra data at the end
at java.base/sun.security.util.DerValue.<init>(DerValue.java:432) ~[na:na]
at java.base/sun.security.util.DerValue.<init>(DerValue.java:344) ~[na:na]
at java.base/sun.security.x509.X509Key.decode(X509Key.java:373) ~[na:na]
... 47 common frames omitted
I would be very grateful in advance to anyone who can help me.
Currently the component constructor code has been changed several times according to other implementations but they are similar or give the same error.
Error was encountered while creating environment variables in the bash script. Where only one line had to be corrected to avoid using encoding the already encoded key.
PRIVATE_KEY=$(sed '1d;$d' refresh.key | tr -d '\n')
PUBLIC_KEY=$(sed '1d;$d' refresh.pub | tr -d '\n')