无法使用Apache PDFBOX验证数字签名

无法使用Apache PDFBOX验证数字签名,pdf,digital-signature,bouncycastle,pdfbox,verification,Pdf,Digital Signature,Bouncycastle,Pdfbox,Verification,我是使用数字签名的新手。在其中一个项目中,我们使用ApachePDFBox处理数字签名的pdf文件。虽然我们可以测试所有功能,但签名pdf文件的验证是我们无法破解的。我们使用BouncyCastle作为提供程序。代码如下: //从pdf文件中获取数字签名和签名内容 byte[] signatureAsBytes = pdsignature.getContents(new FileInputStream(this.INPUT_FILE)); byte[] signedContentAsBytes

我是使用数字签名的新手。在其中一个项目中,我们使用ApachePDFBox处理数字签名的pdf文件。虽然我们可以测试所有功能,但签名pdf文件的验证是我们无法破解的。我们使用BouncyCastle作为提供程序。代码如下:

//从pdf文件中获取数字签名和签名内容

byte[] signatureAsBytes = pdsignature.getContents(new FileInputStream(this.INPUT_FILE));
byte[] signedContentAsBytes = pdsignature.getSignedContent(new FileInputStream(this.INPUT_FILE));
//数字签名验证

Security.addProvider(new BouncyCastleProvider());
Signature signer = Signature.getInstance("RSA","BC");

//Get PublicKey from p7b file
X509Certificate cert509=null;
File file = new File("C:\\certificate_file.p7b");
FileInputStream fis = new FileInputStream(file);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection c = cf.generateCertificates(fis);
Iterator it = c.iterator();
PublicKey pubkey;

while (it.hasNext()) 
{
   cert509 = (X509Certificate) it.next();
   pubkey = cert509.getPublicKey();
}

boolean VERIFIED=false;
Security.addProvider(new BouncyCastleProvider());
Signature signer = Signature.getInstance("RSA","BC");
PublicKey key=this.getPublicKey(false);
signer.initVerify(key);

List<PDSignature> allsigs = this.PDFDOC.getSignatureDictionaries();
Iterator<PDSignature> i = allsigs.iterator();

while(i.hasNext())
{
        PDSignature sig = (PDSignature) i.next();
        byte[] signatureAsBytes = sig.getContents(new FileInputStream(this.INPUT_FILE));
        byte[] signedContentAsBytes = sig.getSignedContent(new FileInputStream(this.INPUT_FILE));
        signer.update(signedContentAsBytes);
        VERIFIED=signer.verify(signatureAsBytes);
}

System.out.println("Verified="+VERIFIED);

使用上面的代码,我总是得到“false”的响应。我不知道如何解决这个问题。请帮助

您的主要问题是存在多种类型的PDF签名,这些签名在签名容器的格式和签名字节的实际内容上有所不同。另一方面,BC代码只能验证上述签名容器中包含的裸签名字节序列

可互操作的签名类型 正如标题所说,下面的列表包含“可互操作的签名类型”,这些类型或多或少都有严格的定义。指定还包括完全自定义签名方案的方法。但让我们假设我们处于一种可互操作的状态。签名类型的集合可分解为:

  • 第12.8.3.2节PKCS#1签名中定义的adbe.x509.rsa#u sha1;签名值内容包含一个DER编码的PKCS#1二进制数据对象;这个数据对象是一个相当裸露的签名,在RSA的情况下是一个包含填充文档哈希和哈希算法的加密结构

  • 第12.8.3.3节PKCS#7签名中定义的adbe.pkcs7.sha1;签名值内容包含一个DER编码的PKCS#7二进制数据对象;此数据对象是一个大容器对象,它还可以包含元信息,例如,它可能包含用于构建证书链的证书、用于证书吊销检查的吊销信息、用于固定签名时间的数字时间戳等等。。。文件字节范围的SHA1摘要应使用数据类型的ContentInfo封装在PKCS#7 SignedData字段中。该签名数据的摘要应作为普通PKCS#7摘要合并

  • 第12.8.3.3节PKCS#7签名中定义的adbe.pkcs7.分离;签名值内容包含一个DER编码的PKCS#7二进制数据对象,见上文。文件字节范围内的原始签名消息摘要应合并为普通PKCS#7签名数据字段。PKCS#7 SignedData字段中不得封装任何数据

  • ETSI.CAdES.分离中定义,并将集成到ISO 32000-2中;签名值内容包含CMS中指定的DER编码的SignedData对象;CMS签名容器是PKCS#7签名容器的近亲,见上文。这本质上是adbe.pkcs7.detached的一个不同的、定义更严格的变体

  • ETSI.RFC3161中定义,并将纳入ISO 32000-2;签名值内容包含RFC 3161中指定的时间戳标记;时间戳令牌同样与PKCS#7签名容器密切相关,见上文,但它们包含一个特殊的数据子结构,其中包含文档散列、创建戳的时间以及发布时间服务器上的信息


我会建议研究我命名的规范和其中引用的文件,主要是RFC。基于这些知识,您可以轻松找到合适的BouncyCastle类来分析不同的签名内容

一个工作示例来验证ApachePDFBOx1.8.16和BouncyCastle1.44的
adbe.pkcs7.Distached
PDF签名(最常见的PDF签名):

import org.apache.pdfbox.pdmodel.PDDocument;
导入org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
导入org.bouncycastle.cms.cms可处理;
导入org.bouncycastle.cms.cms可由tearray处理;
导入org.bouncycastle.cms.CMSSignedData;
导入org.bouncycastle.cms.SignerInformation;
导入org.bouncycastle.cms.SignerInformationStore;
导入java.io.File;
导入java.io.FileInputStream;
导入java.security.cert.CertStore;
导入java.security.cert.x509证书;
导入java.util.Collection;
导入java.util.Iterator;
导入java.util.List;
公共类PDFBoxValidateSignature{
公共静态void main(字符串[]args)引发异常{
File signedFile=新文件(“sample signed.pdf”);
//我们加载已签名的文档。
PDDocument document=PDDocument.load(signedFile);
List signatureDictionaries=document.getSignatureDictionaries();
//然后我们一次验证一个签名。
对于(PDSignature signatureDictionary:signatureDictionary){
//注意,这段代码目前只支持“adbe.pkcs7.detached”,这是最常见的签名/子过滤器。
字节[]signatureContent=signatureDictionary.getContents(新文件输入流(signedFile));
字节[]signedContent=signatureDictionary.getSignedContent(新文件输入流(signedFile));
//现在我们构建了一个PKCS#7或CMS。
CMSProcessable cmsProcessableInputStream=新CMSProcessableByteArray(签名内容);
CMSSignedData CMSSignedData=新的CMSSignedData(cmsProcessableInputStream,signatureContent);
SignerInformationStore SignerInformationStore=cmsSignedData.getSignerInfos();
集合签名者=signerInformationStore.getSigners();
CertStore certs=cmsSignedData.getCertificatesAndCRLs(“集合”,(字符串)null);
迭代器signersIterator=signers.Iterator();
while(signersIterator.hasNext()){
SignerInformation SignerInformation=(SignerInformation)signersIterator
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
  Key:  Sun RSA public key, 2048 bits
  Validity: [From: Tue Aug 06 12:26:47 IST 2013,
  To: Wed Aug 05 12:26:47 IST 2015]
  Algorithm: [SHA256withRSA]