【发布时间】:2018-03-14 09:56:41
【问题描述】:
我有一个 pdf 文档,需要进行数字签名,并且签名由外部服务提供。在启动签名之前我没有证书链。我尝试了以下代码,但收到 SigDict/Contents 非法数据消息。
创建文档哈希的源并将其发布到外部服务以对其进行签名
InputStream data = null;
DocumentSignStatus documentSignStatus = new DocumentSignStatus();
int contentEstimated = 8192;
PdfReader reader = new PdfReader(requestParams.getDocumentToBeSigned());
try {
reader.unethicalreading = true;
int pdfPagenumber = 1;
if((Integer)requestParams.getSignPageNo() == null || requestParams.getSignPageNo()==0 ){
//pdfPagenumber = 1; // Default signature on first page.
pdfPagenumber = reader.getNumberOfPages(); // Sign on last page
}else {
pdfPagenumber = requestParams.getSignPageNo();
}
PdfSignatureAppearance appearance = null;
ByteArrayOutputStream os = null;
os = new ByteArrayOutputStream ();
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
Calendar cal = Calendar.getInstance();
appearance = stamper.getSignatureAppearance();
appearance.setSignDate(cal);
appearance.setAcro6Layers(false);
appearance.setReason("Test Signature");
appearance.setLocation("India");
appearance.setImage(null);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
Rectangle rect = requestParams.getRect();
appearance.setVisibleSignature(rect, pdfPagenumber, null);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(appearance.getReason());
dic.setLocation(appearance.getLocation());
dic.setContact(appearance.getContact());
dic.setDate(new PdfDate(appearance.getSignDate()));
appearance.setCryptoDictionary(dic);
appearance.preClose(exc);
data = appearance.getRangeStream();
MessageDigest messageDigest;
String provider = null;
String hashAlgorithm = DigestAlgorithms.SHA256;
if (provider == null){
messageDigest = MessageDigest.getInstance(hashAlgorithm);
}else {
messageDigest = MessageDigest.getInstance(hashAlgorithm,provider);
}
int read = 0;
byte[] buff = new byte[contentEstimated];
while ((read = data.read(buff, 0, contentEstimated)) > 0)
{
messageDigest.update(buff,0,read);
}
byte[] hashDigest = messageDigest.digest();
byte[] documentHash = org.bouncycastle.util.encoders.Hex.encode(hashDigest);
//eSign Start
String hashdocument = new String(documentHash, "UTF-8");
System.out.println("Document Hash :"+hashdocument);
//Generate Sign Request XML for external source to sign the document hash
String eSignXmlStr = esignXML.generateEsignXML20(hashdocument,requestParams.getAadhaarNo());
String eSignSignedXML = myXMLSigner.signXML(eSignXmlStr, true);
System.out.print("sign request xml: " + eSignSignedXML);
// sign request xml generation complete
documentSignStatus.setSignedXML(eSignSignedXML);
session.put("hashdocument", documentHash);
session.put("appearance", appearance);
session.put("baos", os);
}catch(Exception e) {
e.printStackTrace();
}
return documentSignStatus;
以下是将PKCS7响应附加到pdf以完成签名程序并获得签名的pdf的来源。
byte[] hashdocument = (byte[])session.get("hashdocument");
PdfSignatureAppearance appearance = (PdfSignatureAppearance)session.get("appearance");
ByteArrayOutputStream os = (ByteArrayOutputStream)session.get("baos");
//Get signed response xml
InputStream x = request.getInputStream();
String responseXML = IOUtils.toString(x, "UTF-8");
System.out.print("REsponse:" + responseXML);
//parse the xml and get pkcs7 data
String pkcs7asString = getPKCS7DataFromDigitalSignatureResponse(responseXML);
byte[] signedDocByte = org.bouncycastle.util.encoders.Base64.decode(pkcs7asString);
//////////////////// ADD SIGNED BYTES/HASH TO PDF DOCUMENT.
int contentEstimated = 8129;
byte[] paddedSig = new byte[contentEstimated];
System.arraycopy(signedDocByte, 0, paddedSig, 0, signedDocByte.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
try {
appearance.close(dic2);
} catch (DocumentException e) {
e.printStackTrace();
}
try(OutputStream outputStream = new FileOutputStream("/SignTest2.0.pdf")) {
os.writeTo(outputStream);
}
os.close();
getPKCS7DataFromDigitalSignatureResponse(responseXML) 方法用于解析外部服务响应,它返回一个 PKCS7 作为字符串。 我试图找出问题所在,但找不到根本原因。 任何人都可以帮助解决这个问题。使用 itext 版本 5.4.5 复制 od 签名文件是 PDF with Signature Problem
【问题讨论】:
-
您的代码看起来像是您将一些古老的签名样本作为模板。如果您使用的是 iText 5(而不是更新和积极开发的 iText 7),至少切换到可用的最新 5.5.x 版本。然后使用当前的签名 API。
-
@mkl 感谢您的建议,找到了根本原因,我使用错误的值填充字节数组 8219 而不是 8192。
标签: java itext digital-signature