ImageGear for C and C++ on Linux v19.10 - Updated
Use PDF Security
User Guide > How to Work with... > Formats with Additional Functionality > PDF > How to... > Use PDF Security

Before working with a PDF document, make sure to initialize the PDF component (see Getting Started with PDF).

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:

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);