/**
* 使用公钥验签
*
* @param data
* @param sign
* @param publicKeyStr
* @param signMode
* @return boolean验签结果
*/
public static boolean verify(String data, String sign, String publicKeyStr, SignMode signMode) {
try {
PublicKey pubKey = getPublicKey(publicKeyStr);
Signature signature = Signature.getInstance(signMode.getMode());
signature.initVerify(pubKey);
signature.update(data.getBytes());
return signature.verify(Base64Utils.decodeToByte(sign));
} catch (Exception e) {
log.error("验签字符串时遇到异常", e);
}
return false;
}
这个SignMode signMode 是个哈希算法:SignMode.SHA1 ,问题是,既有公钥,又有数据,还有哈希,底层的 signature.verify 是怎么操作的呢?
答:代码中,SignMode
通过 signMode.getMode()
返回的是签名算法的名称,例如 SHA1WithRSA
。这个算法名称是由 Signature.getInstance()
使用的,该方法会根据提供的算法名称获取一个 Signature
对象。
在这里,Signature.getInstance(signMode.getMode())
创建了一个特定算法的 Signature
对象,用于使用给定的公钥进行验证。
当 signature.update(data.getBytes())
被调用时,该方法将提供的数据更新到 Signature 对象中,实际上是对这些数据进行哈希操作,因为签名算法通常不直接对原始数据进行签名,而是对其哈希值进行签名,以提高安全性和效率。
最后,signature.verify(Base64Utils.decodeToByte(sign))
执行验签操作,其中包括了使用提供的公钥验证已更新的数据。这个方法会返回一个布尔值,表示验签的结果。
在底层,Signature
类使用了 Java Security Provider 中相应算法的实现。例如,对于 SHA1WithRSA
,它会使用 RSA 算法以及 SHA-1 哈希算法的实现来完成签名验证的过程。这个过程涉及到使用公钥解密签名并比较哈希值等操作,确保签名的合法性和数据的完整性。
那么Signature 对象,用于使用给定的公钥进行验证。是什么验证的,就是 signature.verify的底层是怎么实现的?
Signature
对象的主要目的是提供数字签名和验证数字签名的功能。在这个上下文中,验证数字签名的过程涉及以下步骤:
-
初始化验证模式: 使用
signature.initVerify(pubKey)
初始化Signature
对象为验证模式,并与给定的公钥pubKey
相关联。 -
更新验证数据: 使用
signature.update(data.getBytes())
更新Signature
对象,将待验证的原始数据添加到对象中。通常,签名算法不直接对原始数据进行签名,而是对其进行哈希操作。这确保了对大量数据的验证更高效,同时保护了数据的完整性。 -
执行验证: 使用
signature.verify(Base64Utils.decodeToByte(sign))
方法,其中包括了将 Base64 编码的签名解码为字节数组的操作。验证的底层实现通常涉及使用公钥对签名进行解密,并与已哈希的原始数据进行比较。(这个是关键)
具体的验证过程取决于使用的签名算法。以 RSA 算法为例,验证过程包括使用公钥对签名进行解密,并比较解密后的值与原始数据的哈希值。如果两者匹配,则验证成功;否则,验证失败。
在底层,Signature
类通过 Java Security Provider 提供的相关算法实现验证过程。具体的实现会涉及到复杂的数学运算,例如使用公钥对签名进行解密,生成哈希值并进行比较等。这些底层细节由 Java 运行时环境的安全提供者负责实现。
上验签代码:
/**
* 验证签名的引擎方法,用于实际验证传入的签名数据。
*
* @param var1 要验证的签名数据的字节数组
* @return 如果验证成功,返回 true;否则返回 false
* @throws SignatureException 当签名验证过程中出现异常时抛出
*/
protected boolean engineVerify(byte[] var1) throws SignatureException {
// 检查传入的签名数据长度是否与公钥的字节长度相匹配
if (var1.length != RSACore.getByteLength(this.publicKey)) {
throw new SignatureException("Signature length not correct: got " + var1.length +
" but was expecting " + RSACore.getByteLength(this.publicKey));
} else {
// 获取消息摘要的字节数组
byte[] var2 = this.getDigestValue();
try {
// 使用 RSA 算法对传入的签名数据进行解密
byte[] var3 = RSACore.rsa(var1, this.publicKey);
// 使用填充方案对解密后的数据进行去填充操作
byte[] var4 = this.padding.unpad(var3);
// 将解除填充后的数据进行签名编码解析,得到实际的签名字节数组
byte[] var5 = decodeSignature(this.digestOID, var4);
// 比较消息摘要和解析得到的签名是否相等
return Arrays.equals(var2, var5);
} catch (BadPaddingException var6) {
// 解密填充时出现异常,验证失败
return false;
} catch (IOException var7) {
// 解码签名时出现异常,抛出 SignatureException
throw new SignatureException("Signature encoding error", var7);
}
}
}