【问题标题】:pdfbox - document has been altered or corrupted since it was signedpdfbox - 文档自签署以来已被更改或损坏
【发布时间】:2015-12-07 01:36:14
【问题描述】:

我正在使用pdfbox-1.8.8对PDF文件做签名功能。

当我签署文件时,我得到了

这是我的代码:

public void signDetached(String inputFilePath, String outputFilePath, String signatureImagePath, Sign signProperties) {
    OutputStream outputStream = null;
    InputStream inputStream = null;
    PDDocument document = null;
    InputStream signImageStream = null;

    try {
        setTsaClient(null);
        document = PDDocument.load(inputFilePath);
        // create signature dictionary
        PDSignature signature = new PDSignature();
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName("VANDUC1102");
        signature.setLocation(null);
        String displayName = "Hello World, Document signed by VANDUC1102";
        String reason = reasonText+ " " + displayName;
        signature.setReason(reason);

        // the signing date, needed for valid signature
        signature.setSignDate(Calendar.getInstance());            
        int signatureInPage = signProperties.getPageNumber() + 1;
        signImageStream = new FileInputStream(new File(signatureImagePath));
        PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(inputFilePath, signImageStream, signatureInPage);

        float xAxis = convertPixel2Point(signProperties.getX()) ;
        float yAxis = convertPixel2Point(signProperties.getY());               
        float signImageHeight = convertPixel2Point(signImageHeight);    
        float signImageWidth = convertPixel2Point(signImageWidth);

        visibleSig.xAxis(xAxis)
                .yAxis(yAxis)
                .zoom(0)
                .signatureFieldName("Signature")
                .height(signImageHeight)
                .width(signImageWidth);
        PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();

        signatureProperties.signerName(eiUser.getName())
                 .signerLocation(null)
                 .signatureReason(reason)
                 .preferredSize(0)
                 .page(signProperties.getPageNumber())
                 .visualSignEnabled(true)
                 .setPdVisibleSignature(visibleSig)
                 .buildSignature();
         // register signature dictionary and sign interface
        SignatureOptions signatureOptions = new SignatureOptions();
        signatureOptions.setVisualSignature(signatureProperties);
        signatureOptions.setPage(signatureInPage);
        document.addSignature(signature, this, signatureOptions);

        File outputFile = new File(outputFilePath);
        outputStream = new FileOutputStream(outputFile);
        inputStream = new FileInputStream(inputFilePath);
        IOUtils.copyStream(inputStream, outputStream);
        document.saveIncremental(inputStream, outputStream);
        outputStream.flush();
    } catch (COSVisitorException | SignatureException | IOException ex) {
        log.error("signDetached ", ex);
    } finally {
        IOUtils.closeStream(outputStream);
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(signImageStream);
        IOUtils.closeStream(document);
    }
}
private float convertPixel2Point(float pixel){
    return pixel * (float) 72/96;
}

所以,我这个问题是因为我使用了自签名证书或我的代码有问题。

这里是sample file的链接。

谢谢

【问题讨论】:

  • 请分享一个签名的 PDF 样本以供检查。
  • 1.8.10 或 2.0 RC2 是否仍然存在问题?使用示例代码?我可以测试自己,但我还需要未签名的 PDF。
  • 我意识到我根本不需要未签名的 PDF,我可以从已签名的文件中创建那个。我刚刚用普通示例进行了测试,它工作正常(在 2.0 RC2 中)。
  • 是的。我测试了 2.0RC2 版本。成功了,谢谢@TilmanHauserr

标签: java pdf pdfbox self-signed


【解决方案1】:

分析损坏的签名 PDF

我刚刚查看了您的示例 PDF。结构上看起来没问题,只是签名中给出的数据哈希值

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

与有符号字节范围的实际哈希值不匹配

4f48eab20d340957bd5693104af097ed7363bd84181a6a1c834c138c1376cbe3

因此,要么文件确实在事后被操纵,要么签名过程中的哈希计算已经出错。

由于您的示例代码不是独立的 - 它似乎依赖于作为提供附加方法和实现某些接口的类的一部分 - 我无法检查它是哪一个。

原因

在 OP 在评论中指出他构建代码的示例是 CreateVisibleSignature.java 之后,我可以重现该问题(参见 SignLikeVanduc1102 测试方法 testCorruptOriginal),并将他的代码与原始代码进行比较,原因很快就变得明显了:他在PDDocument.saveIncremental(InputStream, OutputStream) 调用中使用了错误的InputStream 参数:

File outputFile = new File(outputFilePath);
outputStream = new FileOutputStream(outputFile);
inputStream = new FileInputStream(inputFilePath);
IOUtils.copyStream(inputStream, outputStream);
document.saveIncremental(inputStream, outputStream);

inputStream

  • 在前面的IOUtils.copyStream 调用过程中已经读过并且
  • 毕竟是错误的:它只指原始 PDF,但 saveIncremental 需要 InputStream 指的是带有原始 PDF 加上新的带有签名的修订版的 PDF。

因此,可以这样解决:

File outputFile = new File(outputFilePath);
outputStream = new FileOutputStream(outputFile);
inputStream = new FileInputStream(inputFilePath);
IOUtils.copyStream(inputStream, outputStream);
IOUtils.closeStream(inputStream);
inputStream = new FileInputStream(outputFile);
document.saveIncremental(inputStream, outputStream);

(另见SignLikeVanduc1102测试方法testCorruptFixed。)

这对应于原始PDFBox示例代码:

File outputDocument = new File(document.getParent(), substring + "_signed.pdf");
FileInputStream fis = new FileInputStream(document);
FileOutputStream fos = new FileOutputStream(outputDocument);

int c;
while ((c = fis.read(buffer)) != -1) {
  fos.write(buffer, 0, c);
}
fis.close();
fis = new FileInputStream(outputDocument); 

OP 声明使用 PDFBox 2.0 他的代码有效。这很可能是由于增量保存调用已更改,它不再具有 inputStream 参数。

【讨论】:

  • 谢谢@mkl,我是 PDF 文件结构的新手,你能给我一些文件来了解 PDF 文件结构、PDF 文件的签署者的工作方式或关于你检查我的文件的方式的更多细节。
  • 您可能还对this answer 以及从那里引用的文档感兴趣。
  • @mkl 我用来签名的代码跟在PDFBox的example后面
  • @mkl ,我使用的是 2.0 RC2 版本,它成功了,谢谢
  • @vanduc1102 我无法清楚地确定哪个 PDFBox 示例类是您的测试的基类。但显然您的链接指向示例 trunk 版本,该版本正朝着 2.0.0 发展。如果您在最初尝试使用 PDFBox 1.8.8 时确实使用了它们,那么出现问题也就不足为奇了……2.0.0-RC2 中的 API 与 1.x API 有很大不同,甚至与 1.8 也不同。 x API。
猜你喜欢
  • 2021-02-22
  • 2021-06-20
  • 1970-01-01
  • 2016-09-16
  • 2018-12-04
  • 2021-05-11
  • 2023-04-03
  • 2021-11-06
  • 1970-01-01
相关资源
最近更新 更多