java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:无效密钥格式

java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:无效密钥格式,java,rsa,public-key,Java,Rsa,Public Key,我正在尝试在Java中获取用于jwt令牌验证的RSA PublicKey,但尝试失败,出现以下异常: java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:密钥格式无效 我的代码: String publicKeyString = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRk

我正在尝试在Java中获取用于jwt令牌验证的RSA PublicKey,但尝试失败,出现以下异常: java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:密钥格式无效

我的代码:

    String publicKeyString = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMk5pKytLeUpVaDhLYklLVU51OG0KUk5lRCtrU2tXZEh6MjBvSFZYK0g0cVd4WHlJSTk0MVdJUFU2WFpPc3lMeE9qZU1hb0ZRanJ6bDFwYnZQekUyRQpwMmhlK1BnQ1JteDNqOFlMVVd3dGpuQTVwTTFLWDhpNG5vTUw4RmlWY1U2NkE5RjRkZmRQR2MzY0tQQ2ZPbnorCmtBbW5qRllzajYzRCsrTThYSDRWaS9Vc0V3T1lzU05FR2RncUd2OTlTNHpVRzFzd2FqZ1NnODhvbTVaOC9Ja1AKY01LT3cvWkpvVHNDN3l1VlJnTC9xa3EwaDVkM2lXVXNNdXl1K0xoblRhTko4bW9WQmpJT2lQQkR0cEQyN1lzNgpCSGs1dEdBa3ZHZDg0N3c4SjVEeTFzYWlQS0pxelltcUx5akg3b3VlcERFczdEZ2UxZUlJeno5a1RnSkhKZHVzCnd3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";
    PublicKey publicKey = getPublicKey(Base64.getDecoder().decode(publicKeyString), "RSA");
和getPublicKey函数:

private static PublicKey getPublicKey(byte[] keyBytes, String algorithm) {
    PublicKey publicKey = null;
    try {
        KeyFactory kf = KeyFactory.getInstance(algorithm);
        EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        System.out.println(keySpec.getFormat());

        publicKey = kf.generatePublic(keySpec);
    } catch (NoSuchAlgorithmException e) {
        System.out.println("Could not reconstruct the public key, the given algorithm could not be found.");
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
        System.out.println("Could not reconstruct the public key");
    }

    return publicKey;
}

我知道有很多类似的问题处理同一个异常被抛出,我已经阅读了很多,并尝试了解决方案,但没有任何效果。非常感谢您的帮助。

您的数据不是实际X.509公钥块(SubjectPublicKeyInfo)的base64编码。它实际上是PEM文件的base64编码,PEM文件本身是结构化和编码的。此外,此PEM文件被标记为包含“RSA公钥”,这可能是“原始”PKCS1格式,对Java来说是错误的,但幸运的是,创建此PEM文件的任何内容都有缺陷,PEM文件的主体实际上是一个X.509 SubjectPublicKeyInfo,它应该具有PEM标签“公钥”。(RFC5280是X.509的配置文件。)

因此,您需要将字符串解码为PEM,然后解析PEM以获得X.509:

        String orig = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMk5pKytLeUpVaDhLYklLVU51OG0KUk5lRCtrU2tXZEh6MjBvSFZYK0g0cVd4WHlJSTk0MVdJUFU2WFpPc3lMeE9qZU1hb0ZRanJ6bDFwYnZQekUyRQpwMmhlK1BnQ1JteDNqOFlMVVd3dGpuQTVwTTFLWDhpNG5vTUw4RmlWY1U2NkE5RjRkZmRQR2MzY0tQQ2ZPbnorCmtBbW5qRllzajYzRCsrTThYSDRWaS9Vc0V3T1lzU05FR2RncUd2OTlTNHpVRzFzd2FqZ1NnODhvbTVaOC9Ja1AKY01LT3cvWkpvVHNDN3l1VlJnTC9xa3EwaDVkM2lXVXNNdXl1K0xoblRhTko4bW9WQmpJT2lQQkR0cEQyN1lzNgpCSGs1dEdBa3ZHZDg0N3c4SjVEeTFzYWlQS0pxelltcUx5akg3b3VlcERFczdEZ2UxZUlJeno5a1RnSkhKZHVzCnd3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";

        String pem = new String(Base64.getDecoder().decode(orig)); // default cs okay for PEM
        String[] lines = pem.split("\n"); lines[0] = lines[lines.length-1] = ""; String body = String.join("", lines);
        // in general split on "\r?\n" (or delete "\r" and split on "\n")
        //or instead:
        //String body = pem.replaceAll("-----(BEGIN|END) RSA PUBLIC KEY-----\n","").replaceAll("\n", ""); // or "\r?\n"
        
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey key = kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(body)));
        // for test only:
        System.out.println ( ((java.security.interfaces.RSAPublicKey)key).getModulus() );

注意:您的特定数据的PEM使用单字符(NL aka
\n
)换行符,但PEM通常可以使用NL或CRLF(
\r\n
);请参阅我的评论。

您的数据不是实际X.509公钥块(SubjectPublicKeyInfo)的base64编码。它实际上是PEM文件的base64编码,PEM文件本身是结构化和编码的。此外,此PEM文件被标记为包含“RSA公钥”,这可能是“原始”PKCS1格式,对Java来说是错误的,但幸运的是,创建此PEM文件的任何内容都有缺陷,PEM文件的主体实际上是一个X.509 SubjectPublicKeyInfo,它应该具有PEM标签“公钥”。(RFC5280是X.509的配置文件。)

因此,您需要将字符串解码为PEM,然后解析PEM以获得X.509:

        String orig = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMk5pKytLeUpVaDhLYklLVU51OG0KUk5lRCtrU2tXZEh6MjBvSFZYK0g0cVd4WHlJSTk0MVdJUFU2WFpPc3lMeE9qZU1hb0ZRanJ6bDFwYnZQekUyRQpwMmhlK1BnQ1JteDNqOFlMVVd3dGpuQTVwTTFLWDhpNG5vTUw4RmlWY1U2NkE5RjRkZmRQR2MzY0tQQ2ZPbnorCmtBbW5qRllzajYzRCsrTThYSDRWaS9Vc0V3T1lzU05FR2RncUd2OTlTNHpVRzFzd2FqZ1NnODhvbTVaOC9Ja1AKY01LT3cvWkpvVHNDN3l1VlJnTC9xa3EwaDVkM2lXVXNNdXl1K0xoblRhTko4bW9WQmpJT2lQQkR0cEQyN1lzNgpCSGs1dEdBa3ZHZDg0N3c4SjVEeTFzYWlQS0pxelltcUx5akg3b3VlcERFczdEZ2UxZUlJeno5a1RnSkhKZHVzCnd3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";

        String pem = new String(Base64.getDecoder().decode(orig)); // default cs okay for PEM
        String[] lines = pem.split("\n"); lines[0] = lines[lines.length-1] = ""; String body = String.join("", lines);
        // in general split on "\r?\n" (or delete "\r" and split on "\n")
        //or instead:
        //String body = pem.replaceAll("-----(BEGIN|END) RSA PUBLIC KEY-----\n","").replaceAll("\n", ""); // or "\r?\n"
        
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey key = kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(body)));
        // for test only:
        System.out.println ( ((java.security.interfaces.RSAPublicKey)key).getModulus() );
注意:您的特定数据的PEM使用单字符(NL aka
\n
)换行符,但PEM通常可以使用NL或CRLF(
\r\n
);见我的评论