TX Text Control .NET for WPF

Passwords and Access Permissions

Topic

Before a contract or a salary statement leaves a WPF application as PDF, you decide who may open it and what readers may do with it. A user password encrypts the file, and a master password guards the permissions for printing, copying and editing. TX Text Control .NET for WPF writes both when it saves a PDF, and it opens protected PDF files when your application passes the password. The sections below cover saving with passwords, the password option of the Save As dialog and a WPF password prompt for protected files.

A first protected PDF is saved in Create a PDF. Whether passwords and permissions are enough for your documents is a question for PDF Passwords and Permissions in the Security section.

How PDF Passwords Work

  • UserPassword is needed to open the document, which is encrypted with it. With an empty string, anyone can open the document.
  • MasterPassword, the owner password, guards the permissions and the security settings. With an empty string, access isn't restricted.
  • DocumentAccessPermissions lists what users may do once the document is open. It works only together with a master password; combine its values with |.

SaveSettings and LoadSettings both have the two password properties. They apply to PDF only, with a key length of 128 bits. PDF/A forbids encryption, so StreamType.AdobePDFA never writes a password. The values of the permissions:

ValueAllows
AllowAllEvery permission
NoneNo permission
AllowLowLevelPrintingPrinting
AllowHighLevelPrintingPrinting without restrictions
AllowExtractContentsCopying or extracting text and graphics
AllowContentAccessibilityExtracting content for the visually impaired only
AllowGeneralEditingChanging the content
AllowAuthoringAdding comments and filling in form fields, signature fields included
AllowAuthoringFieldsFilling in existing form fields, signature fields included
AllowDocumentAssemblyInserting, rotating and deleting pages, creating bookmarks and thumbnails

Protect the Document When Saving

Handlers of this page go into MainWindow.xaml.cs, with using System.IO;, using System.Windows;, using System.Windows.Controls; and using TXTextControl; at the top. Protect the PDF With Passwords in Getting Started saves a PDF with a user password, a master password and permissions, and shows the password prompt of the PDF reader. Choose different values for the two passwords: then users who can open the document can't change its permissions or remove the protection.

Leave out the user password, and the document opens for everyone while the permissions still apply. This suits a form that users fill in and print but mustn't change, as Save a Fillable Form shows with AllowAuthoringFields and AllowHighLevelPrinting.

Permissions are instructions that compliant PDF readers follow, not encryption, so confidential documents need a user password; Why Permissions Aren't Enough explains the difference.

Let the User Set the Password in the Save As Dialog

When users save documents themselves, let them choose the password. With SaveSettings.DialogSettings EnterPassword, the Save As dialog gets a button that opens a dialog for an encryption password:

private void saveAsPdfButton_Click(object sender, RoutedEventArgs e)
{
    SaveSettings saveSettings = new SaveSettings();

    // Adds a button for an encryption password to the Save As dialog
    if (textControl1.Save(StreamType.AdobePDF, saveSettings, SaveSettings.DialogSettings.EnterPassword) ==
        TXTextControl.WPF.DialogResult.OK)
    {
        MessageBox.Show(this, $"Saved: {saveSettings.SavedFile}");
    }
}

Save returns the DialogResult of the namespace TXTextControl.WPF, named in full because the file doesn't import that namespace. The password button appears only while Adobe PDF is the selected file type, since PDF/A doesn't support encryption. Loading and Saving lists the other options of the dialog.

Open a Password-Protected PDF

TX Text Control decrypts protected PDF files while loading them, and your application is responsible for asking the user for the password and for restricting what the permissions forbid. Without the right user password, Load throws a FilterException with the Reason InvalidPassword. The following handler repeats the prompt until the file opens or the user cancels:

private void openProtectedPdfButton_Click(object sender, RoutedEventArgs e)
{
    string path = "invoice-protected.pdf";
    LoadSettings loadSettings = new LoadSettings();

    while (true)
    {
        try
        {
            textControl1.Load(path, StreamType.AdobePDF, loadSettings);
            break;
        }
        catch (FilterException exception) when (exception.Reason == FilterException.FilterError.InvalidPassword)
        {
            // No password or a wrong one: ask the user
            string password = AskForPassword(System.IO.Path.GetFileName(path));

            if (password == null)
            {
                return;
            }

            loadSettings = new LoadSettings() { UserPassword = password };
        }
    }

    // loadSettings.DocumentAccessPermissions now holds what the PDF allows
}

AskForPassword builds a small modal window with a PasswordBox, which masks the input, and returns null when the user cancels. Because TXTextControl has classes named Button and HorizontalAlignment as well, the WPF types are named in full:

private string AskForPassword(string fileName)
{
    PasswordBox passwordBox = new PasswordBox() { Margin = new Thickness(0, 8, 0, 8) };
    System.Windows.Controls.Button okButton = new System.Windows.Controls.Button()
        { Content = "OK", IsDefault = true, Width = 75, Margin = new Thickness(0, 0, 8, 0) };
    System.Windows.Controls.Button cancelButton = new System.Windows.Controls.Button()
        { Content = "Cancel", IsCancel = true, Width = 75 };

    StackPanel buttons = new StackPanel()
        { Orientation = Orientation.Horizontal, HorizontalAlignment = System.Windows.HorizontalAlignment.Right };
    buttons.Children.Add(okButton);
    buttons.Children.Add(cancelButton);

    StackPanel panel = new StackPanel() { Margin = new Thickness(12) };
    panel.Children.Add(new TextBlock() { Text = $"{fileName} is protected. Enter its password:" });
    panel.Children.Add(passwordBox);
    panel.Children.Add(buttons);

    Window dialog = new Window()
    {
        Title = "Password",
        Content = panel,
        Owner = this,
        SizeToContent = SizeToContent.WidthAndHeight,
        ResizeMode = ResizeMode.NoResize,
        WindowStartupLocation = WindowStartupLocation.CenterOwner
    };

    okButton.Click += (s, args) => dialog.DialogResult = true;
    dialog.Loaded += (s, args) => passwordBox.Focus();

    return dialog.ShowDialog() == true ? passwordBox.Password : null;
}

IsCancel closes the window when the user clicks Cancel or presses ESC, and setting DialogResult closes it with true for OK. In a larger application, define the window in XAML of its own instead.

Apply the Permissions in the Editor

After the load, LoadSettings.DocumentAccessPermissions reports what the PDF allows, and a PDF opened with its master password reports AllowAll. How to turn these flags into restrictions of the TextControl, with DocumentPermissions and EditMode.ReadAndSelect, is shown in Respect the Permissions of a PDF in the Security section.

Encryption TX Text Control Can Open

Not every encrypted PDF can be opened: for some encryptions, Load throws a FilterException with the Reason Encrypted. Encrypted PDF Documents lists the encryptions TX Text Control imports. The PDF files TX Text Control saves use a 128-bit key, which Adobe Acrobat shows as 128-bit AES:

The Document Security dialog box of Adobe Acrobat for a PDF with a document open password and no permissions password, listing all operations as allowed and the encryption level 128-bit AES.

Save a Loaded PDF With Its Password

Once loaded, a PDF is a document in the editor, and the protection of the next PDF comes from the SaveSettings of that save. The TX Words sample remembers the user password of a loaded PDF and passes it again when it saves the document as PDF. The LoadSettings of the load hold it:

private void saveAgainButton_Click(object sender, RoutedEventArgs e)
{
    LoadSettings loadSettings = new LoadSettings() { UserPassword = "user1234" };
    textControl1.Load("invoice-protected.pdf", StreamType.AdobePDF, loadSettings);

    // ... the user edits the document ...

    SaveSettings saveSettings = new SaveSettings()
    {
        UserPassword = loadSettings.UserPassword,
        MasterPassword = "owner1234",
        DocumentAccessPermissions = DocumentAccessPermissions.AllowLowLevelPrinting
    };

    textControl1.Save("invoice-protected.pdf", StreamType.AdobePDF, saveSettings);
}

Check That a PDF Is Encrypted

For PDF files that your application protects automatically, verify the result: loading the file without a password has to fail with the reason InvalidPassword. Check That a PDF Is Encrypted in the Security section has a method that runs this check in a ServerTextControl, and the blog article PDF Security Explained: Passwords, Permissions, Encryption and Digital Signatures in C# .NET explains how encryption, permissions and digital signatures complement each other.

PDF Passwords and Document Protection

Don't mix up PDF passwords with the protection of a document in the editor. With EditMode.UsePassword, a user protects a document so that only its editable regions can be changed; the password is stored in the document, also in DOCX, RTF and PDF, and TX Text Control opens such a document read-only. A PDF user password encrypts the file for any PDF reader. The protection in the editor is covered in Document Protection and Editable Regions.

Next Steps