gpt4 book ai didi

java - 自签名应用 itext 5.5.11 以来,文档已被更改或损坏

转载 作者:行者123 更新时间:2023-12-04 16:38:04 25 4
gpt4 key购买 nike

基本上我收到错误文档已被更改或损坏自应用签名以来,我按照 itext 网站的示例并适应了我的情况。

  • 准备要签名的文档,添加append模式,因为可以一份已经签署的文件
  • 调用网络服务对哈希进行签名
  • 将签名哈希添加到准备好的文档中

我没有想法,希望能得到一些帮助这是我的代码片段:

    public static final String src = "DynamicClient\sample.pdf";
public static final String temp= "DynamicClient\sampleTEMP.pdf";
public static final String dest= "DynamicClient\sampleFINAL.pdf";

public static void emptySignatureSVC(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
reader.setAppendable(true);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0',null,true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(0, 0, 0, 0), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ETSI_CADES_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
reader.close();

}

public static void createSignatureSVC(String src, String dest, String fieldname, byte[] sign, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {

PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
ExternalSignatureContainer external = new MyExternalSignatureContainer(sign, chain);
MakeSignature.signDeferred(reader, fieldname, os, external);
}


public static void main(String[] args) throws Exception {

Certificate[] chain = signWS.getChain();//External WS to get chain
emptySignatureSVC(src, temp, "signature", chain);
InputStream is = new FileInputStream(new File(temp));
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest("SHA256"));
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CADES);

byte[] extSignature = signWS(sh);//External WS to sign
sgn.setExternalDigest(extSignature, null, "RSA");

createSignatureSVC(temp, dest, "signature", sgn.getEncodedPKCS7(hash,null, null, null, CryptoStandard.CADES), chain);
}

文件如下: original one Signed one

编辑:忘记添加我使用的容器:

class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
protected Certificate[] chain;
public MyExternalSignatureContainer(byte[] sig,Certificate[] chain) {
this.sig = sig;
this.chain=chain;
}
public byte[] sign(InputStream is)throws GeneralSecurityException {

return sig;

}

@Override
public void modifySigningDictionary(PdfDictionary signDic) {
// TODO Auto-generated method stub

}
}

最佳答案

您的代码中有两个问题:

  • 你散列了错误的数据并且
  • 您签名不正确。

散列错误的数据

您正在像这样散列整个准备好的 PDF:

InputStream is = new FileInputStream(new File(temp));
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest("SHA256"));

这是不正确的。

签名的 PDF 基本上具有这种结构(阅读 here 了解更多详情):

(顺便说一下,草图不是 100% 正确的,因为签名值周围的尖括号分隔符“<”和“>”也不能被散列。)

您在 temp 准备的 PDF 具有相同的结构,只是“签名值”还不是实际的签名值,而是一个 8192 十六进制编码零字节的占位符(8192 因为那是数字你给了 MakeSignature.signExternalContainer)。

但是,正如您在草图中看到的那样,签名值(或在您的情况下为占位符)不得经过哈希处理以进行签名。

您可以在 MakeSignature.signExternalContainer 之后使用 PdfSignatureAppearance.getRangeStream 返回的数据来计算散列,正如@LkbhaiLr 在 his answer 中所建议的那样.

或者,您可以使用(而不是 ExternalBlankSignatureContainer)自定义 ExternalSignatureContainer 实现,它在其 sign 方法中简单地散列其 InputStream 参数并提供该哈希值。

我更喜欢后一种方法,但前一种方法也被广泛使用。

签名不正确

您可以像这样检索裸签名值:

byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CADES);
byte[] extSignature = signWS(sh);//External WS to sign

即您将属性结构按原样转发给您的签名服务,并期望它为其创建适当的签名值。

正在检查您的 signed example file但是,很明显该签名服务没有达到您的期望:它不是使用 SHA256withRSA 进行签名,而只是使用 RSA 和 PKCS#1 填充进行加密。因此,它希望您为自己完成一半的签名,即使用 SHA256 进行散列并构建 DigestInfo 结构。

因此,在调用 signWS 之前,您必须对 sgn.getAuthenticatedAttributeBytes 返回的属性结构进行哈希处理,然后将生成的哈希值包装在 DigestInfo 中> 对象。

当您在别处计算哈希值时,这对您来说应该不是问题。并将散列包装在 DigestInfo RFC 8017 section 9.2 note 1 中提供捷径:

For the nine hash functions mentioned in Appendix B.1, the DER encoding T of the DigestInfo value is equal to the following:

...
SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H.
...

即您只需要在哈希值前加上字节序列 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20

关于java - 自签名应用 itext 5.5.11 以来,文档已被更改或损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66770181/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com