Java 是否可以使用哈希和签名哈希对PDF文档进行签名?
我可以使用带有外部签名的itextpdf库对文档进行签名 但问题是最终用户不想发送他的文档,因为它可能包含任何敏感数据。因此,我要求最终用户提供文档哈希,以便使用外部服务对哈希进行签名,并将签名后的哈希发送回 但是,问题来了,当他们试图使用itextpdf(Java 是否可以使用哈希和签名哈希对PDF文档进行签名?,java,pdf,itext,Java,Pdf,Itext,我可以使用带有外部签名的itextpdf库对文档进行签名 但问题是最终用户不想发送他的文档,因为它可能包含任何敏感数据。因此,我要求最终用户提供文档哈希,以便使用外部服务对哈希进行签名,并将签名后的哈希发送回 但是,问题来了,当他们试图使用itextpdf(PdfSignatureAppearance)使用给定的签名哈希对文档进行签名时,PDF文档正在被签名。但在验证签名时,它表明签名无效 我在这里也看到过类似的问题 因此,出现这个问题是因为每次使用PdfSignatureAppearance
PdfSignatureAppearance
)使用给定的签名哈希对文档进行签名时,PDF文档正在被签名。但在验证签名时,它表明签名无效
我在这里也看到过类似的问题
因此,出现这个问题是因为每次使用PdfSignatureAppearance
(itextpdf库)打开文档时,哈希都会失效
有谁能告诉我,是否可以使用itextpdf库使用先前生成的哈希和已签名的哈希(我从外部服务获得)对PDF文档进行签名,以便哈希不会失效?我猜如果您直接使用SHA512之类的东西对PDF的字节进行哈希,除非PDF内容发生更改,否则哈希值应始终保持不变。仅对文档字节进行签名是不够的。某些属性也需要签名。您的最终客户不应该在不使用iText的情况下创建哈希。@StoneBird评论的另一个补充是,你不能仅仅散列整个文档。你必须在PDF文件中留下一个“洞”来放置签名。很明显,除了签名本身,PDF中的每个字节都应该签名。@Harish cf.对于PDF签名的某些背景。延迟签名无法工作,您没有将授权字节用于哈希[链接]
class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
protected Certificate[] chain;
protected PrivateKey pk;
public MyExternalSignatureContainer(byte[] sig,Certificate[] chain,PrivateKey pk) {
this.sig = sig;
this.chain=chain;
this.pk=pk;
}
public byte[] sign(InputStream is)throws GeneralSecurityException {
return sig;
}
public void modifySigningDictionary(PdfDictionary signDic) {
}
}
public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
return hash;
}
public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");
//return extSignature;
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.sign(sh);
System.out.println(signature.getEncryptionAlgorithm());
// Calendar cal = Calendar.getInstance();
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
}
public void createSignature(String src, String dest, String fieldname,byte[] hash, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
ExternalSignatureContainer external = new MyExternalSignatureContainer(hash,chain,pk);
MakeSignature.signDeferred(reader, fieldname, os, external);
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", chain);
byte[] hh_sign = (app.signed_hash(hh, pk, chain));
app.createSignature(TEMP, DEST1, "sig1",hh_sign, pk, chain);
}