我使用iTextPdf对PDF进行签名和完整性检查,由Alfresco提供
这是签名代码:
public void signItem(NodeRef itemToSign, String signer) {
try{
// retrieving user's public and private key
Certificate chain[] = getCertificate(signer);
PrivateKey pk = getPrivateKey(signer);
String digestAlgorithm = DigestAlgorithms.SHA512;
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
// Getting content of item to sign
InputStream originalInputStream = getNodeRefInputStream(itemToSign);
PdfReader pdfReader = new PdfReader(originalInputStream);
// get an outputStream on the item to sign nodeRef and give to the
// pdfStamper
ByteArrayOutputStream outputStream = getNodeRefOutputStream(itemToSign);
// logger.info("Before" + outputStream);
PdfStamper pdfStamper = PdfStamper.createSignature(pdfReader, outputStream, '\0', new File("temp"), true);
// Creating the appearance
PdfSignatureAppearance appearance = pdfStamper.getSignatureAppearance();
appearance.setReason("freeze");
appearance.setLocation("koosserydesk");
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "signature space");
// the sign document is subject to future approval signatures
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_FORM_FILLING);
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider.getName());
// signing...
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, CryptoStandard.CMS);
// get the signed input stream
InputStream signedInputStream = new ByteArrayInputStream(outputStream.toByteArray());
// replace the itemToSign content with the signed content
ContentWriter writer = getWriter(itemToSign);
writer.putContent(signedInputStream);
} catch (Exception e) {
// do something
}
}
这是完整性检查的代码
public void checkDocIntegrity(NodeRef itemToSign) throws KoosseryDeskServerException {
/** check the integrity of the document **/
ArrayList<String> signatureNames;
PdfPKCS7 pkcs7;
boolean result = false;
try {
InputStream is = getNodeRefInputStream(itemToSign);
PdfReader reader = new PdfReader(is);
AcroFields fields = reader.getAcroFields();
signatureNames = fields.getSignatureNames();
String name = signatureNames.get(0);
System.out.println("Siganture names = " + signatureNames);
System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());
pkcs7 = fields.verifySignature(name);
result = pkcs7.verify();
System.out.println("Is the document integrity check OK? : "+result);
} catch (Exception e) {
// do something
}
}
当我对使用上述signItem函数签名的文档运行完整性检查时,我始终获取此输出:
Siganture names = [signature space]
Document revision: 1 of 2
Is the document integrity check OK? : false
我认为完整性检查总是错误的,因为在贴上签名后添加了第二个第二个修订版,但是: 我不知道为什么我得到了两个文件修订版,但我没有添加任何注释或其他批准签名。
请告诉我,我做错了什么? 谢谢!
答案 0 :(得分:3)
看起来您的方法getNodeRefOutputStream
会返回ByteArrayOutputStream
已包含原始文档的副本,或者您的方法getWriter
返回{em>将追加添加到现有内容而不是替换。{/ 1>
结果是最终结果文件是(A)原始文件和(B)原始文件加签名的串联。
要解决此问题,请更改或替换错误的方法调用,以返回一个有效用压模输出替换原始内容的对象。
分析你的PDF很快就会发现它有点破碎,而不是预期的两个版本(首先是原始PDF,然后是为签名创建的附加内容)它实际上由组成三个部分(首先是原始PDF,然后再是原始PDF,然后创建用于使用交叉引用对其进行签名的添加内容,就好像原始部分在前面但只有一次)。
效果是
(您可能需要阅读信息安全堆栈交换中的this answer以了解详细信息。)
对于iText类,这种行为闻所未闻。因此,它似乎是由您的代码引起的。
查看您发布的代码,原始文档的重复很可能是由于您的代码
ContentWriter
返回的ByteArrayOutputStream
(如果该流初始化为原始文档的副本)或getNodeRefOutputStream
返回的ContentWriter
(如果该类的getWriter
方法实际附加到现有内容中)。因此,我建议不要将putContent
设置为outputStream
返回的ByteArrayOutputStream
,以将getNodeRefOutputStream
设置为空outputStream
;如果这没有帮助,我建议寻找new ByteArrayOutputStream()
或getWriter
的替代方案。