Java 用bouncy castle验证签名

Java 用bouncy castle验证签名,java,bouncycastle,signing,Java,Bouncycastle,Signing,我使用不推荐使用的BouncyCastleAPI继承了一些代码。在将它更新为新的API之前,我想编写一个测试来验证我没有改变它的行为。但是,我无法找到正确的方法来验证生成的签名。要更改的代码为: public static byte[] createSignedData(byte[] content, X509Certificate cert, PrivateKey key) throws NoSuchAlgorithmException, NoSuchProviderExcep

我使用不推荐使用的BouncyCastleAPI继承了一些代码。在将它更新为新的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);
如果您使用以下选项,它将返回一个分离的签名:

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

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

这就是我使用
bcmail-jdk16-1.46.jar
bcprov-jdk16-1.46.jar
jdk1.6.0_45
对签名进行签名和验证所做的工作(我假设您正在使用Java,因为您从未指定过它,还有疑问标记-但希望.NET版本非常类似)

您可以下载我的示例中使用的密钥库,网址为:

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

if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) { ... }
然后加载另一个密钥库,从中获取另一个证书。我要知道的是,我使用的certificates.p12文件包含两个别名为
Key1
Key2
的证书,因此您可以通过使用
Key1
对内容进行签名,并使用
Key2
验证您的签名来处理它们

例如:

然后将第84行替换为:

if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromKeystore2))) { ... }
请注意,
certFromSignedData
更改为
certFromKeystore2
,您的签名验证将失败,因为您的内容是使用
Key1
签名的


Java代码:

不要忘记更改常量中的密钥库路径

if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromKeystore2))) { ... }
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");
            }
        }
    }
}