【问题标题】:Cannot verify rsa signature on Android无法在 Android 上验证 rsa 签名
【发布时间】:2015-05-20 15:33:24
【问题描述】:

我正在尝试使用私钥对加密消息进行签名并在 Java 中对其进行验证。这是我第一次使用加密和签名,所以我不确定它应该如何工作,我有点卡在这里。验证总是返回 false。

我在这里签名:

public byte[] rsaSign (byte[] data) {

byte[] cipherData = null;

try {

    RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(signModulus, signExponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey privKey = fact.generatePrivate(keySpec);

    Signature s = Signature.getInstance("SHA1withRSA");
    s.initSign(privKey);

    s.update(data);

    return s.sign();
}

return cipherData;
}

我在这里尝试验证签名:

public boolean rsaVerify (byte[] data, byte[] signature) {

boolean success = false;

try {

    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(signModulus, signPublicExponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(keySpec);

    Signature s = Signature.getInstance("SHA1withRSA");
    s.initVerify(pubKey);

    s.update(data);

    success = s.verify(signature);

    return success;

} 

return false;
}

任何人都可以看到问题吗?密钥在 C# 中生成并在 java 中转换为 BigIntegers。

【问题讨论】:

  • 对我来说,这显然看起来像一个与图书馆相关的问题,而且正如 Ilmari 所提到的,在 SO 上会好很多。您应该强烈考虑迁移您的问题,因为它很可能会在 SO 上得到回答。
  • 我确实在 SO 上发布了它,但我没有得到任何答案。我会考虑让它自成一体并再试一次。谢谢!
  • @user3685322:确保将输入值发布到任何构建signModulus、signExponent、signPublicExponent;问题可能就在那里。

标签: java cryptography rsa digital-signature


【解决方案1】:

签名验证失败,因为您在验证方法中使用了不同的public key。 使用public key验证签名是否与rsaSign()方法中使用的private key一致。

希望这会对您有所帮助。注意,这个public key与签名生成方法中使用的private key是一致的:

/**
     * This method will sign message with RSA 2048 key
     * @return Void
     */
    public void rsaSign (String message) throws Exception {
        //key generation
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        keyGen.initialize(2048, random);

        KeyPair keyPair = keyGen.generateKeyPair();
        PrivateKey priv = keyPair.getPrivate();
        PublicKey pub   = keyPair.getPublic();

        System.out.println("RSAPub key Mod for Sign/Verify  : " + Helper.toHex(((RSAPublicKey)pub).getModulus().toByteArray()));
        System.out.println("RSAPub key Exp for Sign/Verify  : " + Helper.toHex(((RSAPublicKey)pub).getPublicExponent().toByteArray()));

        //sign
        Signature dsa   = Signature.getInstance(signALG);
        dsa.initSign(priv);

        dsa.update(Helper.toByte(message));
        byte[] realSig = dsa.sign();
        System.out.println("RSA Sign-Data   : " + Helper.toHex(realSig));
    }


/**
     * This method verify signature with RSA public key
     * @param message The plain message
     * @param rsaMOD RSA Public key Modulus in string
     * @param rsaEXP RSA Public key Exponent in string
     * @param rsaSignData Signature which will be verified
     * @return true if verifications success, false otherwise
     */
    public boolean rsaVerify(String message, String rsaMOD, String rsaEXP, String rsaSignData) throws Exception {
        BigInteger modBigInteger = new BigInteger(Helper.toByte(rsaMOD));
        BigInteger exBigInteger = new BigInteger(Helper.toByte(rsaEXP));

        RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = factory.generatePublic(spec);

        Signature signature = Signature.getInstance(signALG);
        signature.initVerify(publicKey);
        signature.update(Helper.toByte(message));

        return signature.verify(Helper.toByte(rsaSignData));
    }

【讨论】:

  • 没有。 RSAPublicKeySpec 有参数,问题说明是用 C# 生成的。
  • 我认为 OP 破坏了密钥对的一致性。 @fgrieu
  • 我对新介绍没意见;我对version 1 of the answer 有疑问,因为我看不到问题中的代码是“在验证方法中生成新的公钥的迹象
  • 你的意思是破坏了密钥对的一致性?我在 c# 中生成了密钥对并将它们传输到我的 android 应用程序中,主要用于测试。公钥最终将在服务器端使用。
  • 打破一致性意味着,您使用私钥生成签名,但不使用相应的公钥来验证该签名。你试试我在答案中发布的代码吗?
【解决方案2】:

您应该先尝试使用自己生成的密钥对在本地测试这些东西。如果失败了,你的代码就是错误的——它是 Java Signature 的一个非常简单的包装器,所以这不太可能。

您已经使用了完整的签名算法规范,因此提供者默认值在这里不是问题。

然后在签名生成/验证之前,通过以 Hex 或 Base64 打印出来来检查双方数据的正确性。如果失败,则说明 I/O 或编码/解码错误。编码/解码错误和字符串处理约占密码学相关问题总数的 30%!

最后,您可以获得并比较私钥和公钥的模数。如果模数不匹配,那么您使用的是不同密钥对的私钥和公钥,签名验证当然总是会失败。

【讨论】:

    猜你喜欢
    • 2021-01-12
    • 2017-07-30
    • 2016-01-15
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-11-24
    • 2016-09-26
    相关资源
    最近更新 更多