2

我想从第三方时间服务器向文件添加时间戳。当 pdf 在 acrobat 或其他 pdf 查看器中打开时,我想查看有关签名卡或任何其他中时间戳的信息。此外,我想以图形方式将时间戳可视化为带有时间戳的 pdf 中的图像或文本。

我从时间服务器获取令牌:

import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;

...

public TimeStampToken getTimeStampToken(){

  ...

  return response.getTimeStampToken();
}

现在如何使用 pdf 框为 pdf 添加时间戳?

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;

...

public static void addTimeStamp(final File pdfFile, final File signedPdfFile, TimeStampToken token) {

    try (
        FileInputStream fis1 = new FileInputStream(pdfFile);
        FileOutputStream fos = new FileOutputStream(signedPdfFile);
        FileInputStream fis = new FileInputStream(signedPdfFile);
        PDDocument doc = PDDocument.load(pdfFile)) {
        int readCount;
        final byte[] buffer = new byte[8 * 1024];
        while ((readCount = fis1.read(buffer)) != -1) {
            fos.write(buffer, 0, readCount);
        }

        final PDSignature signature = new PDSignature();
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName("NAME");
        signature.setLocation("LOCATION");
        signature.setReason("REASON");
        signature.setSignDate(Calendar.getInstance());

        doc.addSignature(signature);
        doc.saveIncremental(fos);
    } catch (final Exception e) {
        e.printStackTrace();
    }
}
4

2 回答 2

1

正如您刚刚提到的时间戳,而不是带有签名时间戳的签名,我假设您的意思是根据 PAdES LTV 或 PDF-2 的文档时间戳。

PDFBox 签名示例在实现时考虑了常规数字签名,而不是裸数字时间戳。但是你可以很容易地适应它们。CreateVisibleSignature和其他示例创建签名字节以嵌入在父类中实现的SignatureInterface方法中:signCreateSignatureBase

/**
 * SignatureInterface implementation.
 *
 * This method will be called from inside of the pdfbox and create the PKCS #7 signature.
 * The given InputStream contains the bytes that are given by the byte range.
 *
 * This method is for internal use only.
 *
 * Use your favorite cryptographic library to implement PKCS #7 signature creation.
 */
@Override
public byte[] sign(InputStream content) throws IOException
{
    //TODO this method should be private
    try
    {
        List<Certificate> certList = new ArrayList<Certificate>();
        certList.add(certificate);
        Store certs = new JcaCertStore(certList);
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
        ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
        gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
        gen.addCertificates(certs);
        CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
        CMSSignedData signedData = gen.generate(msg, false);
        if (tsaClient != null)
        {
            signedData = signTimeStamps(signedData);
        }
        return signedData.getEncoded();
    }
    catch (GeneralSecurityException e)
    {
        throw new IOException(e);
    }
    catch (CMSException e)
    {
        throw new IOException(e);
    }
    catch (TSPException e)
    {
        throw new IOException(e);
    }
    catch (OperatorCreationException e)
    {
        throw new IOException(e);
    }
}

创建签名库

(顺便说一句,我强烈不同意 TODO 评论。)

此外,CreateVisibleSignature在 中设置签名的子过滤器signPDF

/**
 * Sign pdf file and create new file that ends with "_signed.pdf".
 *
 * @param inputFile The source pdf document file.
 * @param signedFile The file to be signed.
 * @param tsaClient optional TSA client
 * @param signatureFieldName optional name of an existing (unsigned) signature field
 * @throws IOException
 */
public void signPDF(File inputFile, File signedFile, TSAClient tsaClient, String signatureFieldName) throws IOException
{
    [...]

    PDSignature signature;

    // sign a PDF with an existing empty signature, as created by the CreateEmptySignatureForm example. 
    signature = findExistingSignature(doc, signatureFieldName);

    if (signature == null)
    {
        // create signature dictionary
        signature = new PDSignature();
    }

    // default filter
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);

    // subfilter for basic and PAdES Part 2 signatures
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

    [...]
}

要创建 PAdES 文档时间戳,您可以简单地创建示例的副本,使用返回给定数据的时间戳令牌的实现CreateVisibleSignature覆盖该SignatureInterface方法,替换该行signInputStream

    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

signPDF

    signature.setSubFilter(new COSName("ETSI.RFC3161"));

并添加一行

    signature.setType(new COSName("DocTimeStamp"));

将类型设置为时间戳。

于 2017-01-19T08:35:37.987 回答
0

我想在没有密钥库证书和密钥的情况下向 pdf 添加时间戳,它看起来像这样:

public static void signWithTimeStampToken() throws InvalidPasswordException, NoSuchAlgorithmException, IOException, TSPException {
    final File inFile = new File("test.pdf");
    final File outFile = new File("test_signed.pdf");
    final MessageDigest digest = MessageDigest.getInstance("SHA-1");
    final TSAClient tsaClient = new TSAClient(new URL("your service"), null, null, digest);
    PdfTimeStampUtils.signPdf(inFile, outFile, tsaClient);
}

private static void signPdf(final File inFile, final File outFile, final TSAClient tsaClient) throws InvalidPasswordException, IOException, NoSuchAlgorithmException,
        TSPException {
    final PDSignature signature = new PDSignature();
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(COSName.getPDFName("ETSI.RFC3161"));
    signature.setSignDate(Calendar.getInstance());
    final PDDocument pdf = PDDocument.load(inFile);

    final TimestampSignatureImpl sig = new TimestampSignatureImpl(tsaClient);
    pdf.addSignature(signature, sig);
    pdf.saveIncremental(new FileOutputStream(outFile));
    pdf.close();
}

我正在使用 pdfbox 示例TSAClient 中的tsaclient

当我在 acrobat 中打开签名的 pdf 时,我可以在签名中看到:

在此处输入图像描述

于 2017-01-19T09:31:46.960 回答