首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用pdfbox和TimeStampToken添加时间戳

如何使用pdfbox和TimeStampToken添加时间戳
EN

Stack Overflow用户
提问于 2017-01-19 14:49:46
回答 2查看 2.6K关注 0票数 2

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

我从时间服务器获取token:

代码语言:javascript
复制
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;

...

public TimeStampToken getTimeStampToken(){

  ...

  return response.getTimeStampToken();
}

现在如何使用pdf box将时间戳添加到pdf?

代码语言:javascript
复制
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();
    }
}
EN

Stack Overflow用户

发布于 2017-01-19 16:35:38

因为您只提到了时间戳,而不是带有签名时间戳的签名,所以我假设您是指按照PDF或PAdES -2的文档时间戳。

PDFBox签名示例的实现考虑到了常规的数字签名,而不是裸露的数字时间戳。但您可以相当容易地对它们进行调整。CreateVisibleSignature和其他示例创建要嵌入在父类CreateSignatureBase中实现的SignatureInterface方法sign中的签名字节

代码语言:javascript
复制
/**
 * 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-comment。)

此外,CreateVisibleSignaturesignPDF中设置签名的子过滤器

代码语言:javascript
复制
/**
 * 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示例的副本,用返回给定InputStream中数据的时间戳令牌的实现覆盖SignatureInterface方法sign,替换该行

代码语言:javascript
复制
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

signPDF中使用

代码语言:javascript
复制
    signature.setSubFilter(new COSName("ETSI.RFC3161"));

并添加一行

代码语言:javascript
复制
    signature.setType(new COSName("DocTimeStamp"));

要将类型设置为时间戳,请执行以下操作。

票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41735485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档