A PDF document can be secured by encrypting its contents and requiring a password for access.
Using ImageGear, applications can open and decrypt password-secured PDF documents, provided that the correct password is supplied.
Once a PDF document is opened, ImageGear can:
- Set or change the PDF document's access permissions
- Set or change the encryption used and what gets encrypted
- Set or change what content does or does not get encrypted
- Set, change, or remove the secure PDF document's password
Refer to the PDFSecurity Sample for complete sample code that illustrates how to use this capability.
This section illustrates how to:
Open a Password-Secured PDF Document
Prior to opening any password-secured PDF documents, an authorization callback procedure must be registered using the IG_PDF_register_authproc() function:
C and C++ |
Copy Code
|
// Register a PDF authorization callback.
IG_PDF_register_authproc(PdfAuthorize, UIntToPtr(IG_PDF_PERM_REQ_OPR_OPEN));
|
This authorization callback is expected to provide the password using the IG_PDF_doc_perm_request() function. An example callback would look like:
C and C++ |
Copy Code
|
AT_PDF_BOOL ACCUAPI PdfAuthorize(HIG_PDF_DOC pdfDocument, LPVOID clientData)
{
SHORT requestStatus = IG_PDF_PERM_REQ_DENIED;
UINT requestOperation = PtrToUint(clientData);
// The password stored in obtainedPassword can be obtained
// from a password dialog, for example.
IG_PDF_doc_perm_request(pdfDocument, IG_PDF_PERM_REQ_OBJ_DOC, requestOperation,
obtainedPassword &requestStatus);
return (requestStatus == IG_PDF_PERM_REQ_GRANTED);
}
|
When the IG_mpi_file_open() function attempts to open a secure PDF that requires a password, the registered callback is invoked.The callback provides the password and authenticates it. If the PDF document does not require a password, then the callback is not called, and the file is immediately opened. In both cases, use the IG_mpi_file_open() function to open all pages of the document as follows:
C and C++ |
Copy Code
|
HMIGEAR document = 0;
IG_mpi_create(&document, 0);
IG_mpi_file_open(filepath, document, IG_FORMAT_PDF, IG_MP_OPENMODE_READONLY);
|
Manage a PDF Document's Security Settings
After the document has been successfully opened, its security settings, i.e., encryption and password, can be managed.
Request Permission to Modify Security Settings
Before you can manage a PDF document's security settings, you need to request permission to change the security settings by using the IG_PDF_doc_perm_request() function, and then checking whether that permission has been granted:
C and C++ |
Copy Code
|
HIG_PDF_DOC pdfDocument = NULL;
SHORT requestStatus = IG_PDF_PERM_REQ_DENIED;
UINT requestOperation = IG_PDF_PERM_REQ_OPR_SECURE;
IG_mpi_info_get(document, IG_MP_DOCUMENT, &pdfDocument, sizeof(pdfDocument));
IG_PDF_doc_perm_request(pdfDocument, IG_PDF_PERM_REQ_OBJ_DOC, requestOperation, obtainedPassword, &requestStatus);
if (requestStatus == IG_PDF_PERM_REQ_GRANTED)
{
// make the changes here
...
}
|
Secure a PDF Document
After access has been granted, secure a PDF document with a new password and 256-bit AES encryption by creating a new AT_PDF_SECURITYDATA object and setting its fields as follows:
C and C++ |
Copy Code
|
AT_PDF_SECURITYDATA newSecurityData;
LPAT_PDF_SECURITYDATA securityData = NULL;
HIG_PDF_ATOM securityHandler = IG_PDF_ATOM_NULL;
// Permissions flags to allow.
const int negativePermissions = IG_PDF_PERM_SETTABLE | IG_PDF_PRIV_PERM_HIGH_PRINT |
IG_PDF_PRIV_PERM_FILL_AND_SIGN | IG_PDF_PRIV_PERM_FORM_SUBMIT |
IG_PDF_PRIV_PERM_DOC_ASSEMBLY | IG_PDF_PRIV_PERM_ACCESSIBLE;
// Get document security data structure.
IG_PDF_doc_get_security_data(pdfDocument, &securityData);
if (securityData == NULL)
{
// Initialize new security data.
memset(&newSecurityData, 0, sizeof(newSecurityData));
newSecurityData.size = sizeof(AT_PDF_SECURITYDATA);
newSecurityData.encryptMetadata = true;
newSecurityData.encryptAttachmentsOnly = false;
securityData = &newSecurityData;
}
// If there is a user password.
securityData->hasUserPW = (password.length() > 0);
// If the user password should be changed.
securityData->newUserPW = true;
// Set the user password.
// Clear the userPW field first before copying the user password.
memset(securityData->userPW, 0, sizeof(securityData->userPW));
// NOTE: We copy only the smallest amount needed as the debug version of strcpy_s writes
// debug guard bytes after the string which will cause the password to be incorrect.
size_t copyLimit = (std::min)(sizeof(securityData->userPW), password.length() + 1);
strcpy_s(securityData->userPW, copyLimit, password.c_str());
// Permissions flags to allow.
securityData->perms = (AT_DWORD)(IG_PDF_PERM_USER - negativePermissions);
// Password key's length.
securityData->keyLength = 32;
// Add support for Acrobat 5.0 and up.
securityData->revision = IG_PDF_REVISION_3;
// Set the encryption method to the AES algorithm.
securityData->encryptMethod = IG_PDF_STD_SECURITY_METHOD_AES_V2;
|
Then set the crypt handler and security data for the document as follows:
C and C++ |
Copy Code
|
HIG_PDF_ATOM securityHandler = IG_PDF_ATOM_NULL;
// Set a new security handler for the document.
IG_PDF_atom_from_string("Standard", &securityHandler);
IG_PDF_doc_set_new_crypt_handler(pdfDocument, securityHandler);
// Set the new security data structure for the specified document's new security handler.
IG_PDF_doc_set_new_security_data(pdfDocument, securityData);
|
Modify Security Settings
If the document is already a secured document, it is possible to create all new security features using the code described above and in the sample. It is also possible to change only specific security settings and leave others unchanged.
For example, to change only the password of an already-encrypted PDF document, create an AT_PDF_SECURITYDATA object using IG_PDF_doc_get_security_data(), into which is retrieved the existing security data for the document, instead of creating a new, empty AT_PDF_SECURITYDATA object and then changing only the password fields, leaving the other fields unchanged. Code to do this could look like:
C and C++ |
Copy Code
|
LPAT_PDF_SECURITYDATA securityData = NULL;
// Get the existing security data structure for the document's security handler.
IG_PDF_doc_get_security_data(pdfDocument, &securityData);
if (securityData != NULL)
{
size_t copyLimit = 0;
// If there is a user password.
securityData->hasUserPW = (passwordLength > 0);
// If the user password should be changed.
securityData->newUserPW = true;
// Set the user password.
// Clear the userPW field first before copying the user password.
memset(securityData->userPW, 0, sizeof(securityData->userPW));
// NOTE: We copy only the smallest amount needed as the debug version of strcpy_s writes
// debug guard bytes after the string which will cause the password to be incorrect.
size_t copyLimit = min(sizeof(securityData->userPW), passwordLength + 1);
strcpy_s(securityData->userPW, copyLimit, password);
// Set the new security data structure for the specified document's new security handler.
IG_PDF_doc_set_new_security_data(pdfDocument, securityData);
}
|
Remove Security from a PDF Document
As another option, use the IG_PDF_doc_set_new_crypt_handler() function with a null argument to remove all security from a secure PDF document. In this case, there is no need to use the IG_PDF_doc_set_new_security_data() function. Processing after opening the document is simply:
C and C++ |
Copy Code
|
IG_PDF_doc_set_new_crypt_handler(pdfDocument, IG_PDF_ATOM_NULL);
|
Save a PDF Document with New or Modified Security Settings
Finally, after the security settings are newly set or updated, or the security is removed completely, use the IG_mpi_file_save() function with the saving format set to IG_FORMAT_PDF to write the PDF document:
C and C++ |
Copy Code
|
const UINT firstPage = 0;
IG_mpi_file_save(filepath, document, firstPage, 0, pageCount, IG_FORMAT_PDF,
IG_MPI_SAVE_OVERWRITE);
|