我在查看这个参考项目后找到了答案https://code.google.com/p/j4ops/ https://code.google.com/p/j4ops/。本指南也很有帮助,尽管它专门处理使用 iText 的 PDF,而 iText 使用来自加密操作的 BC:http://itextpdf.com/book/digitalsignatures20130304.pdf http://itextpdf.com/book/digitalsignatures20130304.pdf。诀窍是通过实现使用 Sign(byte[] toEncrypt) 方法的 Signer 接口,将签名操作委托给外部提供者(PKCS11、PKCS12 等)。这样,可以设置提供者,然后只需调用签名方法,并将如何签名的实现细节留给提供者本身。
Bouncy Castle 使用 CMSSignedDataGenerator 类和 SignerInf 内部类分别构建 CMS 容器和签名者信息。因此,技巧是构建一个不需要私钥的 SignerInf 对象,因为 sign() 操作应该委托给提供者。私钥甚至可能不可用,特别是在使用智能卡时。此外,在对哈希进行签名和构建 CMS 容器时,需要考虑需要添加为签名属性和/或未签名属性的信息。因此,这些是解决问题的基本步骤:
// Build the items to encrypt, objects for method parameters would be obtained previously.
byte[] toEncrypt = externalSignerInfoGenerator.getCmsBytesToSign(hash,
signingTime,
PKCSObjectIdentifiers.data,
x509Cert,
timeStampToken,
ocsp);
// The externalSignerInfoGenerator.getCmsBytesToSign is a method from a re implemention of the
// SignerInf inner class from CMSSignedDataGenerator and is used to get a byte array from an
// org.bouncycastle.asn1.ASN1EncodableVector. To build the vector one should add attributes to
// their corresponding OID's using the org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers interface,
// for example:
ASN1EncodableVector signedAttrVector = buildSignedAttributes (hash, signingTime, contentType,
x509Cert, ocspResp);
// This would call the buildSignedAttributes method to build the signed attributes vector
ASN1EncodableVector signedAttrVector = new ASN1EncodableVector();
// Add CMS attributes
signedAttrVector.add (new Attribute(CMSAttributes.contentType, new DERSet (contentType)));
signedAttrVector.add (new Attribute (CMSAttributes.signingTime, new DERSet(new Time (signingTime))));
signedAttrVector.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash))));
// Not all attributes are considered in BC's CMSAttributes interface, therefore one would have to add
// an additional step:
signedAttrVector.add(buildOcspResponseAttribute(ocspResp));
// This method would call buildOcspResponseAttribute to add the object as a PKCSObjectIdentifier
protected Attribute buildOcspResponseAttribute (byte[] ocspResp) throws IOException, CMSException {
return new Attribute (PKCSObjectIdentifiers.id_aa_ets_revocationRefs,
new DERSet(DERUtil.readDERObject(ocspResp)));
}
// Call sign method from provider, such as PKCS11, PKCS12, etc.
byte [] signature = getSignProvider().sign(toEncrypt);
// Now build standard org.bouncycastle.cms.SignerInfoGenerator with hash, signed data
// and certificate to add to CMS, create attached or detached signature
// create signed envelope
CMSSignedData envdata = externalCMSSignedDataGenerator.generate(false);
byte[] enveloped = envdata.getEncoded();