//--------------------------------------------------------------------------------------- // Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved. // Consult legal.txt regarding legal and license information. //--------------------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "../../LicenseKey/CPP/LicenseKey.h" using namespace std; using namespace pdftron; using namespace SDF; using namespace PDF; using namespace Filters; //--------------------------------------------------------------------------------------- // This sample shows encryption support in PDFNet. The sample reads an encrypted document and // sets a new SecurityHandler. The sample also illustrates how password protection can // be removed from an existing PDF document. //--------------------------------------------------------------------------------------- int main(int argc, char *argv[]) { int ret = 0; PDFNet::Initialize(LicenseKey); // Relative path to the folder containing test files. string input_path = "../../TestFiles/"; string output_path = "../../TestFiles/Output/"; // Example 1: // secure a PDF document with password protection and adjust permissions try { // Open the test file cout << "-------------------------------------------------" << endl << "Securing an existing document..." << endl; PDFDoc doc((input_path + "fish.pdf").c_str()); if (!doc.InitSecurityHandler()) { cout << "Document authentication error..." << endl; ret = 1; } // Perform some operation on the document. In this case we use low level SDF API // to replace the content stream of the first page with contents of file 'my_stream.txt' if (true) // Optional { cout << "Replacing the content stream, use flate compression..." << endl; // Get the page dictionary using the following path: trailer/Root/Pages/Kids/0 Obj page_dict = doc.GetTrailer().Get("Root").Value() .Get("Pages").Value() .Get("Kids").Value() .GetAt(0); // Embed a custom stream (file mystream.txt) using Flate compression. MappedFile embed_file((input_path + "my_stream.txt")); FilterReader mystm(embed_file); page_dict.Put("Contents", doc.CreateIndirectStream(mystm, FlateEncode(Filter()))); } //encrypt the document // Apply a new security handler with given security settings. // In order to open saved PDF you will need a user password 'test'. SecurityHandler new_handler; // Set a new password required to open a document const char* user_password="test"; new_handler.ChangeUserPassword(user_password); // Set Permissions new_handler.SetPermission (SecurityHandler::e_print, true); new_handler.SetPermission (SecurityHandler::e_extract_content, false); // Note: document takes the ownership of new_handler. doc.SetSecurityHandler(new_handler); // Save the changes. cout << "Saving modified file..." << endl; doc.Save((output_path + "secured.pdf").c_str(), 0, NULL); cout << "Done. Result saved in secured.pdf" << endl; } catch(Common::Exception& e) { cout << e << endl; ret = 1; } catch(...) { cout << "Unknown Exception" << endl; ret = 1; } // Example 2: // Opens an encrypted PDF document and removes its security. try { cout << "-------------------------------------------------" << endl; cout << "Open the password protected document from the first example..." << endl; // Open the encrypted document that we saved in the first example. PDFDoc doc((output_path + "secured.pdf").c_str()); cout << "Initializing security handler without any user interaction..." << endl; // At this point MySecurityHandler callbacks will be invoked. // MySecurityHandler.GetAuthorizationData() should collect the password and // AuthorizeFailed() is called if user repeatedly enters a wrong password. if (!doc.InitStdSecurityHandler("test")) { cout << "Document authentication error..." << endl << "The password is not valid." << endl; ret = 1; } else { cout << "The password is correct! Document can now be used for reading and editing" << endl; // Remove the password security and save the changes to a new file. doc.RemoveSecurity(); doc.Save(output_path + "secured_nomore1.pdf", 0, NULL); cout << "Done. Result saved in secured_nomore1.pdf" << endl; /* SecurityHandler hdlr = doc.GetSecurityHandler(); cout << "Document Open Password: " << hdlr.IsUserPasswordRequired() << endl; cout << "Permissions Password: " << hdlr.IsMasterPasswordRequired() << endl; cout << "Permissions: " << "\n\tHas 'owner' permissions: " << hdlr.GetPermission(SecurityHandler::e_owner) << "\n\tOpen and decrypt the document: " << hdlr.GetPermission(SecurityHandler::e_doc_open) << "\n\tAllow content extraction: " << hdlr.GetPermission(SecurityHandler::e_extract_content) << "\n\tAllow full document editing: " << hdlr.GetPermission(SecurityHandler::e_doc_modify) << "\n\tAllow printing: " << hdlr.GetPermission(SecurityHandler::e_print) << "\n\tAllow high resolution printing: " << hdlr.GetPermission(SecurityHandler::e_print_high) << "\n\tAllow annotation editing: " << hdlr.GetPermission(SecurityHandler::e_mod_annot) << "\n\tAllow form fill: " << hdlr.GetPermission(SecurityHandler::e_fill_forms) << "\n\tAllow content extraction for accessibility: " << hdlr.GetPermission(SecurityHandler::e_access_support) << "\n\tAllow document assembly: " << hdlr.GetPermission(SecurityHandler::e_assemble_doc) << endl; */ } } catch(Common::Exception& e) { cout << e << endl; ret = 1; } catch(...) { cout << "Unknown Exception" << endl; ret = 1; } // An advanced example showing how to work with custom security handlers. // A custom security handler is a class derived from a SecurityHandler. // Define a custom security handler used to obtain document password dynamically via user feedback. class MySecurityHandler : public SecurityHandler { public: MySecurityHandler (int key_len, int enc_code) : SecurityHandler("Standard", key_len, enc_code) {} MySecurityHandler (const MySecurityHandler& s) : SecurityHandler(s) {} virtual ~MySecurityHandler() { // cout << "MySecurityHandler Destroy"; } // In this callback ask the user for password/authorization data. // This may involve a dialog box used to collect authorization data or something else. virtual bool GetAuthorizationData (Permission p) { cout << "The input file requires user password." << endl; cout << "Please enter the password:" << endl; string password; cin >> password; InitPassword(password.c_str()); return true; } // This callback could be used to customize security handler preferences. virtual bool EditSecurityData(SDF::SDFDoc& doc) { return false; } // This callback is used when authorization process fails. virtual void AuthorizeFailed() { cout << "Authorize failed...." << endl; } MySecurityHandler(const MySecurityHandler& s, TRN_SecurityHandler base) : SecurityHandler(base, true, s.m_derived_procs) { } virtual SecurityHandler* Clone(TRN_SecurityHandler base) const { return new MySecurityHandler(*this, base); } // MySecurityHandler's factory method static TRN_SecurityHandler Create(const char* name, int key_len, int enc_code, void* custom_data) { MySecurityHandler* ret = new MySecurityHandler (key_len, enc_code); // Explicitly specify which methods are overloaded. ret->SetDerived( has_CloneProc | // Clone - must be implemented in every derived class. has_AuthFailedProc | has_GetAuthDataProc); return (TRN_SecurityHandler) ret->mp_handler; } }; // Example 3: // Encrypt/Decrypt a PDF using PDFTron custom security handler try { cout << "-------------------------------------------------" << endl; cout << "Encrypt a document using PDFTron Custom Security handler with a custom id and password..." << endl; PDFDoc doc(input_path + "BusinessCardTemplate.pdf"); // Create PDFTron custom security handler with a custom id. Replace this with your own integer UInt32 custom_id = 123456789; SDF::PDFTronCustomSecurityHandler custom_handler(custom_id); // Add a password to the custom security handler const UString pass("test"); custom_handler.ChangeUserPassword(pass); // Save the encrypted document doc.SetSecurityHandler(custom_handler); doc.Save((output_path + "BusinessCardTemplate_enc.pdf").c_str(), SDFDoc::e_linearized, 0); cout << "Decrypt the PDFTron custom security encrypted document above..." << endl; // Register the PDFTron Custom Security handler with the same custom id used in encryption PDFNet::AddPDFTronCustomHandler(custom_id); PDFDoc doc_enc(output_path + "BusinessCardTemplate_enc.pdf"); doc_enc.InitStdSecurityHandler(pass); doc_enc.RemoveSecurity(); // Save the decrypted document doc_enc.Save((output_path + "BusinessCardTemplate_enc_dec.pdf").c_str(), SDFDoc::e_linearized, 0); cout << "Done. Result saved in BusinessCardTemplate_enc_dec.pdf" << endl; } catch (Common::Exception & e) { cout << e << endl; ret = 1; } catch (...) { cout << "Unknown Exception" << endl; ret = 1; } // Example 4: // Read a password protected PDF using a custom security handler. try { // Register standard security. Required only once per application session. PDFNet::RegisterSecurityHandler("Standard", "Standard Security", MySecurityHandler::Create); cout << "-------------------------------------------------" << endl; cout << "Open the password protected document from the first example..." << endl; PDFDoc doc((output_path + "secured.pdf").c_str()); // Open the encrypted document that we saved in the first example. cout << "Initializing security handler. The password will now be collected from the user" << endl; cout << "Enter 'test' as the password." << endl; // this data is just to show how you can pass your own custom data through InitSecurityHandler void* custom_data = const_cast("my custom pointer"); // At this point MySecurityHandler callbacks will be invoked. // MySecurityHandler.GetAuthorizationData() should collect the password and // AuthorizeFailed() is called if user repeatedly enters a wrong password. if (!doc.InitSecurityHandler(custom_data)) { cout << "Document authentication error..." << endl; cout << "The password is not valid." << endl; } else { cout << "\nThe password is correct! Document can now be used for reading and editing" << endl; // Remove the password security and save the changes to a new file. doc.RemoveSecurity(); doc.Save((output_path + "secured_nomore2.pdf").c_str(), 0, NULL); cout << "Done. Result saved in secured_nomore2.pdf" << endl; } } catch(Common::Exception& e) { cout << e << endl; ret = 1; } catch(...) { cout << "Unknown Exception" << endl; ret = 1; } cout << "-------------------------------------------------" << endl; cout << "Tests completed." << endl; PDFNet::Terminate(); return ret; }