Signature.verify 抛出异常签名长度不正确:得到 248 但预期为 256

Signature.verify is throwing an exception Signature length not correct: got 248 but was expecting 256

java 版本 1.8

import java.io.ByteArrayInputStream;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;

/**
 *
 * @author user
 */
public class Test {
    public static void main(String[] args) throws Exception {
        String publicKeyB64 = "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";
        String data = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjU2MzU4ODUyMzRCOTI1MkRERTAwNTc2NkQ5RDlGMjc2NTY1RjYzRTIiLCJ4NXQiOiJWaldJVWpTNUpTM2VBRmRtMmRueWRsWmZZLUkiLCJ0eXAiOiJKV1QifQ.eyJhcHBjdHhzZW5kZXIiOiIwMDAwMDAwMi0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDBAOGU5MDAzNTgtOWJjMC00YmQyLTlmMzQtNDU5OTY3ODk5MDVkIiwiaXNicm93c2VyaG9zdGVkYXBwIjoiVHJ1ZSIsImFwcGN0eCI6IntcIm1zZXhjaHVpZFwiOlwiYTVkYWY0YzItZTdiYS00NDE5LTljYmUtYjQ4NWE2ZTNiNGQ1XCIsXCJ2ZXJzaW9uXCI6XCJFeElkVG9rLlYxXCIsXCJhbXVybFwiOlwiaHR0cHM6Ly9vdXRsb29rLm9mZmljZTM2NS5jb206NDQzL2F1dG9kaXNjb3Zlci9tZXRhZGF0YS9qc29uLzFcIn0iLCJuYmYiOjE1OTMwMjA4MzAsImV4cCI6MTU5MzA0OTYzMCwiaXNzIjoiMDAwMDAwMDItMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQDhlOTAwMzU4LTliYzAtNGJkMi05ZjM0LTQ1OTk2Nzg5OTA1ZCIsImF1ZCI6Imh0dHBzOi8vbWFpbGFwcC5mb3JjZS5jb20vY2xpZW50cy9tYWlsYXBwL2FjdGl2YXRpb24ifQ";
        String signature = "oifeWN-wnci-WCS6XPLC-74ynG9rmXdePVfMMxX9WsAXOK5tvRpNmNsPqu9bllufAIUhgpNIYtHEB39-_o2pzpugyfkohLJfPovEQa-1X8zzudjxY3j5tRyISzVuwL9l6zROhJIdOvXsoarzcuQ38j492H7ol7auTvfDI4Mwu4Ri_e2rbiFYWsYU36Htj39DEiOvpQ12z7Onu-Yrj1inICTDtJsOdv9HWrO2nZ5IwRdl45Tt0Ks3ZrBeStleNVCXQdU_xKvYtbO02fUfgkFrIzEUZYHgXbK8sE2m0phmeU7Wp-KdW4jVVl9yLQtB98_FJJfw9tI4Oys2NBBY2sLyhQ";
        RSAPublicKey secret = null;
        try {
            secret = null;
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate cert = cf.generateCertificate(new ByteArrayInputStream(Base64.getMimeDecoder().decode(publicKeyB64)));
            secret = (RSAPublicKey) cert.getPublicKey();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        KeyFactory kf = KeyFactory.getInstance("RSA");
        Signature privateSignature = Signature.getInstance("SHA256withRSA");
        privateSignature.initVerify(secret);
        privateSignature.update(data.getBytes("UTF-8"));
        System.out.println(privateSignature.verify(Base64.getMimeDecoder().decode(signature.getBytes())));
    }
}

得到以下异常:

Exception in thread "main" java.security.SignatureException: Signature length not correct: got 248 but was expecting 256
    at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:211)
    at java.security.Signature$Delegate.engineVerify(Signature.java:1394)
    at java.security.Signature.verify(Signature.java:771)
    at com.ciphercloud.plugin.salesforce.rewriters.Test.main(Test.java:35)

还有一个问题: 早些时候,我使用了 Base64.getDecoder().decode(signature.getBytes())) 但它抛出错误,所以我改为 Base64.getMimeDecoder().decode(signature.getBytes()))。我可以知道为什么 Base64.getDecoder().decode() 失败了吗?

这里的问题是解码错误。 Mime (Base64.getMimeDecoder().decode()) 和 Base64 (Base64.getDecoder().decode()) 都不正确。

JWT 使用 Base64url encoding, not Base64。不同之处在于-_字符,它们在base64url中用于替换Base64标准的+/。此外,在 Base64url 编码中省略了填充 =

解码 JWT header、负载和签名的正确方法是使用 Base64url decoder:

Base64.getUrlDecoder().withoutPadding().decode()