Skip to content

Protect PDF

PdfWriter.Encrypt encrypts the document you are about to write, taking a user password, an owner password and an EncryptOptions value that carries the permission bits and the algorithm. The two passwords play different roles: the user password is what a reader needs to open the file under the permissions you set, and the owner password grants full access including the right to change the passwords and permissions.

Leave the user password empty if anyone should be able to open the file and the point is only to declare restrictions. Set both and viewers will prompt before showing anything.

Choosing an algorithm

EncryptOptions.Algorithm takes one of three values.

ValueFilterKeyNotes
model.RC4_128bitV2128-bit RC4The default, since it is the zero value of EncryptionAlgorithm. Widest viewer support, weakest cipher. Handler V2/R3.
model.AES_128bitAESV2128-bit AESHandler V4/R4. Requires a PDF 1.5 or later reader.
model.AES_256bitAESV3256-bit AESHandler V5/R6. The strongest option and the one to use unless you have a reason not to.

RC4 being the default is a consequence of RC4_128bit being declared first in the iota block, so an EncryptOptions that sets only Permissions gets RC4. Set Algorithm explicitly. Anything other than these three values makes Encrypt return an “unsupported algorithm” error.

Encrypt also sets the output document version to the minimum the filter requires: 1.5 for AES-128 and 2.0 for AES-256. It sets rather than raises, so encrypting a PDF 1.7 file with AES-128 writes a 1.5 header. RC4 reports no minimum version and leaves the header alone.

Doing it

opts := &model.EncryptOptions{
    Permissions: security.PermPrinting | security.PermFullPrintQuality |
        security.PermDisabilityExtract,
    Algorithm: model.AES_256bit,
}

pdfWriter, err := pdfReader.ToWriter(nil)
if err != nil {
    return err
}

if err := pdfWriter.Encrypt([]byte(userPassword), []byte(ownerPassword), opts); err != nil {
    return err
}

return pdfWriter.WriteToFile(outputPath)

Passing nil for the options is legal and means security.PermOwner - every permission granted - with RC4-128.

The permission constants and what each one covers are listed in Check Permissions. Whatever you omit from the mask is withheld from anyone holding only the user password.

Encrypting an already encrypted file

Encrypt does not re-encrypt in place. The example bails out with “The PDF is already locked (need to unlock first)” when IsEncrypted reports true, because writing an encrypted source through a fresh writer requires the source to have been decrypted first. To change the password or permissions on a protected file, decrypt it as shown in Unlock PDF and encrypt the result.

Limitations

Permissions are advisory. A PDF viewer is expected to honor them, but nothing in the format prevents software from ignoring the bitmask once the document is open, and UniPDF itself will happily modify a document whose mask forbids modification. If content must stay out of someone’s hands, do not give them the file.

The owner password is the only real secret in a permissions-only setup. With an empty user password, anyone can open the document and any tool can strip the restrictions; the owner password just stops well-behaved viewers from offering to do it.

Encrypt must be called before Write or WriteToFile, since it installs the crypter the writer uses while serializing objects.

Run the example

The example ORs together every flag the security package defines, so out of the box it restricts nothing and the only real protection is the pair of passwords. Edit the permissions variable in protectPdf to drop the ones you want withheld.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/security
go run pdf_protect.go input.pdf <user-pass> <owner-pass> output.pdf

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on