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.
| Value | Filter | Key | Notes |
|---|---|---|---|
model.RC4_128bit | V2 | 128-bit RC4 | The default, since it is the zero value of EncryptionAlgorithm. Widest viewer support, weakest cipher. Handler V2/R3. |
model.AES_128bit | AESV2 | 128-bit AES | Handler V4/R4. Requires a PDF 1.5 or later reader. |
model.AES_256bit | AESV3 | 256-bit AES | Handler 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.pdfIf this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.