验证充气城堡的签名 [英] Verify a signature with bouncy castle

查看:81
本文介绍了验证充气城堡的签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I inherited some code using the deprecated bouncycastle API. Before updating it to the new API I wanted to write a test to verify that I didn't change its behaviour. However, I cannot work out the correct way to verify this signature that is generated. The code to be changed is:

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:

What is being returned from this code? A detached signature? I tried to verify the signature with a small piece of code like this, but it always returns false:

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

推荐答案

如果使用,它将返回 分离 签名:

It will return a detached signature if you use:

gen.generate(data, false);

否则,它将返回封装在签名中的 签名数据 .因此,如果您的签名是分离的(不是您的情况)为了进行验证,则需要从签名的数据字节或中创建一个新的 CMSSignedData 对象> Base64 封装了 string ,并且还在构造函数中带有原始数据的副本.

Otherwise it will return signed data encapsulated in the signature. So, if your signature is detached (which is not your case) in order to verify it you will need to create a new CMSSignedData object from your signed data bytes or Base64 enconded string and also a copy of the original data as well in the constructor.

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

I think you're not verifying your signature the right way, also I don't know which bouncycastle library version are you using and you just provided a code snippet which is too vague to analyze.

这是我使用 bcmail-jdk16-1.46.jar bcprov-jdk16-1.46签名并验证签名的方法.jar jdk1.6.0_45 (我假设您使用的是 Java ,因为您从未指定过它,同样是有问题的标签-但希望 .NET 的版本非常相似.

This is what I did in order to sign and verify a signature using bcmail-jdk16-1.46.jar, bcprov-jdk16-1.46.jar and jdk1.6.0_45 (I'm assuming you are using Java since you never specified it, also in question tags - but hopefully .NET version is very similar).

您可以从以下示例中下载在我的示例中使用的 keystore :

You can download the keystore used in my example at: https://dl.dropboxusercontent.com/u/15208254/keys/certificates.p12

此外,如果您想检查签名验证是否工作正常,则可以更改证书(因为我正在根据自己的无用证书进行验证) 签名验证过程中的 84行 :

Also, if you want to check if the signature verification is working fine, you can change the certificate (since I'm verifying against my own certificate which doesn't make sense) by changing this line in the signature verification process, line 84:

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

,然后加载另一个 keystore ,以从中获取另一个 证书 .要知道,我正在使用的 certificates.p12 文件包含两个别名为 Key1 Key2 的证书.例如,您可以通过使用 Key1 签名内容并使用 Key2 验证签名来与他们一起玩耍.

And then loading another keystore to get another certificate from it. Just to know, the certificates.p12 file I am using, contains two certificates with alias Key1 and Key2 so you can play around with them by signing your content with Key1 and verifying your signature with Key2 for example.

例如:

e.g:

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

然后将 第84行 替换为此:

Then replace line 84 with this:

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

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

Notice that certFromSignedData changed to certFromKeystore2 and your signature verification will fail because your content was signed with Key1.

Java代码:

Java code:

别忘了更改常量中的 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");
            }
        }
    }
}

这篇关于验证充气城堡的签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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