java.security.InvalidKeyException:无效的密钥格式... PublicKey 错误
Posted
技术标签:
【中文标题】java.security.InvalidKeyException:无效的密钥格式... PublicKey 错误【英文标题】:java.security.InvalidKeyException: invalid key format ... PublicKey error 【发布时间】:2021-11-16 01:27:02 【问题描述】:我知道有很多问题,但似乎没有一个适合我的需要。
我需要验证 JWT 令牌,我只有 PublicKey(这很好,因为我可以验证 jwt 的符号。
代码如下。
首先我们有公钥
private static final String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA88aLoh5l9W9UY3Hb+YGU\r\n"
+ "ZQBwVWuNTNpF5nm9uU+MqmB7EUmTYdD4Jk09zjBUutnggY10Jbjxdrv09HnHrqbj\r\n"
+ "+hyOyIXgSsVIK5bGZVHKLJzzZmWgn0QgcEXzR97J47MFeWkn0tEgDlP8LEMZE7ix\r\n"
+ "9WgoJHGGtUaQV5MM3U9S13zyRmaYekCVfLh2REHevb1aHgDReCLx92ZIdc9ldE9g\r\n"
+ "99v87E5zNKSv3AI8EVRt/Tpjfyuk7XTEqY6pz83tCfy1uch8NihhVjY8O2J3pilP\r\n"
+ "VW/L83GMJ5Shea0mE2Dq9Gh4lrVvAy+OHkarwGgdlYLwy1Dmof2SYCCq2SJyv5ZR\r\n"
+ "fwIDAQAB";
然后在我们得到的方法里面
JWTVerifier verifierToken = JWT.require(Algorithm.RSA256((RSAPublicKey) getPublicFederaKey(), null)).build();
DecodedJWT decodeJwt = verifierToken.verify(token);
Map<String, Object> claims = new HashMap<String, Object>();
String codiceFiscale = decodeJwt.getClaim("CODICEFISCALE").asString();
System.err.println("CODICE FISCALE: "+codiceFiscale);
if (decodeJwt.getExpiresAt().before(java.util.Calendar.getInstance().getTime()))
throw new RuntimeException("Expired token!");
如果您在 verifyToken 上看到它引用 getPublicFederaKey();
private PublicKey getPublicFederaKey() throws CustomException
PublicKey key = null;
try
String keyTrimmed = publicKey.trim().replace("\n", "").replace("\r", "");
System.err.println(keyTrimmed);
int stringLength = keyTrimmed.length(); //392
String hexString = Hex.encodeHexString(publicKey.getBytes("UTF-8"));
byte[] hexedPublicKey = DatatypeConverter.parseHexBinary(hexString);
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(hexedPublicKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
key = kf.generatePublic(keySpecX509);
catch (Exception e)
throw new CustomException(e.getMessage());
return key;
我在这里看到了一个答案,并直接用字符串尝试了 hexParsing,但给了我错误的十六进制或类似的非法字符(我认为这是因为它有 af 字符)所以我猜对了,因为它正在等待对于十六进制而不是原始字符串。
然后在我尝试使用 Base64 之前类似的东西
rsa = Cipher.getInstance("RSA");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pkey.getBytes());
PublicKey pk = keyFactory.generatePublic(publicKeySpec);
最后,如您所见,我试图复制“Duncan Jones”的回复,但无济于事。
java.security.InvalidKeyException: invalid key format on generating RSA public key
在任何情况下,我需要的是字符串 publicKey(我剪切了 ----BEGIN---- -----END----),然后转换为 java.security.PublicKey转换为 java.security.interfaces.RSAPublicKey
非常感谢您。
【问题讨论】:
【参考方案1】:最后这成功了。
byte[] decodedBytes = Base64.getMimeDecoder().decode(keyTrimmed.getBytes());
X509EncodedKeySpec keySpecX509B = new X509EncodedKeySpec(decodedBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey generatePublic = (RSAPublicKey) keyFactory.generatePublic(keySpecX509B);
注意解码器上的区别...
包java.util.Base64.getMimeDecoder();
我通过 string.getBytes() raw,没有以前的 Base64 编码
重要的一课,从 API Provider 获取正确的文档。
来自 javadocs 的一些信息
公共类 Base64 扩展对象
此类仅包含用于获取 Base64 编码方案的编码器和解码器的静态方法。此类的实现支持 RFC 4648 和 RFC 2045 中指定的以下 Base64 类型。 •基本 使用 RFC 4648 和 RFC 2045 的表 1 中指定的“Base64 字母”进行编码和解码操作。编码器不添加任何换行(行分隔符)字符。解码器拒绝包含 base64 字母表之外的字符的数据。
•URL 和文件名安全 使用 RFC 4648 的表 2 中指定的“URL 和文件名安全 Base64 字母”进行编码和解码。编码器不添加任何换行符(行分隔符)。解码器拒绝包含 base64 字母表之外的字符的数据。
•MIME 使用 RFC 2045 的表 1 中指定的“Base64 字母”进行编码和解码操作。编码后的输出必须以每行不超过 76 个字符的形式表示,并使用回车“\r”紧跟换行“\n”作为行分隔符。没有行分隔符添加到编码输出的末尾。在解码操作中忽略所有未在 base64 字母表中找到的行分隔符或其他字符。
似乎我的密钥是这样组成的,它实际上需要 \r 和 \n。
【讨论】:
以上是关于java.security.InvalidKeyException:无效的密钥格式... PublicKey 错误的主要内容,如果未能解决你的问题,请参考以下文章