§HOW-TO GUIDE · C# · .NET 8 & 10

Password-protect a PDF with AES-256 in C#

Setting a user password on a PdfDocument is enough to encrypt it: SelectPdf.Universal uses AES with a 256-bit key (revision 6 of the PDF security handler) by default. An owner password adds permissions such as no printing or no copying.

Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64

Video walkthrough · 3:27 · Watch on YouTube · Short · 0:56
§STEP BY STEP

Build it step by step.

  1. 1Install the NuGet packages

    SelectPdf.Universal is the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.

    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.win-x64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.linux-x64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.linux-arm64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.osx-arm64
  2. 2Create a console app

    Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace Program.cs with the code below.

    terminal
    dotnet new console -n PdfSample
    cd PdfSample
  3. 3Import the namespace

    Program.cs · lines 1–1
    using SelectPdf.Universal;

    HtmlToPdf, PdfDocument and the encryption enums are all in SelectPdf.Universal.

  4. 4Get the password

    Program.cs · lines 3–5
    // 1. The password readers type to open the file.
    //    Read it from a secret store or the environment; never commit a real one.
    string userPassword = Environment.GetEnvironmentVariable("PDF_USER_PASSWORD") ?? "open-me";

    The user password is the one readers type to open the file. Read it from a secret store or an environment variable, as here; open-me is only a placeholder for the sample. Do not write real passwords into source code or plain-text configuration files.

  5. 5Create the PDF

    Program.cs · lines 7–13
    // 2. Create the PDF.
    HtmlToPdf converter = new HtmlToPdf();
    PdfDocument doc = converter.ConvertHtmlString("""
        <h1>Payslip</h1>
        <p>Employee: Jane Doe</p>
        <p>Net pay: 3,250.00</p>
        """);

    HtmlToPdf converts a small payslip to a PdfDocument. In your application this is any document you build or convert: an invoice, a statement, a report.

  6. 6Encrypt it with AES-256

    Program.cs · lines 15–18
    // 3. Encrypt it with AES-256 (these two lines are the defaults, written out).
    doc.Security.Algorithm = PdfEncryptionAlgorithm.AES;
    doc.Security.KeySize = PdfEncryptionKeySize.EncryptKey256BitRevision6;
    doc.Security.UserPassword = userPassword;

    Security holds the document's encryption settings. Algorithm = AES with KeySize = EncryptKey256BitRevision6 is AES-256, revision 6, and it is already the default, so the only line you need is UserPassword. They are written out here so the choice is visible in your code.

  7. 7Save and close

    Program.cs · lines 20–22
    // 4. Save and close.
    doc.Save("payslip-protected.pdf");
    doc.Close();

    Save writes the encrypted file and Close releases the document. Opening payslip-protected.pdf now asks for the password.

  8. 8Run it

    terminal
    dotnet run

    The program writes payslip-protected.pdf to the working folder. Without a license key, every page carries a trial watermark; set GlobalProperties.LicenseKey before the first conversion to remove it.

§COMPLETE PROGRAM

The complete Program.cs.

This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.

Program.cs
using SelectPdf.Universal;

// 1. The password readers type to open the file.
//    Read it from a secret store or the environment; never commit a real one.
string userPassword = Environment.GetEnvironmentVariable("PDF_USER_PASSWORD") ?? "open-me";

// 2. Create the PDF.
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertHtmlString("""
    <h1>Payslip</h1>
    <p>Employee: Jane Doe</p>
    <p>Net pay: 3,250.00</p>
    """);

// 3. Encrypt it with AES-256 (these two lines are the defaults, written out).
doc.Security.Algorithm = PdfEncryptionAlgorithm.AES;
doc.Security.KeySize = PdfEncryptionKeySize.EncryptKey256BitRevision6;
doc.Security.UserPassword = userPassword;

// 4. Save and close.
doc.Save("payslip-protected.pdf");
doc.Close();

Open the project on GitHub → this program and the variations below, ready to dotnet run

§OUTPUT

The PDF it produces.

First page of payslip-protected.pdf, the PDF this sample produces
payslip-protected.pdf, page 1

Download payslip-protected.pdf ↓ the file this sample produced, unedited

§VARIATIONS

Variations you will need next.

Each variation is a separate file in the same project, compiled and run with the program above.

Block printing and copying with an owner password

OwnerPassword is the password that changes the permissions. With it set, CanPrint, CanCopyContent and CanEditContent set to false turn those actions off. Compliant viewers honour the permissions, but they do not keep the content confidential: the user password does that, so set both.

RestrictPermissions.cs
using SelectPdf.Universal;

static class RestrictPermissions
{
    public static void Run()
    {
        string userPassword = Environment.GetEnvironmentVariable("PDF_USER_PASSWORD") ?? "open-me";
        string ownerPassword = Environment.GetEnvironmentVariable("PDF_OWNER_PASSWORD") ?? "owner-change-me";

        HtmlToPdf converter = new HtmlToPdf();
        PdfDocument doc = converter.ConvertHtmlString("<h1>Contract draft</h1><p>For review only.</p>");

        // the user password opens the file; the owner password changes the permissions
        doc.Security.UserPassword = userPassword;
        doc.Security.OwnerPassword = ownerPassword;

        // no printing, no copying, no editing
        doc.Security.CanPrint = false;
        doc.Security.CanCopyContent = false;
        doc.Security.CanEditContent = false;

        doc.Save("contract-restricted.pdf");
        doc.Close();
    }
}

Encrypt an existing PDF file

PdfSecurityManager loads a PDF you already have, sets the passwords and saves an encrypted copy, with the same AES-256 default. The new file is then opened again with new PdfDocument(fileName, password), the constructor for password-protected PDFs.

EncryptExistingFile.cs
using SelectPdf.Universal;

static class EncryptExistingFile
{
    public static void Run()
    {
        // a PDF that already exists (here made on the spot)
        PdfDocument report = new HtmlToPdf().ConvertHtmlString("<h1>Annual report</h1>");
        report.Save("report.pdf");
        report.Close();

        string userPassword = Environment.GetEnvironmentVariable("PDF_USER_PASSWORD") ?? "open-me";
        string ownerPassword = Environment.GetEnvironmentVariable("PDF_OWNER_PASSWORD") ?? "owner-change-me";

        // PdfSecurityManager encrypts an existing file (AES-256, revision 6, by default)
        var security = new PdfSecurityManager();
        security.Load("report.pdf");
        security.UserPassword = userPassword;
        security.OwnerPassword = ownerPassword;
        security.Save("report-protected.pdf");
        security.Close();

        // open it again with the password
        PdfDocument check = new PdfDocument("report-protected.pdf", userPassword);
        Console.WriteLine($"Opened with the password: {check.Pages.Count} page(s)");
        check.Close();
    }
}

Encrypt during HTML to PDF conversion

converter.Options.SecurityOptions takes the same passwords and permissions, so every PDF the converter produces is encrypted as it is created, with AES-256 by default. Here copying is turned off for a converted web page.

EncryptDuringConversion.cs
using SelectPdf.Universal;

static class EncryptDuringConversion
{
    public static void Run()
    {
        string userPassword = Environment.GetEnvironmentVariable("PDF_USER_PASSWORD") ?? "open-me";
        string ownerPassword = Environment.GetEnvironmentVariable("PDF_OWNER_PASSWORD") ?? "owner-change-me";

        // set the security on the converter: every PDF it produces is encrypted
        HtmlToPdf converter = new HtmlToPdf();
        converter.Options.SecurityOptions.UserPassword = userPassword;
        converter.Options.SecurityOptions.OwnerPassword = ownerPassword;
        converter.Options.SecurityOptions.CanCopyContent = false;

        PdfDocument doc = converter.ConvertUrl("https://selectpdf.com");
        doc.Save("page-protected.pdf");
        doc.Close();
    }
}
§TROUBLESHOOTING

Common problems and fixes.

An old PDF reader cannot open the file

Readers older than Acrobat X cannot open AES-256. If you must support them, set Algorithm = PdfEncryptionAlgorithm.AES and KeySize = PdfEncryptionKeySize.EncryptKey128Bit. Avoid RC4: it is broken and kept only for old viewers.

Anyone can still open the PDF

Only an owner password was set. The owner password controls permissions; the user password is the one that has to be typed to open the document.

A PDF/A document with a password is refused

PDF/A does not allow encryption. Protect archived documents at the storage level instead.

A search index cannot read the document's metadata

By default the XMP metadata is encrypted with the content. Set EncryptMetadata = false to leave it readable. The title, author and keywords entries stay encrypted either way.

§GOOD TO KNOW

Good to know.

  • Setting a password is enough: the document is encrypted with AES and a 256-bit key, revision 6 of the PDF security handler. This applies to a new document, to an existing document that is not encrypted, and to the HTML to PDF converter's security options. Source
  • A document that is already encrypted keeps its own algorithm and key length unless they are changed. Source
  • Readers older than Acrobat X cannot open AES-256; when such readers must be supported, choose AES with a 128-bit key rather than RC4. Source
  • An owner password without a user password lets anyone open the document; the user password is what keeps the content confidential. Source
  • AES-256-GCM is also available. It is defined by PDF 2.0, so choosing it writes the document as PDF 2.0, which older viewers may not open. Source
?FAQ

Questions, answered.

Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.

AES with a 256-bit key, revision 6 of the PDF security handler (EncryptKey256BitRevision6). Setting the password is enough; you do not need to choose the algorithm or the key length.
The user password is required to open the document. The owner password is required to change the permissions, such as printing, copying or editing.
Load it with PdfSecurityManager, set UserPassword and OwnerPassword, and save. You can also open it as a PdfDocument and set doc.Security.UserPassword before saving.
Yes. Set the algorithm to PdfEncryptionAlgorithm.AESGCM. AES-256-GCM is defined by PDF 2.0, so the document is written as PDF 2.0, which only recent viewers open.