You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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]
    ...

错误原因

  1. 二次Base64编码:脚本中对PEM文件提取出的Base64密钥内容,又执行了一次base64 -w 0编码,导致最终存储的密钥是双重Base64编码的结果。Java解码后得到的不是密钥的DER字节流,而是原始Base64字符串的字节,解析时出现多余数据。
  2. 公钥格式不匹配: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:验证(可选)

手动验证公钥格式是否正确:

  1. 复制.env中的JWT_BE_PUBLIC_KEY值,保存到文件public.b64
  2. 执行解码命令:base64 -d public.b64 > public.der
  3. 执行解析命令:openssl x509 -inform DER -in public.der -text,若能正常输出公钥信息,则格式正确。

代码验证

原有的JJwtManager代码无需修改,只要密钥格式和编码正确,即可正常加载密钥。

内容的提问来源于stack exchange,提问作者Rogelio Olarte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:44:50