You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使用PublicKey验证RSA签名失败问题求助

RSA签名验证失败的问题分析与修复

核心问题:私钥生成逻辑错误

你的代码中generatePrivateKey方法存在致命错误:使用公钥指数e初始化RSAPrivateKeySpec,但该规范要求传入的是私钥指数d,而非公钥指数。这导致生成的私钥完全无效,用它签名的消息自然无法被正确公钥验证。

RSAPrivateKeySpec的构造参数定义为:RSAPrivateKeySpec(BigInteger modulus, BigInteger privateExponent),你错误地将公钥指数e当作私钥指数传入,直接导致签名逻辑失效。

修复方案

方案1:使用合法私钥指数d手动生成私钥

如果你已经拥有对应公钥的私钥指数d,修改generatePrivateKey方法,将参数替换为私钥指数d:

static PrivateKey generatePrivateKey(String modulus, String privateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
    BigInteger n = new BigInteger(1, Base64.getUrlDecoder().decode(modulus));
    BigInteger d = new BigInteger(1, Base64.getUrlDecoder().decode(privateExponent));

    return KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(n, d));
}

同时在main方法中传入对应的d值(你原代码仅提供了n和e,缺失私钥指数d,需要补充)。

方案2:用KeyPairGenerator自动生成密钥对(推荐)

手动构造密钥对容易出错,实际开发中推荐使用Java提供的KeyPairGenerator生成合法RSA密钥对,它会自动处理所有密钥参数:

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;

public class JWT2 {

    public static void main(String[] args) throws Exception {
        String plainTextMessage = "A Secret!";
        
        // 生成2048位RSA密钥对(安全强度达标)
        KeyPair keyPair = generateRSAKeyPair();
        
        // 签名
        byte[] signedMessageBytes = signMessage(plainTextMessage, keyPair.getPrivate());
        
        // 验证
        boolean isMsgValid = verifySignedMessage(plainTextMessage.getBytes(StandardCharsets.UTF_8), signedMessageBytes, keyPair.getPublic());
        System.out.println("isMsgValid = " + isMsgValid); // 输出true
        
        // 可选:导出密钥参数用于存储
        RSAPublicKeySpec pubSpec = KeyFactory.getInstance("RSA").getKeySpec(keyPair.getPublic(), RSAPublicKeySpec.class);
        RSAPrivateKeySpec privSpec = KeyFactory.getInstance("RSA").getKeySpec(keyPair.getPrivate(), RSAPrivateKeySpec.class);
        String n = Base64.getUrlEncoder().encodeToString(pubSpec.getModulus().toByteArray());
        String e = Base64.getUrlEncoder().encodeToString(pubSpec.getPublicExponent().toByteArray());
        String d = Base64.getUrlEncoder().encodeToString(privSpec.getPrivateExponent().toByteArray());
        System.out.println("n: " + n);
        System.out.println("e: " + e);
        System.out.println("d: " + d);
    }

    // 生成RSA密钥对
    static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    static boolean verifySignedMessage(byte[] plainTextMessagebytes, byte[] signedMessageBytes, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(plainTextMessagebytes);
        return signature.verify(signedMessageBytes);
    }

    static byte[] signMessage(String plainTextMessage, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(plainTextMessage.getBytes(StandardCharsets.UTF_8));
        return signature.sign();
    }

    // 从导出的参数恢复公钥
    static PublicKey generatePublicKey(String modulus, String publicExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
        BigInteger n = new BigInteger(1, Base64.getUrlDecoder().decode(modulus));
        BigInteger e = new BigInteger(1, Base64.getUrlDecoder().decode(publicExponent));

        return KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(n, e));
    }

    // 从导出的参数恢复私钥
    static PrivateKey generatePrivateKey(String modulus, String privateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
        BigInteger n = new BigInteger(1, Base64.getUrlDecoder().decode(modulus));
        BigInteger d = new BigInteger(1, Base64.getUrlDecoder().decode(privateExponent));

        return KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(n, d));
    }
}

额外说明

  • 你代码中使用的SHA256withRSA签名算法是安全合规的,这部分逻辑没有问题。
  • 手动构造密钥对时,必须同时拥有模数n、公钥指数e、私钥指数d三个参数,缺一不可。

内容的提问来源于stack exchange,提问作者Kuldeep Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:35:16