Java iText 5通过MakeSignature.signDeferred进行外部签名时签名无效

Java iText 5通过MakeSignature.signDeferred进行外部签名时签名无效,java,pdf,itext,digital-signature,signature,Java,Pdf,Itext,Digital Signature,Signature,我正在使用iText 5 Java进行外部签名。首先,我创建签名外观,计算签名属性的哈希值,并为签名保留空白位置。稍后,当我从客户端获得签名的散列时,我通过MakeSignature.signDeferred将其插入PDF 但是PDF阅读器显示签名无效。抱怨PDF已被修改。 这是用于签名的代码。我已经删除了很多功能代码,以保持代码的基本功能 import com.itextpdf.text.DocumentException; 导入com.itextpdf.text.Rectangle; 导入

我正在使用iText 5 Java进行外部签名。首先,我创建签名外观,计算签名属性的哈希值,并为签名保留空白位置。稍后,当我从客户端获得签名的散列时,我通过
MakeSignature.signDeferred
将其插入PDF

但是PDF阅读器显示签名无效。抱怨PDF已被修改。

这是用于签名的代码。我已经删除了很多功能代码,以保持代码的基本功能

import com.itextpdf.text.DocumentException;
导入com.itextpdf.text.Rectangle;
导入com.itextpdf.text.pdf.*;
导入com.itextpdf.text.pdf.security.*;
导入org.apache.commons.codec.binary.Base64;
导入org.apache.commons.codec.binary.Hex;
导入java.io.*;
导入java.security.GeneralSecurityException;
导入java.security.MessageDigest;
导入java.security.cert.Certificate;
导入java.security.cert.CertificateException;
导入java.security.cert.CertificateFactory;
导入java.util.Calendar;
导入java.util.GregorianCalendar;
公共类MklTest{
静态字符串thisHash;
静态类MyExternalSignatureContainer实现ExternalSignatureContainer{
受保护字节[]sig;
公共MyExternalSignatureContainer(字节[]sig){
this.sig=sig;
}
公共字节[]符号(InputStream为){
返回信号;
}
@凌驾
公共无效修改签名字典(PdfDictionary signDic){
}
}
静态类EmptyContainer实现ExternalSignatureContainer{
公共空容器(){
}
公共字节[]符号(InputStream为){
ExternalDigest digest=hashAlgorithm1->DigestAlgorithms.getMessageDigest(hashAlgorithm1,null);
试一试{
byte[]hash=DigestAlgorithms.digest(即digest.getMessageDigest(“SHA256”);
thisHash=Hex.encodeHexString(哈希);
返回新字节[0];
}捕获(IOException |一般安全性异常e){
抛出新的运行时异常(e);
}
}
@凌驾
公共无效修改签名字典(PdfDictionary PdfDictionary){
pdfDictionary.put(PdfName.FILTER、PdfName.ADOBE_PPKMS);
pdfDictionary.put(PdfName.SUBFILTER,PdfName.ADBE_PKCS7_分离);
}
}
公共静态字符串emptySignature(字符串src、字符串dest、字符串字段名、证书[]链)引发IOException、DocumentException、GeneralSecurityException{
PdfReader读取器=新PdfReader(src);
FileOutputStream os=新的FileOutputStream(dest);
PdfStamper stamper=PdfStamper.createSignature(读卡器,操作系统,'\0');
Calendar cal=GregorianCalendar.getInstance();
计算添加(日历分钟,10);
PdfSignatureAppearance外观=母版。getSignatureAppearance();
外观。setVisibleSignature(新矩形(36748144780),1,字段名);
外观.setCertificate(链[0]);
外观。设置原因(“尼斯”);
外观。设置位置(“德里”);
外观。设置信号日期(cal);
ExternalSignatureContainer external=新的EmptyContainer();
MakeSignature.signExternalContainer(外观,外部,8192);
os.close();
reader.close();
返回此哈希;
}
公共静态证书getCert()抛出CertificateException{
String cert=”“;//我们从客户端获得的证书
ByteArrayInputStream userCertificate=新的ByteArrayInputStream(Base64.decodeBase64(cert));
CertificateFactory cf=CertificateFactory.getInstance(“X.509”);
返回cf.generateCertificate(用户证书);
}
私有静态外部摘要getDigest(){
返回新的ExternalDigest(){
public MessageDigest getMessageDigest(字符串哈希算法)
抛出一般安全性异常{
返回DigestAlgorithms.getMessageDigest(hashAlgorithm,null);
}
};
}
publicstaticvoidcreatesignature(stringsrc、stringdest、stringfieldname、byte[]签名)抛出IOException、DocumentException、GeneralSecurityException{
PdfReader读取器=新PdfReader(src);
FileOutputStream os=新的FileOutputStream(dest);
ExternalSignatureContainer external=新的MyExternalSignatureContainer(签名);
MakeSignature.signDeferred(读卡器、字段名、操作系统、外部);
reader.close();
os.close();
}
公共静态void main(字符串[]args)引发异常{
证书cert=getCert();
证书[]链={cert};
字符串src=“/home/spooderman/Downloads/sample.pdf”;
字符串between=“/tmp/sample\u out\u between.pdf”;
字符串dest=“/tmp/sample_out.pdf”;
字符串fieldName=“sign”;
字符串哈希=空签名(src、between、fieldName、chain);
String signature=“;//我们从客户端获得的签名哈希签名
字节[]signatureBytes=Hex.decodeHex(signature.tocharray());
PdfPKCS7 sgn=新的PdfPKCS7(null,链,“SHA256”,null,getDigest(),false);
sgn.setExternalDigest(signatureBytes,null,“RSA”);
byte[]data=sgn.getEncodedPKCS7(Hex.decodechex(hash.tocharray()),null,null,null,MakeSignature.CryptoStandard.CMS);
createSignature(介于、目的地、字段名、数据之间);
}
}
这是最新的

这是最新的

这是最新的

计算PDF的哈希值

954927c9286320e904920b0bf12f7cad387c1a9afd5a92314960a1083593f7dc
这是我从客户端收到的签名哈希签名

6c14b965c7e90c3134653a9261b0666dce7a7e28cb605fc3152ad111fa7915a77396799357daf1d37c52163ce6d34bfd96ee743e721b45e929f6d8aced144f094d03dce00f25c6c1fc5aa63c92322780f7de675c194ef17303a643055dbbedfec9d5200994fcdfc3ad9488d568ad3f6cd2d262e360a79ad90b5ffb188723de559f3696dcb223930f842172e4838f7d5e6a44494ced54bca54ed12133ea189d616a10039a222ce61885ad98b8ba0bd83d63b887e2c188ca10bd2f53f92f08c5585b9826553280c19976a0ba29f7789ad6a80010b4a6431d3b6bb8f27999b23d3739de03db6db8ab46acaf38b33bd37a74465744c3f95a093deff26cb44b45e27e
我在stackoverflow上做了很多尝试,但问题仍然是一样的。任何正确方向上的帮助都将不胜感激


对于我正在使用的客户端部分,它使本地USB令牌和HSM模块可供JS客户端使用。

问题在于
EmptyContainer.sign
方法只提供