pdfbox - 文档自签名后已被更改或损坏

时间:2015-12-07 01:36:14

标签: java pdf pdfbox self-signed

我正在使用 pdfbox-1.8.8 在PDF文件上执行签名功能。

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

enter image description here

这是我的代码:

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

的链接

由于

1 个答案:

答案 0 :(得分:3)

分析损坏的签名PDF

我刚看了一下你的样本PDF。在结构上看起来没问题,只是签名中给出的数据哈希值

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

与签名字节范围的实际哈希值不匹配

4f48eab20d340957bd5693104af097ed7363bd84181a6a1c834c138c1376cbe3

因此,事实上文件已被操纵,或者在签名过程中的哈希计算已经做错了。

由于您的示例代码不是自包含的 - 它似乎依赖于提供其他方法和实现某些接口的类的一部分 - 我无法检查它是哪一个。

原因

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

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参数。