PKCS#7格式数字签名验证
名词解释
数字签名:在ISO7498-2标准中定义为:"附加在数据单元上的一些数据,或是对数据单元所作的密码变换,这种数据和变换允许数据单元的接收者用以确认数据单元来源和数据单元的完整性,并保护数据,防止被人(例如接收者)进行伪造"。
PKCS#7:也叫做加密消息的语法标准,由RSA安全体系在公钥加密系统中交换数字证书产生的一种加密标准。PKCS#7描述数字证书的语法和其他加密消息——尤其是,数据加密和数字签名的方法,也包含了算法。当使用PKCS#7进行数字签名时,结果包含签名证书(一列相关证书撤回列表)和已证明路径上任何其他证书。如果使用PKCS#7加密数据,通常包含发行者的参考消息和证书的序列号,它与用于解密已加密数据的公共密钥相关。
PKCS#7标准定义了多种内容类型,包括下面这些:
·数据:字节或8位元组串。
·签名设计:随加密数据摘要一起的数据。一个信息摘要是一个哈希算法的结果(术语摘要和散列是相同定义的)。使用信息摘要保证原始消息在传输过程中没有被篡改,并确认发送者的身份。
·封装数据:密文加上公钥能够解密数据。用这种方法保持消息内容对所有人保密,都是信任收件人。
·签名和加密数据:有公钥的加密内容和双重加密的消息摘要。
·摘要数据:数据加上消息摘要。
·单独的加密数据:在这种情况,加密数据的公钥必须通过其他机制传输。
实现方法
1、 使用java自带的安全包。由于jdk中没有对PKCS#7格式签名数据的处理。在做验证时需要三个参数:原文;签名数据和签名者证书/签名者公钥,都是BASE64编码。代码如下:
public boolean SignedData_Verify(byte[] signData,byte[] signedData,byte[] cert) {
boolean verifyRet = true;
try {
// 创建Factory对象
CertificateFactory oCf = CertificateFactory.getInstance("X.509");
// 创建X509证书对象
InputStream ois = new ByteArrayInputStream(cert);
X509Certificate oCert = (X509Certificate)oCf.generateCertificate(ois);
// 创建签名对象
Signature oSign = Signature.getInstance("SHA1withRSA");
// 初始化签名对象
oSign.initVerify(oCert);
// 传入签名原文
oSign.update(signData);
// 验证数字签名
verifyRet = oSign.verify(signedData);
}
catch (Exception e) {
verifyRet = false;
e.printStackTrace();
System.out.println("验证数字签名失败");
}
return verifyRet;
}
2、 通过bouncycastle的CMSSignedData可以实现pkcs#7格式签名数据的验证,利用CMSSignedData生成pkcs#7格式签名数据。由于pkcs#7里面包含了原文和证书信息,所以参数只需要签名值即可。代码如下:
public boolean SignedData_Verify(byte[] SignedData) {
boolean verifyRet = true;
try {
// 新建PKCS#7签名数据处理对象
CMSSignedData sign = new CMSSignedData(signedData);
// 添加BouncyCastle作为安全提供
Security.addProvider(new
org.bouncycastle.jce.provider.BouncyCastleProvider());
// 获得证书信息
CertStore certs = sign.getCertificatesAndCRLs("Collection", "BC");
// 获得签名者信息
SignerInformationStore signers = sign.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
// 当有多个签名者信息时需要全部验证
while (it.hasNext()) {
SignerInformation signer = (SignerInformation) it.next();
// 证书链
Collection certCollection = certs.getCertificates(signer
.getSID());
Iterator certIt = certCollection.iterator();
X509Certificate cert = (X509Certificate) certIt.next();
// 验证数字签名
if (signer.verify(cert.getPublicKey(), "BC")) {
verifyRet = true;
} else {
verifyRet = false;
}
}
}
catch (Exception e) {
verifyRet = false;
e.printStackTrace();
System.out.println("验证数字签名失败");
}
return verifyRet;
}