Sample code for 30+ languages & platforms
PureBasic Requires Chilkat v11.7.0+

Encrypt a PDF for a Certificate Instead of a Password

See more PDF Protection Examples

Demonstrates certificate security, where a PDF is encrypted for one or more recipients and each opens it with their own certificate and private key. No password is involved. Only the public certificate of a recipient is needed to encrypt. Each recipient has its own permissions, and the changeSecurity permission gives a recipient owner rights. PreLoadCheck tells an application that a file is certificate-encrypted and which certificates can open it. A PDF that cannot be opened, because no matching certificate and private key were provided, fails to load.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkCert.pb"
IncludeFile "CkPdf.pb"
IncludeFile "CkJsonObject.pb"

Procedure ChilkatExample()

    success.i = 0

    ;  This example requires the Chilkat API to have been previously unlocked.
    ;  See Global Unlock Sample for sample code.

    ;  The PDF used in this example is available at two_page_memo.pdf

    ;  The recipient's certificate.  Only the public certificate is needed to encrypt.
    recipient.i = CkCert::ckCreate()
    If recipient.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkCert::ckLoadFromFile(recipient,"qa_data/certs/recipient.cer")
    If success = 0
        Debug CkCert::ckLastErrorText(recipient)
        CkCert::ckDispose(recipient)
        ProcedureReturn
    EndIf

    pdf.i = CkPdf::ckCreate()
    If pdf.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkPdf::ckLoadFile(pdf,"qa_data/pdf/two_page_memo.pdf")
    If success = 0
        Debug CkPdf::ckLastErrorText(pdf)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        ProcedureReturn
    EndIf

    ;  Call AddEncryptCert once for each recipient.
    success = CkPdf::ckAddEncryptCert(pdf,recipient)
    If success = 0
        Debug CkPdf::ckLastErrorText(pdf)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        ProcedureReturn
    EndIf

    ;  recipientPermissions[0] belongs to the first certificate added.  changeSecurity gives that
    ;  recipient owner rights, so the file can be managed later.
    json.i = CkJsonObject::ckCreate()
    If json.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::ckUpdateString(json,"method","certificate")
    CkJsonObject::ckUpdateBool(json,"recipientPermissions[0].changeSecurity",1)

    jsonOut.i = CkJsonObject::ckCreate()
    If jsonOut.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkPdf::ckProtection(pdf,"encrypt",json,jsonOut)
    If success = 0
        Debug CkPdf::ckLastErrorText(pdf)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        ProcedureReturn
    EndIf

    Debug "method: " + CkJsonObject::ckStringOf(jsonOut,"pending.method")
    Debug "algorithm: " + CkJsonObject::ckStringOf(jsonOut,"pending.algorithm")
    Debug "recipients: " + Str(CkJsonObject::ckSizeOfArray(jsonOut,"pending.recipients"))

    success = CkPdf::ckWriteFile(pdf,"qa_output/memo_for_recipient.pdf")
    If success = 0
        Debug CkPdf::ckLastErrorText(pdf)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        ProcedureReturn
    EndIf

    ;  PreLoadCheck says how the file is protected, without loading it.
    reader.i = CkPdf::ckCreate()
    If reader.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    info.i = CkJsonObject::ckCreate()
    If info.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkPdf::ckPreLoadCheck(reader,"qa_output/memo_for_recipient.pdf",info)
    If success = 0
        Debug CkPdf::ckLastErrorText(reader)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        CkPdf::ckDispose(reader)
        CkJsonObject::ckDispose(info)
        ProcedureReturn
    EndIf

    Debug "saved file, method: " + CkJsonObject::ckStringOf(info,"method")
    Debug "saved file, recipients: " + Str(CkJsonObject::ckSizeOfArray(info,"recipients"))

    ;  The recipient opens it with the certificate and its private key, here from a .pfx file.
    ;  (On Windows, a certificate that is installed in the Windows certificate store with its private
    ;  key is found automatically when the PDF is loaded, and SetDecryptCert is not needed for it.)
    myCert.i = CkCert::ckCreate()
    If myCert.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkCert::ckLoadPfxFile(myCert,"qa_data/pfx/recipient.pfx","pfx-password")
    If success = 0
        Debug CkCert::ckLastErrorText(myCert)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        CkPdf::ckDispose(reader)
        CkJsonObject::ckDispose(info)
        CkCert::ckDispose(myCert)
        ProcedureReturn
    EndIf

    success = CkPdf::ckSetDecryptCert(reader,myCert)
    If success = 0
        Debug CkPdf::ckLastErrorText(reader)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        CkPdf::ckDispose(reader)
        CkJsonObject::ckDispose(info)
        CkCert::ckDispose(myCert)
        ProcedureReturn
    EndIf

    success = CkPdf::ckLoadFile(reader,"qa_output/memo_for_recipient.pdf")
    If success = 0
        Debug CkPdf::ckLastErrorText(reader)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        CkPdf::ckDispose(reader)
        CkJsonObject::ckDispose(info)
        CkCert::ckDispose(myCert)
        ProcedureReturn
    EndIf

    empty.i = CkJsonObject::ckCreate()
    If empty.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    loadedInfo.i = CkJsonObject::ckCreate()
    If loadedInfo.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkPdf::ckProtection(reader,"getInfo",empty,loadedInfo)
    If success = 0
        Debug CkPdf::ckLastErrorText(reader)
        CkCert::ckDispose(recipient)
        CkPdf::ckDispose(pdf)
        CkJsonObject::ckDispose(json)
        CkJsonObject::ckDispose(jsonOut)
        CkPdf::ckDispose(reader)
        CkJsonObject::ckDispose(info)
        CkCert::ckDispose(myCert)
        CkJsonObject::ckDispose(empty)
        CkJsonObject::ckDispose(loadedInfo)
        ProcedureReturn
    EndIf

    Debug "opened with: " + CkJsonObject::ckStringOf(loadedInfo,"loaded.openedWith")
    Debug "pages: " + Str(CkPdf::ckNumPages(reader))

    ;  Sample output:

    ;  method: certificate
    ;  algorithm: aes-256
    ;  recipients: 1
    ;  saved file, method: certificate
    ;  saved file, recipients: 1
    ;  opened with: certificate
    ;  pages: 2


    CkCert::ckDispose(recipient)
    CkPdf::ckDispose(pdf)
    CkJsonObject::ckDispose(json)
    CkJsonObject::ckDispose(jsonOut)
    CkPdf::ckDispose(reader)
    CkJsonObject::ckDispose(info)
    CkCert::ckDispose(myCert)
    CkJsonObject::ckDispose(empty)
    CkJsonObject::ckDispose(loadedInfo)


    ProcedureReturn
EndProcedure