Encrypt & Decrypt PDFs - C++ Sample Code

Sample code for using Apryse SDK to read encrypted (password protected) documents, secure a document with encryption, or remove encryption. Samples provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby, Go and VB. Learn more about our Server SDK.

1//---------------------------------------------------------------------------------------
2// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
3// Consult legal.txt regarding legal and license information.
4//---------------------------------------------------------------------------------------
5
6#include <PDF/PDFNet.h>
7#include <PDF/PDFDoc.h>
8#include <SDF/SecurityHandler.h>
9#include <SDF/PDFTronCustomSecurityHandler.h>
10#include <Filters/FilterReader.h>
11#include <Filters/FlateEncode.h>
12#include <Filters/MappedFile.h>
13#include <iostream>
14#include <string>
15#include "../../LicenseKey/CPP/LicenseKey.h"
16
17using namespace std;
18
19using namespace pdftron;
20using namespace SDF;
21using namespace PDF;
22using namespace Filters;
23
24
25//---------------------------------------------------------------------------------------
26// This sample shows encryption support in PDFNet. The sample reads an encrypted document and
27// sets a new SecurityHandler. The sample also illustrates how password protection can
28// be removed from an existing PDF document.
29//---------------------------------------------------------------------------------------
30int main(int argc, char *argv[])
31{
32 int ret = 0;
33 PDFNet::Initialize(LicenseKey);
34
35 // Relative path to the folder containing test files.
36 string input_path = "../../TestFiles/";
37 string output_path = "../../TestFiles/Output/";
38
39 // Example 1:
40 // secure a PDF document with password protection and adjust permissions
41
42 try
43 {
44 // Open the test file
45 cout << "-------------------------------------------------" << endl << "Securing an existing document..." << endl;
46 PDFDoc doc((input_path + "fish.pdf").c_str());
47 if (!doc.InitSecurityHandler())
48 {
49 cout << "Document authentication error..." << endl;
50 ret = 1;
51 }
52
53
54 // Perform some operation on the document. In this case we use low level SDF API
55 // to replace the content stream of the first page with contents of file 'my_stream.txt'
56 if (true) // Optional
57 {
58 cout << "Replacing the content stream, use flate compression..." << endl;
59
60 // Get the page dictionary using the following path: trailer/Root/Pages/Kids/0
61 Obj page_dict = doc.GetTrailer().Get("Root").Value()
62 .Get("Pages").Value()
63 .Get("Kids").Value()
64 .GetAt(0);
65
66 // Embed a custom stream (file mystream.txt) using Flate compression.
67 MappedFile embed_file((input_path + "my_stream.txt"));
68 FilterReader mystm(embed_file);
69 page_dict.Put("Contents",
70 doc.CreateIndirectStream(mystm,
71 FlateEncode(Filter())));
72 }
73
74 //encrypt the document
75
76
77 // Apply a new security handler with given security settings.
78 // In order to open saved PDF you will need a user password 'test'.
79 SecurityHandler new_handler;
80
81 // Set a new password required to open a document
82 const char* user_password="test";
83 new_handler.ChangeUserPassword(user_password);
84
85 // Set Permissions
86 new_handler.SetPermission (SecurityHandler::e_print, true);
87 new_handler.SetPermission (SecurityHandler::e_extract_content, false);
88
89 // Note: document takes the ownership of new_handler.
90 doc.SetSecurityHandler(new_handler);
91
92 // Save the changes.
93 cout << "Saving modified file..." << endl;
94 doc.Save((output_path + "secured.pdf").c_str(), 0, NULL);
95
96 cout << "Done. Result saved in secured.pdf" << endl;
97 }
98 catch(Common::Exception& e) {
99 cout << e << endl;
100 ret = 1;
101 }
102 catch(...) {
103 cout << "Unknown Exception" << endl;
104 ret = 1;
105 }
106
107 // Example 2:
108 // Opens an encrypted PDF document and removes its security.
109
110 try
111 {
112 cout << "-------------------------------------------------" << endl;
113 cout << "Open the password protected document from the first example..." << endl;
114
115 // Open the encrypted document that we saved in the first example.
116 PDFDoc doc((output_path + "secured.pdf").c_str());
117
118 cout << "Initializing security handler without any user interaction..." << endl;
119
120 // At this point MySecurityHandler callbacks will be invoked.
121 // MySecurityHandler.GetAuthorizationData() should collect the password and
122 // AuthorizeFailed() is called if user repeatedly enters a wrong password.
123 if (!doc.InitStdSecurityHandler("test"))
124 {
125 cout << "Document authentication error..." << endl << "The password is not valid." << endl;
126 ret = 1;
127 }
128 else
129 {
130 cout << "The password is correct! Document can now be used for reading and editing" << endl;
131
132 // Remove the password security and save the changes to a new file.
133 doc.RemoveSecurity();
134 doc.Save(output_path + "secured_nomore1.pdf", 0, NULL);
135 cout << "Done. Result saved in secured_nomore1.pdf" << endl;
136
137 /*
138 SecurityHandler hdlr = doc.GetSecurityHandler();
139 cout << "Document Open Password: " << hdlr.IsUserPasswordRequired() << endl;
140 cout << "Permissions Password: " << hdlr.IsMasterPasswordRequired() << endl;
141 cout << "Permissions: "
142 << "\n\tHas 'owner' permissions: " << hdlr.GetPermission(SecurityHandler::e_owner)
143 << "\n\tOpen and decrypt the document: " << hdlr.GetPermission(SecurityHandler::e_doc_open)
144 << "\n\tAllow content extraction: " << hdlr.GetPermission(SecurityHandler::e_extract_content)
145 << "\n\tAllow full document editing: " << hdlr.GetPermission(SecurityHandler::e_doc_modify)
146 << "\n\tAllow printing: " << hdlr.GetPermission(SecurityHandler::e_print)
147 << "\n\tAllow high resolution printing: " << hdlr.GetPermission(SecurityHandler::e_print_high)
148 << "\n\tAllow annotation editing: " << hdlr.GetPermission(SecurityHandler::e_mod_annot)
149 << "\n\tAllow form fill: " << hdlr.GetPermission(SecurityHandler::e_fill_forms)
150 << "\n\tAllow content extraction for accessibility: " << hdlr.GetPermission(SecurityHandler::e_access_support)
151 << "\n\tAllow document assembly: " << hdlr.GetPermission(SecurityHandler::e_assemble_doc)
152 << endl;
153 */
154 }
155 }
156 catch(Common::Exception& e) {
157 cout << e << endl;
158 ret = 1;
159 }
160 catch(...) {
161 cout << "Unknown Exception" << endl;
162 ret = 1;
163 }
164
165 // An advanced example showing how to work with custom security handlers.
166 // A custom security handler is a class derived from a SecurityHandler.
167
168 // Define a custom security handler used to obtain document password dynamically via user feedback.
169 class MySecurityHandler : public SecurityHandler
170 {
171 public:
172 MySecurityHandler (int key_len, int enc_code) : SecurityHandler("Standard", key_len, enc_code) {}
173 MySecurityHandler (const MySecurityHandler& s) : SecurityHandler(s) {}
174 virtual ~MySecurityHandler() {
175 // cout << "MySecurityHandler Destroy";
176 }
177
178 // In this callback ask the user for password/authorization data.
179 // This may involve a dialog box used to collect authorization data or something else.
180 virtual bool GetAuthorizationData (Permission p)
181 {
182 cout << "The input file requires user password." << endl;
183 cout << "Please enter the password:" << endl;
184
185 string password;
186 cin >> password;
187
188 InitPassword(password.c_str());
189 return true;
190 }
191
192 // This callback could be used to customize security handler preferences.
193 virtual bool EditSecurityData(SDF::SDFDoc& doc) { return false; }
194
195 // This callback is used when authorization process fails.
196 virtual void AuthorizeFailed() { cout << "Authorize failed...." << endl; }
197
198
199 MySecurityHandler(const MySecurityHandler& s, TRN_SecurityHandler base)
200 : SecurityHandler(base, true, s.m_derived_procs)
201 {
202 }
203
204 virtual SecurityHandler* Clone(TRN_SecurityHandler base) const
205 {
206 return new MySecurityHandler(*this, base);
207 }
208
209 // MySecurityHandler's factory method
210 static TRN_SecurityHandler Create(const char* name, int key_len, int enc_code, void* custom_data)
211 {
212 MySecurityHandler* ret = new MySecurityHandler (key_len, enc_code);
213
214 // Explicitly specify which methods are overloaded.
215 ret->SetDerived(
216 has_CloneProc | // Clone - must be implemented in every derived class.
217 has_AuthFailedProc |
218 has_GetAuthDataProc);
219 return (TRN_SecurityHandler) ret->mp_handler;
220 }
221 };
222
223 // Example 3:
224 // Encrypt/Decrypt a PDF using PDFTron custom security handler
225 try
226 {
227 cout << "-------------------------------------------------" << endl;
228 cout << "Encrypt a document using PDFTron Custom Security handler with a custom id and password..." << endl;
229 PDFDoc doc(input_path + "BusinessCardTemplate.pdf");
230
231 // Create PDFTron custom security handler with a custom id. Replace this with your own integer
232 UInt32 custom_id = 123456789;
233 SDF::PDFTronCustomSecurityHandler custom_handler(custom_id);
234
235 // Add a password to the custom security handler
236 const UString pass("test");
237 custom_handler.ChangeUserPassword(pass);
238
239 // Save the encrypted document
240 doc.SetSecurityHandler(custom_handler);
241 doc.Save((output_path + "BusinessCardTemplate_enc.pdf").c_str(), SDFDoc::e_linearized, 0);
242
243 cout << "Decrypt the PDFTron custom security encrypted document above..." << endl;
244 // Register the PDFTron Custom Security handler with the same custom id used in encryption
245 PDFNet::AddPDFTronCustomHandler(custom_id);
246
247 PDFDoc doc_enc(output_path + "BusinessCardTemplate_enc.pdf");
248 doc_enc.InitStdSecurityHandler(pass);
249 doc_enc.RemoveSecurity();
250 // Save the decrypted document
251 doc_enc.Save((output_path + "BusinessCardTemplate_enc_dec.pdf").c_str(), SDFDoc::e_linearized, 0);
252 cout << "Done. Result saved in BusinessCardTemplate_enc_dec.pdf" << endl;
253 }
254 catch (Common::Exception & e) {
255 cout << e << endl;
256 ret = 1;
257 }
258 catch (...) {
259 cout << "Unknown Exception" << endl;
260 ret = 1;
261 }
262
263 // Example 4:
264 // Read a password protected PDF using a custom security handler.
265
266 try
267 {
268 // Register standard security. Required only once per application session.
269 PDFNet::RegisterSecurityHandler("Standard", "Standard Security", MySecurityHandler::Create);
270
271 cout << "-------------------------------------------------" << endl;
272 cout << "Open the password protected document from the first example..." << endl;
273 PDFDoc doc((output_path + "secured.pdf").c_str()); // Open the encrypted document that we saved in the first example.
274
275 cout << "Initializing security handler. The password will now be collected from the user" << endl;
276 cout << "Enter 'test' as the password." << endl;
277
278 // this data is just to show how you can pass your own custom data through InitSecurityHandler
279 void* custom_data = const_cast<char*>("my custom pointer");
280
281 // At this point MySecurityHandler callbacks will be invoked.
282 // MySecurityHandler.GetAuthorizationData() should collect the password and
283 // AuthorizeFailed() is called if user repeatedly enters a wrong password.
284 if (!doc.InitSecurityHandler(custom_data))
285 {
286 cout << "Document authentication error..." << endl;
287 cout << "The password is not valid." << endl;
288 }
289 else
290 {
291 cout << "\nThe password is correct! Document can now be used for reading and editing" << endl;
292
293 // Remove the password security and save the changes to a new file.
294 doc.RemoveSecurity();
295 doc.Save((output_path + "secured_nomore2.pdf").c_str(), 0, NULL);
296 cout << "Done. Result saved in secured_nomore2.pdf" << endl;
297 }
298 }
299 catch(Common::Exception& e) {
300 cout << e << endl;
301 ret = 1;
302 }
303 catch(...) {
304 cout << "Unknown Exception" << endl;
305 ret = 1;
306 }
307
308 cout << "-------------------------------------------------" << endl;
309 cout << "Tests completed." << endl;
310
311 PDFNet::Terminate();
312 return ret;
313}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales