PKCS#7的签名和验证

对于PKCS#7的签名和验证本来已经无需再谈,但考虑到默认的PKCS#7签名数据中包含原始数据,这样会带来两个问题:
1,如果原始数据量太大,则会严重影响网络传输速度。
2,如果需要对外部的原始数据进行验证,则难以进行(或者还没发现方法)。
解决第一个问题的方法有两个:
1,在签名时通过参数控制不加入原始数据。
2,对原始数据进行MD5或者SHA1算法后再将该hash值作为原始数据进行签名,因为hash值是固定长度(16或者20byte)。
解决第二个问题的方法也相应有两个:
1,验证时通过传入原始数据进行验证。
2,将原始数据进行一次MD5或者SHA1算法后与PKCS#7中的原始数据进行比较,或者将原始数据进行二次MD5或者SHA1算法后与PKCS#7中的hash值进行比较。
验证部分代码如下:
     /**
     * 验证pkcs7格式的签名数据,从外部传入原始数据
     * 
@param signedData pkcs7格式的签名数据
     * 
@param signData 原始数据
     * 
@return 验证结果
     * 
@throws Exception
     
*/

    
public   boolean  verify( byte [] signedData, byte [] signData)  throws  Exception  {
        CMSSignedData sign 
= new CMSSignedData(signedData);
        CertStore certs 
= sign.getCertificatesAndCRLs("Collection""BC");
        SignerInformationStore signers 
= sign.getSignerInfos();
        Collection c 
= signers.getSigners();
        Iterator it 
= c.iterator();
        
boolean  bresult = true;
        
//当有多个签名者信息时需要进行全部验证
        while (it.hasNext()) {
            SignerInformation signer 
= (SignerInformation) it.next();
            Collection certCollection 
= certs.getCertificates(signer.getSID());
            Iterator certIt 
= certCollection.iterator();
            X509Certificate cert 
= (X509Certificate) certIt.next();//证书链????
            byte[] data = signer.getSignature();
            logger.debug(
"签名后数据:" + data.length);
            
for (int i = 0; i < data.length; i++{
                System.out.print(
" " + data[i]);
            }

            System.out.println();
            logger.debug(
"签名后数据Base64: " + new String(Base64.encode(data),"utf8"));
            
if (signer.verify(cert.getPublicKey(), "BC")) {//验证过程???
                logger.info(" pkcs7 verifed success!");
                
//对原始数据计算两次MD5后与签名数据进行比较
                MessageDigest md = MessageDigest.getInstance("MD5","BC");
                md.update(signData);
//                System.out.println("signData=" + new String(signData,"utf8"));
                byte[] digestedData1 = md.digest();
//                md.update(digestedData1);
//                byte[] digestedData2 = md.digest();
                
//签名原始数据,即原始内容的一次MD5值
                byte[] content = (byte[])sign.getSignedContent().getContent();
//                System.out.println("content=" + new String(content,"utf8"));                
//                bresult = CommonUtil.isEqual(digestedData2,signer.getContentDigest());
                bresult = CommonUtil.isEqual(digestedData1,content,digestedData1.length);            
                CommonUtil.displayData(content);
                CommonUtil.displayData(digestedData1);
//                  CommonUtil.displayData(signer.getContentDigest());
            }
else{
                bresult 
= false;
            }

        }

        
return bresult;
    }
注意:
在MS的cryptoapi中得到的PKCS#7的原始数据即原始数据的MD5 hash值是17byte的,即多出了一个NULL byte,所以只需要比较前16个即可。

你可能感兴趣的:(安全技术)