2015-05-20 63 views
2

我试图用私钥签名加密的消息并使用Java验证它。这是我第一次使用加密和签名,所以我不确定它应该如何工作,我有点卡在这里。验证总是返回false。无法验证Android上的rsa签名

在这里,我对消息进行签名:

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。

+0

对我来说,这看起来很像一个图书馆相关的问题,如Ilmari所提到的那样,在SO上会好很多。您应该强烈考虑迁移您的问题,因为它很可能会在SO上得到解答。 – SEJPM

+0

我没有发布它,所以我没有得到任何答案。我会考虑让它自成体系并再次尝试。谢谢! – user3685322

+0

@ user3685322:确保将输入值发布到任何构建signModulus,signExponent,signPublicExponent;问题可能在那里。 – fgrieu

回答

2

签名验证失败,因为您在验证方法中使用了不同的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)); 
    } 
+0

编号RSAPublicKeySpec有参数,问题指出它们已经在C#中生成。 – fgrieu

+1

我认为OP打破了密钥对的一致性。 @fgrieu –

+0

我很喜欢这个新的介绍;我有[版本1的答案](http://crypto.stackexchange.com/revisions/25799/1)问题,因为我没有看到问题中的代码是“_在验证方法中生成新的公钥_ “ – fgrieu

0

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

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

然后在签名生成/验证之前通过在Hex或Base64中打印出来来检查数据的正确性。如果失败了,你会遇到I/O或编码/解码错误。编码/解码错误&字符串处理占加密相关问题总数的约30%!

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