如何使用bouncy城​​堡签名签名数据? [英] How to sign signature data using bouncy castle?

查看:618
本文介绍了如何使用bouncy城​​堡签名签名数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

**This is my code to sign a String.</br>**

package my.package;

import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import sun.misc.BASE64Encoder;

public class SignMessage {
    static final String KEYSTORE_FILE = "keys/certificates.p12";
    static final String KEYSTORE_INSTANCE = "PKCS12";
    static final String KEYSTORE_PWD = "test";
    static final String KEYSTORE_ALIAS = "Key1";

    public static void main(String[] args) throws Exception {

        String text = "This is a message";

        Security.addProvider(new BouncyCastleProvider());

        KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
        ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray());
        Key key = ks.getKey(KEYSTORE_ALIAS, KEYSTORE_PWD.toCharArray());

        //Sign
        PrivateKey privKey = (PrivateKey) key;
        Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
        signature.initSign(privKey);
        signature.update(text.getBytes());

        //Build CMS
        X509Certificate cert = (X509Certificate) ks.getCertificate(KEYSTORE_ALIAS);
        List certList = new ArrayList();
        CMSTypedData msg = new CMSProcessableByteArray(signature.sign());
        certList.add(cert);
        Store certs = new JcaCertStore(certList);
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privKey);
        gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, cert));
        gen.addCertificates(certs);
        CMSSignedData sigData = gen.generate(msg, false);

        FileOutputStream sigfos = new FileOutputStream("D:\\SBI-DATA\\file\\signature_1.txt");
            sigfos.write(Base64.encodeBase64(sp.getEncoded()));

            sigfos.close();
    }
}






现在,EnvelopedData输出将用于通过这种方式验证签名的过程:


Now, the EnvelopedData output will be used in the process to verify the signature by this way:

import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;

public class VerifySignature {
    public static void main(String[] args) throws Exception {
        File p7s = new File("D:\\SBI-DATA\\file\\signature_2.txt") ;
        int size = ((int) p7s.length());
        byte[] sig = new byte[size]; 
        File f = new File("D:\\SBI-DATA\\file\\plain.txt") ;
        int sizecontent = ((int) f.length());
        byte[] Data_Bytes = new byte[sizecontent];  
        Security.addProvider(new BouncyCastleProvider());    
        CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(Data_Bytes), sig);     
            Store store = signedData.getCertificates(); 
            SignerInformationStore signers = signedData.getSignerInfos(); 
            Collection c = signers.getSigners(); 
            Iterator it = c.iterator();
            while (it.hasNext()) { 
                SignerInformation signer = (SignerInformation) it.next(); 
                Collection certCollection = store.getMatches(signer.getSID()); 
                Iterator certIt = certCollection.iterator();
                X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next();
                X509Certificate certFromSignedData = new JcaX509CertificateConverter().setProvider(BC_PROVIDER).getCertificate(certHolder);
                if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) {
                    System.out.println("Signature verified");
                } else {
                    System.out.println("Signature verification failed");
                }
            }
    }    
}  






一切正常,直到signer.verify(..)由于以下异常:


Everything works good until signer.verify(..) due to the following Exception:

Exception in thread "main" org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
    at org.bouncycastle.cms.SignerInformation.doVerify(Unknown Source)
    at org.bouncycastle.cms.SignerInformation.verify(Unknown Source)
    at my.package.VerifySignature.main(VerifySignature.java:64)

我真的不知道我做错了什么。

And I really don't know what I am doing wrong. Can someone please give me a hint of what is happening?

推荐答案

我想你是签署两次,一次直接使用签名,另一个使用 ContentSigner

I think you are signing it twice, once directly using Signature and the other one using ContentSigner. You need only to sign the data, not the signature.

因此,解决方案应该是替换 signature.sign() text 的字符集,而不是使用某些系统默认值。

So the solution should be to replace signature.sign() with text.getBytes(), or text.getBytes(StandardCharsets.UTF_8) if you want to explicitly define a character set for text instead of using some system default.

这篇关于如何使用bouncy城​​堡签名签名数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆