我正在尝试使用私钥对加密邮件进行签名,并使用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。
答案 0 :(得分:2)
签名验证失败,因为您在验证方法中使用了不同的public key
。
使用public key
验证与private key
方法中使用的rsaSign()
一致的签名。
希望这会对你有所帮助。请注意,此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));
}
答案 1 :(得分:0)
您应该首先尝试使用自己生成的密钥对在本地测试这些内容。如果失败了,那么你的代码是错误的 - 它是一个非常简单的Java Signature
包装器,因此根本不可能。
您已经使用了签名算法的完整规范,因此提供程序默认值不是问题。
然后在签名生成/验证之前将其打印在Hex或Base64中,检查双方数据的正确性。如果失败,您就会遇到I / O或编码/解码错误。编码/解码错误&字符串处理约占密码学相关问题总数的30%!
最后,您可以获取并比较私钥和公钥的模数。如果模块不匹配,那么您使用不同密钥对的私钥和公钥,签名验证当然总会失败。