我的java小程序能够使用分离类型的Bouncy Castle 1.4.9生成CMSSignedData。然后,字节数组 sigData.getEncoded() 存储在服务器上的表中(可以访问未包含的内容数据)。现在我想在服务器中创建封装的 CMSSignedData 以便用户下载 .p7m 文件。
我需要开发的函数具有分离签名的字节数组和内容数据的字节数组,并且必须返回CaDES封装签名的字节数组,它将用于下载.p7m文件。
问题是我无法将分离的签名者转换为信封的签名者。
这是我在小程序中使用的一些代码: signCAdeS 使用分离签名对文档进行签名,然后调用 attach(仅用于测试)将分离签名转换为信封签名,但没有成功:使用 Dike 打开创建的 .p7m 文件,无法查看内容数据。
private byte[] signCAdES(byte[] aDocument, PrivateKey aPrivateKey, Certificate[] certChain)
throws GeneralSecurityException {
byte[] digitalSignature = null;
try {
Security.addProvider(new BouncyCastleProvider());
ArrayList<X509Certificate> certsin = new ArrayList<X509Certificate>();
for (int i = 0; i < certChain.length; i++) {
certsin.add((X509Certificate) certChain[i]);
}
X509Certificate cert = certsin.get(0);
//Nel nuovo standard di firma digitale e' richiesto l'hash del certificato di sottoscrizione:
String digestAlgorithm = "SHA-256";
String digitalSignatureAlgorithmName = "SHA256withRSA";
MessageDigest sha = MessageDigest.getInstance(digestAlgorithm);
byte[] digestedCert = sha.digest(cert.getEncoded());
//Viene ora create l'attributo ESSCertID versione 2 cosi come richiesto nel nuovo standard:
AlgorithmIdentifier aiSha256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
ESSCertIDv2 essCert1 = new ESSCertIDv2(aiSha256, digestedCert);
ESSCertIDv2[] essCert1Arr = {essCert1};
SigningCertificateV2 scv2 = new SigningCertificateV2(essCert1Arr);
Attribute certHAttribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));
//Aggiungiamo l'attributo al vettore degli attributi da firmare:
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(certHAttribute);
AttributeTable at = new AttributeTable(v);
CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(at);
//Creaiamo l'oggetto che firma e crea l'involucro attraverso le librerie di Bouncy Castle:
SignerInfoGeneratorBuilder genBuild = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
genBuild.setSignedAttributeGenerator(attrGen);
//Si effettua la firma con l'algoritmo SHA256withRSA che crea l'hash e lo firma con l'algoritmo RSA:
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner shaSigner = new JcaContentSignerBuilder("SHA256withRSA").build(aPrivateKey);
SignerInfoGenerator sifGen = genBuild.build(shaSigner, new X509CertificateHolder(cert.getEncoded()));
gen.addSignerInfoGenerator(sifGen);
X509CollectionStoreParameters x509CollectionStoreParameters = new X509CollectionStoreParameters(certsin);
JcaCertStore jcaCertStore = new JcaCertStore(certsin);
gen.addCertificates(jcaCertStore);
CMSTypedData msg = new CMSProcessableByteArray(aDocument);
CMSSignedData sigData = gen.generate(msg, false); // false=detached
byte[] encoded = sigData.getEncoded();
FileOutputStream fos = new FileOutputStream("H:\\prova2.txt.p7m");
fos.write(attach(aDocument, encoded));
fos.flush();
fos.close();
digitalSignature = encoded;
} catch (CMSException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} catch (OperatorCreationException ex) {
ex.printStackTrace();
}
return digitalSignature;
}
这是attach函数:
public static byte[] attach(byte[] originalData, byte[] detached) {
try {
ASN1InputStream in = new ASN1InputStream(detached);
CMSSignedData sigData = new CMSSignedData(new CMSProcessableByteArray(originalData), in);
return sigData.getEncoded();
} catch (Exception e) {
return null;
}
}
改编自 http://bouncy-castle.1462172.n4.nabble.com/Add-signed-content-to-detached-signatures-td1467150.html
public static byte[] attach(byte[] originalData, byte[] detached) throws IOException {
try (ASN1InputStream in = new ASN1InputStream(detached);) {
BERSequence seqContentData = (BERSequence) in.readObject();
ContentInfo contentInfo = ContentInfo.getInstance(seqContentData);
SignedData sdDetached = new SignedData((ASN1Sequence) contentInfo.getContent());
ContentInfo encapContentInfo = new ContentInfo(CMSObjectIdentifiers.data, new BEROctetString(originalData));
SignedData sdAttached = new SignedData(
sdDetached.getVersion(),
sdDetached.getDigestAlgorithms(),
encapContentInfo,
sdDetached.getCertificates(),
sdDetached.getCRLs(),
sdDetached.getSignerInfos());
ContentInfo contentInfoAttached = new ContentInfo(PKCSObjectIdentifiers.signedData, sdAttached);
return contentInfoAttached.getEncoded();
}
}
使用 BC 1.64 进行测试
这个回应来得有点晚了。您肯定会找到替代方案,因为不可能将分离的 CAdES 转换为包络
查看
CAdES签名的
SignedData
节点的 ASN.1 结构,如 RFC 3852 -CMS 中定义
SignedData
包括 encapContentInfo
,其中包含用于封装签名的原始数据,但不存在于分离签名中。 由于 SignedData
已签名,因此无法添加原始数据以将 detached 转换为 enveloping
注意:正确的术语是“封装”,因为签名包装了数据。 封装的签名将嵌入到数据中
第一个版本使用 byte[],因此它支持最大大小为 2 GB 的文件
:
public static byte[] BundleSignature(byte[] originalData, byte[] detached)
{
Asn1InputStream input = new Asn1InputStream(detached);
BerSequence seqContentData = (BerSequence)input.ReadObject();
ContentInfo contentInfo = ContentInfo.GetInstance(seqContentData);
Org.BouncyCastle.Asn1.Cms.SignedData sdDetached = Org.BouncyCastle.Asn1.Cms.SignedData.GetInstance(((Asn1Sequence)contentInfo.Content));
ContentInfo encapContentInfo = new ContentInfo(Org.BouncyCastle.Asn1.Cms.CmsObjectIdentifiers.Data, new BerOctetString(originalData));
SignedData sdAttached = new SignedData(
sdDetached.Version,
sdDetached.DigestAlgorithms,
encapContentInfo,
sdDetached.Certificates,
sdDetached.CRLs,
sdDetached.SignerInfos);
ContentInfo contentInfoAttached = new ContentInfo(PkcsObjectIdentifiers.SignedData, sdAttached);
return contentInfoAttached.GetEncoded();
}
没有文件限制:
public static void BundleP7Signature(Stream streamDetached, Stream streamInput, Stream streamOutput)
{
Stream outputStream = null;
try
{
CmsSignedData cMSSignedData = new CmsSignedData((CmsProcessable)new CmsProcessableByteArray(new byte[] { 0, 1, 2 }), streamDetached);
CmsSignedDataStreamGenerator cMSSignedDataStreamGenerator;
(cMSSignedDataStreamGenerator = new CmsSignedDataStreamGenerator()).AddSigners(cMSSignedData.GetSignerInfos());
cMSSignedDataStreamGenerator.AddCertificates(cMSSignedData.GetCertificates("Collection"));
outputStream = cMSSignedDataStreamGenerator.Open(streamOutput, true);
Streams.PipeAll(streamInput, outputStream);
}
finally
{
if (outputStream != null)
outputStream.Close();
streamDetached.Close();
streamInput.Close();
streamOutput.Close();
}
}