如何正确读取PEM格式私钥?读取时触发InvalidKeySpecException报错
解决java.security.spec.InvalidKeySpecException读取RSA私钥生成JWT的问题
你在读取RSA私钥生成JWT时遇到以下错误:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : null
代码中直接使用Base64解码私钥后通过PKCS8EncodedKeySpec解析,但报错依旧。
问题诊断
你的私钥是PKCS#1格式的,而PKCS8EncodedKeySpec仅支持解析PKCS#8格式的私钥编码,这是导致错误的核心原因。PKCS#1和PKCS#8是两种不同的RSA私钥编码标准,结构不兼容。
解决方案
提供两种可行的解决方式,按需选择:
方法1:将私钥转换为PKCS#8格式(推荐,无需修改代码)
使用OpenSSL命令将PKCS#1格式的私钥转换为PKCS#8格式:
openssl pkcs8 -topk8 -inform PEM -in your_private_key.pem -outform PEM -nocrypt -out private_key_pkcs8.pem
转换完成后,取出文件中-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的Base64字符串,替换到代码的privateKeyPEMFormatted变量中即可。
方法2:在代码中直接解析PKCS#1格式私钥(需依赖BouncyCastle)
如果无法提前转换私钥,可以通过BouncyCastle库辅助解析PKCS#1私钥:
- 首先添加Maven依赖:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency>
- 修改私钥解析代码:
import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.RSAPrivateKeySpec; import java.util.Base64; private PrivateKey getPrivateKey() throws Exception { // 注册BouncyCastle提供者 Security.addProvider(new BouncyCastleProvider()); String privateKeyPEM = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCATwwggE4AgEAAkEAzPUG7l/N0B5wr7TxF0+5Uxl5GZJ9N7ck+l5lUGM3yMR5YVqekZ6J0ON5nFfTmT3Tx5h+u5YKhzZ/bHYf8bFg9wIDAQABAkAAvNjEzfDbBVeBGWRCGhfM4kQFdyI9IoO2HJ6WgdSZK/LQvdSMbJf6e4O08Kj2FSq+O1WLPoT3sQ4lNaaRQ+2hAiEA+u5tQFcmFUVZsZb+uD/FXNdBlRXI/D7L4Ib4Nnb3OgECIQDYfhFPBeROr9tQRYNhuWmfGAtSjaKlG2cGQXYMlyiNVwIgCcLr5G6eGHiz7E9aPyRQo/1Wn+5x3w9Z0P1pX6QEzL8CIQCET+ZWAA8lfvTofU8QzXpJcN9L5xROOZ1TGyz+jmiOFQIhAK9F1mpOKkFdTLDXrdypo+5rAhnxqV2P9Hp+1vKQtZ9x"; // 解码Base64私钥 byte[] pkcs1Bytes = Base64.getDecoder().decode(privateKeyPEM); ASN1Sequence pkcs1Seq = ASN1Sequence.getInstance(pkcs1Bytes); // 提取PKCS#1结构中的私钥参数 RSAPrivateKeySpec spec = new RSAPrivateKeySpec( ((ASN1Integer) pkcs1Seq.getObjectAt(1)).getPositiveValue(), ((ASN1Integer) pkcs1Seq.getObjectAt(3)).getPositiveValue() ); // 使用BouncyCastle的KeyFactory生成私钥 KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); return kf.generatePrivate(spec); }
验证
生成私钥后,可以用以下代码测试JWT签名:
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; String jwt = Jwts.builder() .setSubject("test_user") .signWith(getPrivateKey(), SignatureAlgorithm.RS256) .compact(); System.out.println(jwt);
内容的提问来源于stack exchange,提问作者Yaron
相关产品推荐
相关产品推荐

