使用iText锁定pdf

时间:2018-04-12 07:09:48

标签: java pdf itext7

我最近尝试转移到iText7,但我遇到了一些问题。我已经有了PDF,我正在尝试锁定和限制对此PDF的权限。我使用与itext5相同的方法,但结果不一样。更确切地说:

  1. 我用过

    PdfWriter writer = new PdfWriter(fos, new WriterProperties()
            .setPublicKeyEncryption(chain,
            new int[EncryptionConstants.ALLOW_DEGRADED_PRINTING],
            EncryptionConstants.ENCRYPTION_AES_256));
    
  2. 但什么都没发生,然后我试过

    2

    PdfWriter writer = new PdfWriter(fos, new WriterProperties()
                .setStandardEncryption("lala".getBytes(), "lala".getBytes(),
                 EncryptionConstants.ALLOW_PRINTING | EncryptionConstants.ENCRYPTION_AES_256,
                        EncryptionConstants.ENCRYPTION_AES_256));
    
    再没有发生任何事。你碰巧知道一些事情吗?

    方法的完整代码:

     public void signPDF(InputStream inputStream, HttpServletResponse response) {
            LOG.debug("Inside signPDF...");
            Security.addProvider(new BouncyCastleProvider());
            try(OutputStream os = response.getOutputStream();
                PdfReader reader = new PdfReader(inputStream);
                PdfWriter writer = new PdfWriter(os, new WriterProperties().setStandardEncryption(null, "test".getBytes(), EncryptionConstants.ALLOW_PRINTING,
                        EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA))) {
                KeyStore ks = KeyStore.getInstance("pkcs12");
                ks.load(new FileInputStream(p12Path), keystorePassword.toCharArray());
                String alias = ks.aliases().nextElement();
                PrivateKey pk = (PrivateKey) ks.getKey(alias, keystorePassword.toCharArray());
                Certificate[] chain = ks.getCertificateChain(alias);
                BouncyCastleProvider provider = new BouncyCastleProvider();
                ITSAClient tsc = new TSAClientBouncyCastle(tsaClient, "", "");
                PdfSigner signer = new PdfSigner(reader, writer.getOutputStream(), true);
                PdfSignatureAppearance appearance = signer.getSignatureAppearance()
                        .setReason("Sign")
                        .setLocation("Test")
                        .setReuseAppearance(false);
                signer.setFieldName("sig");
                IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider.getName());
                IExternalDigest digest = new BouncyCastleDigest();
                System.out.println(signer.getDocument().getNumberOfPages());
                addWatermark(appearance,signer);
                signer.signDetached(digest, pks, chain, null, null, tsc, 0, PdfSigner.CryptoStandard.CMS);
    
            } catch (Exception e) {
                LOG.error("Error while writing to outputstream",e);
            }
        }
    

    现在它已签名,它有水印,但它没有被锁定(即复制内容)

1 个答案:

答案 0 :(得分:2)

iText 7中的签名和加密目前分两个步骤完成,第一步是加密文件,第二步加密文件,签名保持加密完好。

在您的尝试中,您创建了一个包含加密信息的PdfWriter和一个包含签名信息的PdfSigner。由于任何PdfWriter都未使用PdfDocument,因此加密信息会丢失,只会进行签名。

要加密和签名,只需先加密PDF,例如使用像

这样的东西
void encrypt(InputStream source, OutputStream target, byte[] password) throws IOException {
    PdfReader reader = new PdfReader(source);
    PdfWriter writer = new PdfWriter(target, new WriterProperties().setStandardEncryption(null, password,
            EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA));
    new PdfDocument(reader, writer).close();
}

EncryptAndSign方法)

然后签署此加密的PDF,例如使用像

这样的东西
void sign(InputStream original, OutputStream result, String name, CryptoStandard subfilter,
        int certificationLevel, boolean isAppendMode, byte[] password) throws IOException, GeneralSecurityException {
    String reason = "Just another illusionary reason";
    String location = "Right around the corner";
    boolean setReuseAppearance = false;
    String digestAlgorithm = "SHA512";
    ITSAClient tsc = null;

    PdfReader reader = new PdfReader(original, new ReaderProperties().setPassword(password));
    PdfSigner signer = new PdfSigner(reader, result, isAppendMode);

    signer.setCertificationLevel(certificationLevel);

    // Creating the appearance
    signer.getSignatureAppearance()
          .setReason(reason)
          .setLocation(location)
          .setReuseAppearance(setReuseAppearance);

    signer.setFieldName(name);

    // Creating the signature
    IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
    signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, tsc, 0, subfilter);
}

EncryptAndSign方法)

pkchain与您的代码一样确定。

然后组合这些方法,例如像这样

try (   InputStream resourceStream = ...;
        OutputStream encryptedResult = new FileOutputStream(encryptedFile)  ) {
    encrypt(resourceStream, encryptedResult, password);
}

try (   InputStream encryptedSource = new FileInputStream(encryptedFile);
        OutputStream signedResult = new FileOutputStream(signedFile)) {
    sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}

EncryptAndSign test testEncryptAndSignLefterisBab

或者如果您想写入响应并且不希望文件系统中的中间文件:

byte[] encrypted = null;

try (   InputStream resourceStream = ...;
        OutputStream encryptedResult = new ByteArrayOutputStream()  ) {
    encrypt(resourceStream, encryptedResult, password);
    encrypted = encryptedResult.toByteArray();
}

try (   InputStream encryptedSource = new ByteArrayInputStream(encrypted);
        OutputStream signedResult = response.getOutputStream()   ) {
    sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}