public void write(PDDocument doc, SignatureInterface signInterface) throws IOException {
        long idTime =
                doc.getDocumentId() == null ? System.currentTimeMillis() : doc.getDocumentId();

        pdDocument = doc;
        signatureInterface = signInterface;

        if (incrementalUpdate) {
            prepareIncrement(doc);
        }

        // if the document says we should remove encryption, then we shouldn't encrypt
        if (doc.isAllSecurityToBeRemoved()) {
            willEncrypt = false;
            // also need to get rid of the "Encrypt" in the trailer so readers
            // don't try to decrypt a document which is not encrypted
            COSDocument cosDoc = doc.getDocument();
            COSDictionary trailer = cosDoc.getTrailer();
            trailer.removeItem(COSName.ENCRYPT);
        } else {
            if (pdDocument.getEncryption() != null) {
                if (!incrementalUpdate) {
                    SecurityHandler securityHandler =
                            pdDocument.getEncryption().getSecurityHandler();
                    if (!securityHandler.hasProtectionPolicy()) {
                        throw new IllegalStateException(
                                "PDF contains an encryption dictionary, please remove it with " +
                                        "setAllSecurityToBeRemoved() or set a protection policy with protect()");
                    }
                    securityHandler.prepareDocumentForEncryption(pdDocument);
                }
                willEncrypt = true;
            } else {
                willEncrypt = false;
            }
        }

        COSDocument cosDoc = pdDocument.getDocument();
        COSDictionary trailer = cosDoc.getTrailer();
        COSArray idArray;
        boolean missingID = true;
        COSBase base = trailer.getDictionaryObject(COSName.ID);
        if (base instanceof COSArray) {
            idArray = (COSArray) base;
            if (idArray.size() == 2) {
                missingID = false;
            }
        } else {
            idArray = new COSArray();
        }
        if (missingID || incrementalUpdate) {
            MessageDigest md5;
            try {
                md5 = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                // should never happen
                throw new RuntimeException(e);
            }

            // algorithm says to use time/path/size/values in doc to generate the id.
            // we don't have path or size, so do the best we can
            md5.update(Long.toString(idTime).getBytes(StandardCharsets.ISO_8859_1));

            COSDictionary info = trailer.getCOSDictionary(COSName.INFO);
            if (info != null) {
                for (COSBase cosBase : info.getValues()) {
                    md5.update(cosBase.toString().getBytes(StandardCharsets.ISO_8859_1));
                }
            }
            // reuse origin documentID if available as first value
            COSString firstID =
                    missingID ? new COSString(md5.digest()) : (COSString) idArray.get(0);
            // it's ok to use the same ID for the second part if the ID is created for the first time
            COSString secondID = missingID ? firstID : new COSString(md5.digest());
            idArray = new COSArray();
            idArray.add(firstID);
            idArray.add(secondID);
            trailer.setItem(COSName.ID, idArray);
        }
        cosDoc.accept(this);
    }
This will write the pdf document. If signature should be created externally,
{@link #writeExternalSignature(byte[])} should be invoked to set signature after calling this method.

@param doc           The document to write.
@param signInterface class to be used for signing; {@code null} if external signing would be performed
                     or there will be no signing at all
@throws IOException           If an error occurs while generating the data.
@throws IllegalStateException If the document has an encryption dictionary but no protection
                              policy.
tika-fuzzing/src/main/java/org/apache/tika/fuzzing/pdf/EvilCOSWriter.java