【问题标题】:Verify a signature with bouncy castle使用充气城堡验证签名
【发布时间】:2014-08-18 13:25:02
【问题描述】:

我使用已弃用的 bouncycastle API 继承了一些代码。在将它更新到新的 API 之前,我想编写一个测试来验证我没有改变它的行为。但是,我无法找出正确的方法来验证生成的这个签名。要更改的代码是:

public static byte[] createSignedData(byte[] content, X509Certificate cert, PrivateKey key)
        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, IOException {

    // set up the generator
    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

    gen.addSigner(key, cert, CMSSignedGenerator.DIGEST_SHA1);

    // create the signed-data object
    CMSProcessable data = new CMSProcessableByteArray(content);
    CMSSignedData signed = gen.generate(data, BC_PROVIDER);

    return signed.getEncoded();
}

这段代码返回了什么?一个独立的签名? 我试图用这样的一小段代码来验证签名,但它总是返回 false:

Signature signer = Signature.getInstance(
                              "SHA1withRSA", 
                              BouncyCastleProvider.PROVIDER_NAME);
signer.initVerify(cert.getPublicKey());
signer.update(data);
return signer.verify(sig);

【问题讨论】:

    标签: java bouncycastle signing


    【解决方案1】:

    如果你使用,它将返回一个分离的签名:

    gen.generate(data, false);
    

    否则它将返回封装在签名中的签名数据。因此,如果您的签名被分离(这不是您的情况),为了验证它,您需要从您的签名数据字节或 Base64 enconded string 创建一个新的 CMSSignedData 对象以及构造函数中原始数据的副本。

    我认为您没有以正确的方式验证您的签名,我也不知道您使用的是哪个 bouncycastle 库版本,并且您只是提供了一个代码 sn-p 太模糊而无法分析。

    这是我为了使用 bcmail-jdk16-1.46.jarbcprov-jdk16-1.46.jarjdk1.6.0_45 签署和验证签名所做的(我假设您使用的是 Java,因为您从未指定它,也有问题标签 - 但希望 .NET 版本非常相似)。

    您可以在以下位置下载我的示例中使用的 keystorehttps://dl.dropboxusercontent.com/u/15208254/keys/certificates.p12

    另外,如果您想检查签名验证是否正常工作,您可以更改证书(因为我正在根据我自己的证书进行验证,这没有意义)签名验证过程中的行,第 84 行

    if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) { ... }
    

    然后加载另一个 keystore 以从中获取另一个 证书。要知道,我正在使用的 certificates.p12 文件包含两个别名为 Key1Key2 的证书,因此您可以通过签署您的内容来使用它们使用Key1 并使用Key2 验证您的签名。

    例如:

    // Load 'Key2' certificate from 'certificates.p12' at any place on this class after 'ks' declaration
    X509Certificate certFromKeystore2 = (X509Certificate) ks.getCertificate("Key2");
    

    然后将 第 84 行 替换为:

    if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromKeystore2))) { ... }
    

    请注意,certFromSignedData 已更改为 certFromKeystore2,您的签名验证将失败,因为您的内容是使用 Key1 签名的。


    Java 代码:

    不要忘记更改常量中的 keystore 路径!

    package com.example.main;
    
    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.Collection;
    import java.util.Iterator;
    import java.util.List;
    
    import org.bouncycastle.cert.X509CertificateHolder;
    import org.bouncycastle.cert.jcajce.JcaCertStore;
    import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
    import org.bouncycastle.cms.CMSProcessableByteArray;
    import org.bouncycastle.cms.CMSSignedData;
    import org.bouncycastle.cms.CMSSignedDataGenerator;
    import org.bouncycastle.cms.CMSTypedData;
    import org.bouncycastle.cms.SignerInformation;
    import org.bouncycastle.cms.SignerInformationStore;
    import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
    import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
    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;
    
    public class VerifySignature {
    
        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";
    
        static final String DIGEST_SHA1 = "SHA1withRSA";
        static final String BC_PROVIDER = "BC";
    
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public static void main(String[] args) throws Exception {
    
            // Content to be signed
            String text = "My name is Oscar";
    
            Security.addProvider(new BouncyCastleProvider());
    
            // Get keystore
            KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
            ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray());
            Key key = ks.getKey(KEYSTORE_ALIAS, KEYSTORE_PWD.toCharArray());
    
            // Get private key and sign
            PrivateKey privKey = (PrivateKey) key;
            Signature signature = Signature.getInstance(DIGEST_SHA1, BC_PROVIDER);
            signature.initSign(privKey);
            signature.update(text.getBytes());
    
            // Build CMS
            X509Certificate certFromKeystore = (X509Certificate) ks.getCertificate(KEYSTORE_ALIAS);
            List certList = new ArrayList();
            CMSTypedData data = new CMSProcessableByteArray(signature.sign());
            certList.add(certFromKeystore);
            Store certs = new JcaCertStore(certList);
            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
            ContentSigner sha1Signer = new JcaContentSignerBuilder(DIGEST_SHA1).setProvider(BC_PROVIDER).build(privKey);
            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC_PROVIDER).build()).build(sha1Signer, certFromKeystore));
            gen.addCertificates(certs);
            CMSSignedData signedData = gen.generate(data, true);
    
            // Verify signature
            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");
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-20
      • 2015-05-04
      • 1970-01-01
      • 2016-12-02
      • 1970-01-01
      • 2015-12-23
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      相关资源
      最近更新 更多