[英]Verify a signature with bouncy castle
我使用不推荐使用的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);
如果使用,它将返回一个分离的签名:
gen.generate(data, false);
否则,它将返回封装在签名中的签名数据 。 因此,如果分离了签名(不是您的情况)以进行验证,则需要从签名数据字节或Base64
编码的string
以及构造函数中以及原始数据的副本中创建新的CMSSignedData
对象。 。
我认为您没有以正确的方式验证您的签名,也不知道您使用的是哪个bouncycastle
库版本,而您只是提供了一个过于模糊而无法分析的代码段。
这是我为了使用bcmail-jdk16-1.46.jar
, bcprov-jdk16-1.46.jar
和jdk1.6.0_45
签名和验证签名bcmail-jdk16-1.46.jar
jdk1.6.0_45
(我假设您使用的是Java,因为您从未指定过它,有问题的标签-但希望.NET版本非常相似)。
您可以从以下示例中下载我的示例中使用的密钥库 : https : //dl.dropboxusercontent.com/u/15208254/keys/certificates.p12
另外,如果您想检查签名验证是否工作正常,则可以通过在签名验证过程的第84行中更改此行来更改证书(因为我正在使用自己的证书进行验证)
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) { ... }
然后加载另一个密钥库以从中获取另一个证书 。 要知道,我正在使用的certificate.p12文件包含两个别名为Key1
和Key2
证书,因此您可以通过使用Key1
签名内容并使用Key2
验证签名来使用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代码:
不要忘记在常量中更改密钥库路径!
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");
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.