简体   繁体   中英

Lock pdf using iText

I recently tried to move to iText7, but I have some issues. I already have a PDF and I am trying to lock and restrict permissions on this PDF. I used the same approach with itext5, but the result is not the same. To be more precise:

  1. I used

     PdfWriter writer = new PdfWriter(fos, new WriterProperties() .setPublicKeyEncryption(chain, new int[EncryptionConstants.ALLOW_DEGRADED_PRINTING], EncryptionConstants.ENCRYPTION_AES_256)); 

but nothing happened, then I tried

2.

PdfWriter writer = new PdfWriter(fos, new WriterProperties()
            .setStandardEncryption("lala".getBytes(), "lala".getBytes(),
             EncryptionConstants.ALLOW_PRINTING | EncryptionConstants.ENCRYPTION_AES_256,
                    EncryptionConstants.ENCRYPTION_AES_256));

nothing happened again. Do you happen to know something about it ?

Full code of the method:

 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);
        }
    }

Now it is signed, it has watermark, but it is not locked (ie to copy the content)

Signing and encryption in iText 7 currently is done in two separate steps, in the first step the file is encrypted and in the second step this encrypted file is signed keeping encryption intact.

In your attempt you created a PdfWriter with the encryption information and a PdfSigner with the signing information. As your PdfWriter is not used by any PdfDocument , though, the encryption information are lost, only the signing takes place.

To both encrypt and sign, simply first encrypt the PDF, eg using something like

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();
}

(an EncryptAndSign method)

and then sign this encrypted PDF, eg using something like

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);
}

(an EncryptAndSign method)

with pk and chain determined like in your code.

Then combine these methods, eg like this

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 )

or if you want to write to a Response and don't want intermediary files in the file system:

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM