SpringBoot与JJWT集成RSA密钥时出现解码错误求助
RSA密钥加载报错:Unable to decode key 解决方法
问题重现
按照以下流程创建并使用RSA密钥时,出现java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: Unable to decode key错误:
1. 密钥生成脚本
# 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}"
2. .env配置
JWT_BE_PRIVATE_KEY=MIIJKA... JWT_BE_PUBLIC_KEY=MIICIjA...
3. application.properties配置
jwt.private.key=${JWT_BE_PRIVATE_KEY} jwt.public.key=${JWT_BE_PUBLIC_KEY}
4. Java密钥加载代码
@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))); } }
错误日志
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] ... Caused by: java.security.InvalidKeyException: Unable to decode key at java.base/sun.security.x509.X509Key.decode(X509Key.java:375) ~[na:na] ... Caused by: java.io.IOException: extra data at the end at java.base/sun.security.util.DerValue.<init>(DerValue.java:432) ~[na:na] ...
错误原因
- 二次Base64编码:脚本中对PEM文件提取出的Base64密钥内容,又执行了一次
base64 -w 0编码,导致最终存储的密钥是双重Base64编码的结果。Java解码后得到的不是密钥的DER字节流,而是原始Base64字符串的字节,解析时出现多余数据。 - 公钥格式不匹配:
openssl rsa -pubout生成的是PKCS#1格式公钥(首尾行-----BEGIN RSA PUBLIC KEY-----),而代码中X509EncodedKeySpec需要X.509格式的公钥(首尾行-----BEGIN PUBLIC KEY-----)。
解决方案
步骤1:修正密钥生成脚本
修改脚本,去掉二次Base64编码逻辑,同时调整公钥生成命令为X.509格式:
# Generate pem private key in PEM-encoded X.509 format openssl genrsa -out refresh.pem 4096 # 生成X.509格式公钥(适配X509EncodedKeySpec) openssl pkey -in refresh.pem -pubout -out refresh.pub # Convert the private key to PKCS#8 format openssl pkcs8 -topk8 -inform PEM -in refresh.pem -outform PEM -out refresh.key -nocrypt # 直接提取PEM中的Base64内容,去掉首尾行和换行,不做二次编码 PRIVATE_KEY=$(sed '1d;$d' refresh.key | tr -d '\n') PUBLIC_KEY=$(sed '1d;$d' refresh.pub | tr -d '\n') echo "JWT_BE_PRIVATE_KEY=${PRIVATE_KEY}" echo "JWT_BE_PUBLIC_KEY=${PUBLIC_KEY}"
步骤2:更新.env文件
运行修正后的脚本,将新输出的JWT_BE_PRIVATE_KEY和JWT_BE_PUBLIC_KEY值替换.env文件中的旧值。
步骤3:验证(可选)
手动验证公钥格式是否正确:
- 复制.env中的
JWT_BE_PUBLIC_KEY值,保存到文件public.b64 - 执行解码命令:
base64 -d public.b64 > public.der - 执行解析命令:
openssl x509 -inform DER -in public.der -text,若能正常输出公钥信息,则格式正确。
代码验证
原有的JJwtManager代码无需修改,只要密钥格式和编码正确,即可正常加载密钥。
内容的提问来源于stack exchange,提问作者Rogelio Olarte
相关产品推荐
相关产品推荐

