Java 使用充气城堡验证签名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24451744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Verify a signature with bouncy castle
提问by Gary Barker
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:
我使用已弃用的 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();
}
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:
这段代码返回了什么?一个分离的签名?我试图用这样的一小段代码验证签名,但它总是返回false:
Signature signer = Signature.getInstance(
"SHA1withRSA",
BouncyCastleProvider.PROVIDER_NAME);
signer.initVerify(cert.getPublicKey());
signer.update(data);
return signer.verify(sig);
回答by Oscar Jara
It will return a detachedsignature if you use:
如果您使用,它将返回一个分离的签名:
gen.generate(data, false);
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.
否则它将返回封装在签名中的签名数据。因此,如果您的签名被分离(这不是您的情况)以验证它,您将需要CMSSignedData
从您的签名数据字节或Base64
enconded创建一个新对象string
,以及在构造函数中创建原始数据的副本。
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.
我认为您没有以正确的方式验证您的签名,我也不知道bouncycastle
您使用的是哪个库版本,您只是提供了一个过于模糊而无法分析的代码片段。
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 Javasince you never specified it, also in question tags - but hopefully .NETversion is very similar).
这是我以签名和使用验证签名做了bcmail-jdk16-1.46.jar
,bcprov-jdk16-1.46.jar
并且jdk1.6.0_45
(我假设你正在使用的Java,因为你永远不指定,也有问题标签-但希望.NET版本很相似)。
You can download the keystoreused in my example at: https://dl.dropboxusercontent.com/u/15208254/keys/certificates.p12
您可以在我的示例中下载密钥库:https: //dl.dropboxusercontent.com/u/15208254/keys/certificates.p12
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:
此外,如果您想检查签名验证是否正常工作,您可以通过更改签名验证过程中的这一行,第 84行来更改证书(因为我正在验证我自己的证书,这是没有意义的):
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) { ... }
And then loading another keystoreto get another certificatefrom it. Just to know, the certificates.p12file 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.
然后加载另一个密钥库以从中获取另一个证书。只知道,在certificates.p12我使用的文件,包含了两个证书具有别名Key1
,并Key2
让您可以通过签署内容玩弄他们Key1
,并验证您的签名Key2
的例子。
e.g:
例如:
// Load 'Key2' certificate from 'certificates.p12' at any place on this class after 'ks' declaration
X509Certificate certFromKeystore2 = (X509Certificate) ks.getCertificate("Key2");
Then replace line 84with this:
然后用这个替换第 84 行:
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromKeystore2))) { ... }
Notice that certFromSignedData
changed to certFromKeystore2
and your signature verification will fail because your content was signed with Key1
.
请注意,certFromSignedData
更改为certFromKeystore2
并且您的签名验证将失败,因为您的内容是使用Key1
.
Java code:
爪哇代码:
Don't forget to change the keystorepath in the constants!
不要忘记更改常量中的密钥库路径!
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");
}
}
}
}