6. Security: encryption & signatures
Encrypting documents and applying digital signatures.
PDF security comes in two distinct flavours, and they answer different questions. Encryption asks who may open this file and what may they do with it (it is about access control. Digital signatures ask who produced this exact byte stream and has it changed since), it is about authenticity and integrity. This chapter covers both, and the one rule that ties encryption to archival output.
Both features go through PdfDocumentRenderer and PdfSaveOptions, not the
one-line SavePdf extension: they need the options object.
Encryption and permissions
Section titled “Encryption and permissions”Encryption settings live on PdfSaveOptions.SecuritySettings, a
PdfSecuritySettings (namespace Rivoli.Pdf.Security):
using Rivoli.Pdf;using Rivoli.Pdf.Security;
var renderer = new PdfDocumentRenderer("1.7");renderer.RenderToFile(doc, "secure.pdf", new PdfSaveOptions{ SecuritySettings = new PdfSecuritySettings { UserPassword = "open-me", OwnerPassword = "owner-secret", Algorithm = PdfEncryptionAlgorithm.Aes256, Permissions = PdfPermissions.Print | PdfPermissions.CopyContents, EncryptMetadata = true, },});Two passwords, two roles
Section titled “Two passwords, two roles”PDF defines two passwords, and which ones you set changes the behaviour:
| Set… | Effect |
|---|---|
| Owner password only | Anyone can open it; permissions are enforced |
| User + owner password | The user password is required to open; permissions are enforced; the owner password lifts all restrictions |
The owner password is the master key: it bypasses the permission flags. The
user password gates opening. PdfSecuritySettings validates this for you:
encryption requires an owner password, both passwords cap at 127 characters, and
the user and owner passwords must differ (if they match, viewers treat it as
owner-only). Two factory helpers cover the common shapes:
// Open freely, but restrict what readers can do:var restricted = PdfSecuritySettings.CreateWithRestrictions( ownerPassword: "owner-secret", permissions: PdfPermissions.Print);
// Require a password to open at all:var locked = PdfSecuritySettings.CreatePasswordProtected( userPassword: "open-me", ownerPassword: "owner-secret", permissions: PdfPermissions.Print | PdfPermissions.ExtractForAccessibility);Algorithms
Section titled “Algorithms”PdfEncryptionAlgorithm selects the cipher:
| Value | Notes |
|---|---|
None | No encryption (the default for output without SecuritySettings) |
Aes128 | AES-128, broad viewer support (PDF 1.6+) |
Aes256 | AES-256, strongest; the default when you construct PdfSecuritySettings |
Match your PdfVersion to the algorithm: AES-256 wants a 1.7-class output.
Permissions
Section titled “Permissions”PdfPermissions is a [Flags] enum; combine the operations you want to allow.
Permissions are advisory: standard-compliant viewers honour them, but they are
not a hard cryptographic barrier on a determined user.
| Flag | Allows |
|---|---|
None | Nothing (most restrictive) |
Print | Printing |
PrintHighQuality | High-resolution printing |
ModifyContents | Editing page content |
CopyContents | Copying / extracting text and graphics |
ModifyAnnotations | Editing annotations and form fields |
FillForms | Filling form fields |
ExtractForAccessibility | Extraction for assistive technology |
AssembleDocument | Insert / rotate / delete pages |
All | Everything (least restrictive) |
Permissions = PdfPermissions.Print | PdfPermissions.PrintHighQuality | PdfPermissions.ExtractForAccessibility,EncryptMetadata
Section titled “EncryptMetadata”By default document metadata (title, author, …) stays in the clear so indexers
and search can read it. Set EncryptMetadata = true to encrypt it along with the
content.
Encryption is incompatible with PDF/A
Section titled “Encryption is incompatible with PDF/A”This is a hard rule, not a guideline: a PDF/A document may not be encrypted.
The archival profile forbids encryption outright, so Rivoli PDF refuses to produce
both at once. PdfSaveOptions.Validate() throws an InvalidOperationException
if you set a non-None PdfAMode together with SecuritySettings:
// This combination is rejected:new PdfSaveOptions{ PdfAMode = PdfAMode.PdfA1b, SecuritySettings = new PdfSecuritySettings { OwnerPassword = "x" },}.Validate(); // throws: disable one or the otherDecide up front: archival or encrypted, never both. PDF/A is covered in chapter 7.
Digital signatures
Section titled “Digital signatures”Signing is a distinct, post-render step. You render the document to a PDF, then
sign that file: signatures are applied as an incremental update so the original
bytes are preserved and covered by the signature’s byte range. The entry point is
PdfSigner (namespace Rivoli.Pdf.Signatures), driven by a
PdfSignatureInfo carrying your certificate and metadata:
using System.Security.Cryptography.X509Certificates;using Rivoli.Pdf.Signatures;
var cert = new X509Certificate2("signer.pfx", "cert-password");
var info = PdfSignatureInfo.Create(cert, reason: "I approve this document");info.Location = "London, UK";info.ContactInfo = "approvals@example.com";
var signer = new PdfSigner(info);signer.SignDocument("secure.pdf", "secure-signed.pdf");PdfSignatureInfo exposes Certificate, Reason, Location, ContactInfo,
FieldName, SigningTime, and IncludeCertificateChain; its Validate() runs
when you construct the PdfSigner. SignDocument has both file-path and
Stream overloads.
Visible signatures
Section titled “Visible signatures”PdfSigner fills a signature field you placed yourself. Declare a SignatureField
when building the document (see chapter 5), then name
it in PdfSignatureInfo.FieldName:
document.FormFields.Add(new SignatureField("ApproverSignature"){ Rect = new Rectangle(72, 96, 272, 160), PageIndex = 0});// ... render the document, then sign it:
var info = PdfSignatureInfo.Create(cert, reason: "Approved");info.FieldName = "ApproverSignature"; // fills the field you placednew PdfSigner(info).SignDocument("report.pdf", "report-signed.pdf");The field keeps its position, page, and appearance; signing only adds the signature
value. If FieldName names no existing field, an invisible signature field is created
with that name. If you leave FieldName null, the first free Signature{N} name is
used, so signing an already-signed document adds a second, distinctly named signature
rather than colliding with the first. Naming a field that is already signed throws.
- 7. PDF/A & accessibility: archival output, tagging, and why it excludes encryption.
- 5. Forms & interactivity: signature fields versus signing.