简体   繁体   English

无法在Android上验证rsa签名

[英]Cannot verify rsa signature on Android

I'm trying to sign an encrypted message with a private key and verify it in Java. 我正在尝试使用私钥对加密邮件进行签名,并使用Java验证它。 This is my first time working with encryption and signatures so I'm not sure how it is supposed to work and I'm kind of stuck here. 这是我第一次使用加密和签名,所以我不确定它应该如何工作,我有点被困在这里。 The verification always returns false. 验证始终返回false。

Here I sign the message: 在这里我签署消息:

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;
}

And here I try to verify the signature: 在这里,我尝试验证签名:

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;
}

Can anyone see a problem? 任何人都可以看到问题吗? The keys are generated in C# and converted to BigIntegers in java. 密钥在C#中生成,并在java中转换为BigIntegers。

Signature verification is failed because you are using a different public key in the verification method. 签名验证失败,因为您在验证方法中使用了不同的public key Use the public key to verify the signature which is consistent with the private key that is used into rsaSign() method. 使用public key验证签名,该签名与用于rsaSign()方法的private key一致。

Hope this will help you. 希望这会帮助你。 Note that, this public key is consistent with the private key which is used in Signature Generation method : 请注意,此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));
    }

You should try and test these things locally first, with your own generated key pair. 您应该首先尝试使用自己生成的密钥对在本地测试这些内容。 If that fails your code is wrong - it's a very simple wrapper around Java Signature so that's not at all that likely. 如果失败了你的代码是错误的 - 它是一个非常简单的Java Signature包装器,所以根本不可能。

You already used a complete specification of the signature algorithm, so provider defaults are not an issue here. 您已经使用了签名算法的完整规范,因此提供程序默认值不是问题。

Then check the correctness of the data on both sides by printing it out in Hex or Base64 right before signature generation/verification. 然后在签名生成/验证之前,通过在Hex或Base64中打印出来,检查两侧数据的正确性。 If that fails you've got an I/O or encoding/decoding error. 如果失败,则会出现I / O或编码/解码错误。 Encoding/decoding errors & string handling make up about 30% of the total of cryptography related questions! 编码/解码错误和字符串处理占加密相关问题总数的约30%!

Finally you could obtain and compare the modulus of the private and public key. 最后,您可以获取并比较私钥和公钥的模数。 If the moduli don't match then you're using a private and public key of a different key pair, and signature verification will of course always fail. 如果模数不匹配,那么您正在使用不同密钥对的私钥和公钥,签名验证当然总是会失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM