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

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

我正在尝试在 Java 中获取用于 jwt 令牌验证的 RSA 公钥,但我的尝试因以下异常而失败: 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 编码 as required by Java crypto. It actually is the base64 encoding of a PEM file which is itself structured and encoded. Moreover this PEM file is labelled as containing 'RSA PUBLIC KEY' which would be the 'raw' PKCS1 form and wrong for Java, but fortunately whatever created this PEM file was defective and the body of the PEM file actually is an X.509 SubjectPublicKeyInfo which should have PEM label 'PUBLIC KEY' per RFC7468 #13。 (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() );

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