用java签名和用cryptoapi签名生成的数据的相互验证

来源:互联网 发布:cfd软件有哪些 编辑:程序博客网 时间:2024/06/05 19:31
 cryptoapi的CryptSignHash方法签名生成的数据是pkcs#7格式的,java中通过bouncycastle的CMSSignedData可以实现pkcs#7格式签名数据的验证,利用CMSSignedData签名生成pkcs#7格式数据。代码如下:
    /** 
     * 验证pkcs7格式的签名数据
     * 
@param signedData pkcs7格式的签名数据
     * 
@return 验证结果
     * 
@throws Exception
     
*/

    
public boolean verify(byte[] signedData) 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!");
            }
else...{
                bresult 
= false;
            }

        }

        
return bresult;
    }


    
/**
     * 签名生成pkcs7结构数据
     * 
@param signText 原始数据
     * 
@param keystore 密钥库
     * 
@param keyalias 密钥别名
     * 
@param password 密钥库密码
     * 
@return 签名后数据
     * 
@throws Exception
     
*/

    
public byte[] sign(byte[] signText,KeyStore keystore,String keyalias,char[] password) throws Exception {
        CMSSignedDataStreamGenerator gen 
= new CMSSignedDataStreamGenerator();
        Enumeration en 
= keystore.aliases();
        
//遍历密钥库的密钥别名
        while(en.hasMoreElements()){
            String alias 
= (String)en.nextElement();
            logger.debug(
"keyalias:" + alias);
            
if(!alias.equalsIgnoreCase(keyalias))continue;
            
            
//根据别名从证书中获取私钥
            PrivateKey prikey = (PrivateKey) keystore.getKey(keyalias,password);
            X509Certificate x509 
= null;
            
            
//获取该别名对应的证书链
            Certificate[] certs = keystore.getCertificateChain(keyalias);
            
if (certs[0instanceof X509Certificate) {//user's certificate
                x509 = (X509Certificate) certs[0];
            }

            
if (certs[certs.length - 1instanceof X509Certificate) {//root certificate
                x509 = (X509Certificate) certs[certs.length - 1];
            }

            gen.addSigner(prikey, x509, CMSSignedDataStreamGenerator.DIGEST_SHA1,
                    
"BC");
            CertStore certstore 
= CertStore.getInstance("Collection"new CollectionCertStoreParameters(Arrays.asList(certs)),"BC");
            gen.addCertificatesAndCRLs(certstore);
        }

        
//输出字节流
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();//"e:/JavaSignedData.txt"
        OutputStream sigOut = gen.open(bOut,true);//false,不含原始数据,减轻传输负担
        sigOut.write(signText);//对原始数据进行签名
        sigOut.close();
        logger.info(
"pkcs7 signed success!");
        
byte[] signedData = bOut.toByteArray();//签名后数据
        bOut.close();
        
byte[] signedDataBase64 = Base64.encode(signedData);
        logger.debug(
"签名后数据: " + new String(signedData,CHARSET) + " ");
        logger.debug(
"签名后数据Base64: " + new String(signedDataBase64,CHARSET) + " ");
        
return signedData;
    }
    

注意,如果验证cryptoapi的CryptSignHash方法生成PKCS#1的签名数据,则需要在验证时增加一个null byte,代码如下:
            Signature sig = Signature.getInstance("MD5withRSA","BC");
            sig.initVerify(publicKey);
            sig.update(data);
//data为原始数据
            sig.update((byte)0);//增加一个null byte。
            sig.verify(signedData)//signedData为cryptoapi签名生成的128位数据。
原创粉丝点击