【发布时间】:2020-07-09 11:20:39
【问题描述】:
我在原始 PDF 中集成了签名哈希,但签名的有效性仍然存在错误。据说签名后pdf已更改。
以下步骤:我计算哈希值,然后将其发送给签名,最后得到哈希符号,然后继续在原始 pdf 中进行集成
package com.example.hashdocument;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;
import com.lexpersona.commons.utils.ProcessLauncher;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;
public class Test2 {
private static final String SRC = "B:/Hash-et-Reconstitution/tmp/Doc_test.pdf";
private static final String DST = "B:/Hash-et-Reconstitution/tmp/Doc_test_DST.pdf";
private static final String HASH = "B:/Hash-et-Reconstitution/tmp/Doc_test_hashed.hash";
private static final String PATH_BAT = "C:/Repo_LP7/lpcommand.bat";
private static final String PIN = "123456";
private static final String CERTIFICATE = "C:/lp7command/tools/certificate.p12";
private static final String SIGNED_HASH = "B:/Hash-et-Reconstitution/tmp/doc_signed.hash";
private static byte[] readFileToByteArray(File file){
FileInputStream fis = null;
byte[] bArray = new byte[(int) file.length()];
try{
fis = new FileInputStream(file);
fis.read(bArray);
fis.close();
}catch(IOException ioExp){
ioExp.printStackTrace();
}
return bArray;
}
public static File bytesToFile(byte[] fileByte,String pathFile) {
File file = new File(pathFile);
try {
OutputStream os = new FileOutputStream(file);
os.write(fileByte);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
public static byte[] signDocument() throws IOException {
ProcessLauncher p = new ProcessLauncher(System.out, System.err);
int exec;
exec = p.exec("cmd.exe /c "+PATH_BAT+" <nul "+ SIGNED_HASH +" "+ PIN+" "
+ HASH+" "+CERTIFICATE, null, null);
byte[] signedHash = readFileToByteArray(new File(SIGNED_HASH));
return signedHash;
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
PdfSignatureAppearance appearance = null;
ByteArrayOutputStream os = null;
String hash_document = "";
InputStream data = null;
int contentEstimated = 8192;
PdfReader reader = new PdfReader(SRC);
reader.unethicalreading = true;
reader.setAppendable(true);
int pdfPagenumber = 1;
pdfPagenumber = reader.getNumberOfPages(); // Sign on last page
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("Signature de contrat");
appearance.setLocation("MAROC");
appearance.setImage(null);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
Rectangle rect = new Rectangle(300, 300, 20, 20);
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
hash_document = new String(documentHash, "UTF-8");
System.out.println("Document Hash :"+hash_document);
PrintStream out = new PrintStream(new FileOutputStream(HASH));
out.print(hash_document);
byte[] hashdocumentByte = signDocument();
//////////////////// ADD SIGNED BYTES/HASH TO PDF DOCUMENT.
int contentEstimated2 = 8192;
byte[] paddedSig = new byte[contentEstimated2];
byte[] signedDocByte = hashdocumentByte;
System.arraycopy(signedDocByte, 0, paddedSig, 0, signedDocByte.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
appearance.close(dic2);
try(OutputStream outputStream = new FileOutputStream(DST)) {
os.writeTo(outputStream);
}
os.close();
}
}
【问题讨论】:
-
请分享一份您签名的 PDF 文件以供分析。
-
稍微检查了 PDF 我认为 CMS 签名容器本身是可以的,它只是签署了一个与文档的签名字节范围的散列不同的散列。您共享的文档是否还有
System.out.println("Document Hash :"+hash_document);的输出?或者您能否使用您的代码创建另一个签名文档并共享程序输出? -
感谢您的帮助。这里是签署哈希:文件哈希:79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb这是签约函数的输出符号前:哈希标志:79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb最后是这样的签名文档:drive.google.com/file/d/1bYlc1NAbIQMcoj252rOnTfNS0ZC8BQG1/… SPAN>
-
您的输出
79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb是正确的。但是您的签名容器会签名A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B。因此,问题不在于您显示的代码,而显然在signDocument()中,它似乎没有对您计算的哈希值进行签名。
标签: hash itext digital-signature