java signature.verify() 总是返回 False

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3151407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:35:12  来源:igfitidea点击:

signature.verify() Always returns False

javaencryptionprivatepublicverify

提问by Jimmy

 public static void main(String[] args) {
    try{
        String mod = "q0AwozeUj0VVkoksDQSCTj3QEgODomq4sAr02xMyIrWldZrNHhWfZAIcWt2MuAY3X6S3ZVUfOFXOrVbltRrO3F9Z6R8/jJIMv7wjkeVBFC5gncwGR0C3aV9gmF6II19jTKfF1sxb26iMEMAlMEOSnAAceNaJH91zBoaW7ZIh+qk=";
        String exp = "AQAB";
        byte[] modulusBytes = Base64.decodeBase64(mod.getBytes("UTF-8"));
        byte[] exponentBytes = Base64.decodeBase64(exp.getBytes("UTF-8"));
        String signedMessage = "3753e672cfb21e3c182ef2df51f19edeffb63432ed338a47251326ccc14aa63883e910a140cf313754ebc6425aad434e309307cc882da6cd4a4f9f40bd14a9823aca145e5ffc97cd63dbb5925c049282416bdfd7d74ddeef7055065210a841793fe315dff5a44af19c1522daafdc2f7e61ce5a2b42ebf79dfb086e6d210168dd";
        BigInteger modulus = new BigInteger(1, modulusBytes );               
        BigInteger exponent = new BigInteger(1, exponentBytes);
        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        PublicKey pubKey = fact.generatePublic(rsaPubKey);
        Signature signature = Signature.getInstance("SHA1withRSA");
        byte[] sigBytes = hexStringToByteArray(signedMessage);
        signature.initVerify(pubKey);
        System.out.println(signature.verify(sigBytes));
    }catch(Exception e){
        System.out.println("Error: " + e.toString());
    }
}
private static byte[] hexStringToByteArray(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

This code always returns false. I'm not sure where to go from here.

此代码始终返回 false。我不知道从哪里开始。

回答by Rasmus Faber

Where you sign the message you should have some code like this:

在你签署消息的地方,你应该有一些像这样的代码:

Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privKey);
signature.update(message);
byte[] signatureValue = signature.sign();

Note the byte-array named signatureValue. That is the actual signature on the data. That is what you should provide to the verify()-method. The message that is signed should be provided in a call to the update()-method. I.e.:

请注意名为signatureValue. 那是数据上的实际签名。这就是您应该提供给verify()-method 的内容。签名的消息应该在调用update()-method 时提供。IE:

Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(pubKey);
signature.update(message);
bool ok = signature.verify(signatureValue);

回答by Hyman Lloyd

I think the problem is that you are not actually giving it a message to verify.

我认为问题在于你实际上并没有给它一个消息来验证。

An RSA signature works by first hashing the message (that's the "SHA1" in "SHA1withRSA"), and then performing an trapdoor operationto it. This is an operation which is easy to do in one direction and hard in the other direction, unless you know some secret information (the RSA private key).

RSA 签名的工作原理是首先散列消息(即“SHA1withRSA”中的“SHA1”),然后对其执行陷门操作。这是一种在一个方向上很容易在另一个方向上进行的操作,除非您知道一些秘密信息(RSA 私钥)。

To verify, you first invert the mathematical transformation (because it's easy in one direction), and then compare the hash that is embedded in the signature with the hash of the message you just computed. The signature does not in itself contain the message; to verify a signature you need both the signature and the message that was signed.

为了验证,您首先反转数学变换(因为它在一个方向上很容易),然后将嵌入在签名中的散列与您刚刚计算的消息的散列进行比较。签名本身不包含消息;要验证签名,您需要签名和已签名的消息。

At an APIlevel, it looks like the Signatureclass is expecting you to call updatewith the contents of the message that this signature was for. Without this, it probably is comparing the hash with the hash of an empty string, so unless your originally signed message was also an empty string, the signature is in fact not valid.

API级别,Signature该类似乎希望您update使用此签名所针对的消息的内容进行调用。如果没有这个,它可能会将哈希与空字符串的哈希进行比较,因此除非您最初签署的消息也是空字符串,否则签名实际上是无效的。

回答by Jimmy

You were right, thanks Hyman. The below method works perfectly (even with a key created in .NET)! I hope this helps others.

你是对的,谢谢Hyman。下面的方法非常有效(即使使用在 .NET 中创建的密钥)!我希望这对其他人有帮助。

public static void main(String[] args) {
    try{
        String userID = "189711";
        String companyCode = "ILIKEPIZZA";
        String combine = userID + "." + companyCode;
        String mod = "q0AwozeUj0VVkoksDQSCTj3QEgODomq4sAr02xMyIrWldZrNHhWfZAIcWt2MuAY3X6S3ZVUfOFXOrVbltRrO3F9Z6R8/jJIMv7wjkeVBFC5gncwGR0C3aV9gmF6II19jTKfF1sxb26iMEMAlMEOSnAAceNaJH91zBoaW7ZIh+qk=";
        String exp = "AQAB";
        byte[] modulusBytes = Base64.decodeBase64(mod.getBytes("UTF-8"));
        byte[] exponentBytes = Base64.decodeBase64(exp.getBytes("UTF-8"));
        String sign = "3753e672cfb21e3c182ef2df51f19edeffb63432ed338a47251326ccc14aa63883e910a140cf313754ebc6425aad434e309307cc882da6cd4a4f9f40bd14a9823aca145e5ffc97cd63dbb5925c049282416bdfd7d74ddeef7055065210a841793fe315dff5a44af19c1522daafdc2f7e61ce5a2b42ebf79dfb086e6d210168dd";
        BigInteger modulus = new BigInteger(1, modulusBytes );               
        BigInteger exponent = new BigInteger(1, exponentBytes);
        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        PublicKey pubKey = fact.generatePublic(rsaPubKey);
        Signature signature = Signature.getInstance("SHA1withRSA");
        byte[] sigBytes = hexStringToByteArray(sign);
        signature.initVerify(pubKey);
        signature.update(combine.getBytes("UTF-8"));
        System.out.println(signature.verify(sigBytes));
    }catch(Exception e){
        System.out.println("Error: " + e.toString());
    }
}