AES Data Provider

The PSPDFAESCryptoDataProvider allows a transparent decryption of AES256 encrypted files using the RNCryptor file format. The data format expected by the data provider is structured like this:

Copy
1
2
Byte:     |    0    |    1    |      2-9       |  10-17   | 18-33 | <-      ...     -> | n-32 - n |
Contents: | version | options | encryptionSalt | HMACSalt |  IV   |    Encrypted PDF   |   HMAC   |

How to Encrypt Files

When downloading the PSPDFKit for iOS SDK, we include a tool called AESCryptor, which lets you encrypt and decrypt files with ease. It’s located in the downloaded .dmg in Extras > AESCryptor > AESCryptor.app.

  1. Open the AESCryptor application and select the file you want to encrypt under Input. A Finder window will open and allow you to select your desired document.
  2. Now you need a password and salt to safely encrypt your file. We’ll use the following values provided in PSCAESCryptoDataProviderExample.swift.
  • Password: afghadöghdgdhfgöhapvuenröaoeruhföaeiruaerub
  • Salt: ducrXn9WaRdpaBfMjDTJVjUf3FApA6gtim0e61LeSGWV9sTxB0r26mPs59Lbcexn
  1. Now simply click on Encrypt to complete the encryption process.

Here’s how it should appear in the end:

How to Decrypt Files

To programmatically decrypt your encrypted PDF files using PSPDFKit, you need to use the PSPDFAESCryptoDataProvider with the password and salt you used to encrypt the PDF:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Location of your encrypted PDF.
let encryptedPDF = ...

// Note: For shipping apps, you need to protect this string better, making it harder for hackers to simply disassemble and receive the key from the binary. Or, you can add an internet service that fetches the key from an SSL API. But then there's still the slight risk of memory dumping with an attached GDB. Or screenshots. Security is never 100 percent perfect, but using AES makes it more difficult to get the PDF. You can even combine AES and a PDF password.
let passphrase = "afghadöghdgdhfgöhapvuenröaoeruhföaeiruaerub"
let salt = "ducrXn9WaRdpaBfMjDTJVjUf3FApA6gtim0e61LeSGWV9sTxB0r26mPs59Lbcexn"

// PSPDFKit doesn't want to keep the passphrase in memory any longer than it has to. This is the reason we use a passphrase provider.
// For optimal results, always fetch the passphrase/password from secure storage (like the keychain) and never keep it in memory.
let passphraseProvider = { passphrase }

guard let cryptoWrapper = PSPDFAESCryptoDataProvider(url: encryptedPDF, passphraseProvider: passphraseProvider, salt: salt, rounds: PSPDFDefaultPBKDFNumberOfRounds) else {
    return PSPDFViewController(document: nil)
}

// Create a document.
let document = PDFDocument(dataProviders: [cryptoWrapper])
document.uid = encryptedPDF.lastPathComponent // Manually set a UID for encrypted documents.
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Location of your encrypted PDF.
NSURL *const encryptedPDF = ...

// Note: For shipping apps, you need to protect this string better, making it harder for hackers to simply disassemble and receive the key from the binary. Or, you can add an internet service that fetches the key from an SSL API. But then there's still the slight risk of memory dumping with an attached GDB. Or screenshots. Security is never 100 percent perfect, but using AES makes it more difficult to get the PDF. You can even combine AES and a PDF password.
NSString *const passphrase = @"afghadöghdgdhfgöhapvuenröaoeruhföaeiruaerub";
NSString *const salt = @"ducrXn9WaRdpaBfMjDTJVjUf3FApA6gtim0e61LeSGWV9sTxB0r26mPs59Lbcexn";

// PSPDFKit doesn't want to keep the passphrase/password in memory any longer than it has to. This is the reason we use a passphrase provider.
// For optimal results, always fetch the passphrase from secure storage (like the keychain) and never keep it in memory.
NSString * (^const passphraseProvider)(void) = ^() {
    return passphrase;
};

PSPDFAESCryptoDataProvider *cryptoWrapper = [[PSPDFAESCryptoDataProvider alloc] initWithURL:encryptedPDF passphraseProvider:passphraseProvider salt:salt rounds:PSPDFDefaultPBKDFNumberOfRounds];

// Create a document.
PSPDFDocument *document = [[PSPDFDocument alloc] initWithDataProviders:@[cryptoWrapper]];
document.UID = encryptedPDF.lastPathComponent; // Manually set a UID for encrypted documents.

For more information about this process, please take a look at AESCryptoDataProviderExample.swift in our Catalog example.