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

Encrypt and Sign a PDF, and Sign an Encrypted PDF

See more PDF Protection Examples

Demonstrates signing together with encryption. A pending encrypt is applied by SignPdf before it signs, so one call produces a PDF that is both encrypted and signed. A PDF that is already encrypted can be signed too, and stays encrypted. When it was opened with only the user password its permissions decide: adding a signature field needs both the modify and the annotate permission. Loading the PDF with its owner password lifts that.

Chilkat Xbase++ Downloads

Xbase++
LOCAL nSuccess
LOCAL oCert
LOCAL oPdf
LOCAL oJson
LOCAL oJsonOut
LOCAL oSigOpts
LOCAL oCheck
LOCAL oEmpty
LOCAL oInfo
LOCAL oSigInfo
LOCAL nVerified
LOCAL oOwner
LOCAL oTwice

nSuccess := 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 signing certificate, with its private key.
oCert := CreateObject("Chilkat.Cert")
nSuccess := oCert:LoadPfxFile("qa_data/pfx/myPdfSigningCert.pfx", "secret")
IF (nSuccess == 0)
    ? oCert:LastErrorText
    oCert:destroy()
    RETURN
ENDIF

oPdf := CreateObject("Chilkat.Pdf")
nSuccess := oPdf:LoadFile("qa_data/pdf/two_page_memo.pdf")
IF (nSuccess == 0)
    ? oPdf:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    RETURN
ENDIF

//  Encrypt with AES-256 and do not permit modifying.
oPdf:UserPassword := "user-secret"
oPdf:OwnerPassword := "owner-secret"
oJson := CreateObject("Chilkat.JsonObject")
oJson:UpdateBool("permissions.modify", 0)
oJsonOut := CreateObject("Chilkat.JsonObject")
nSuccess := oPdf:Protection("encrypt", oJson, oJsonOut)
IF (nSuccess == 0)
    ? oPdf:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    RETURN
ENDIF

//  The encryption is still pending.  SignPdf applies it first and signs the encrypted result.
nSuccess := oPdf:SetSigningCert(oCert)
IF (nSuccess == 0)
    ? oPdf:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    RETURN
ENDIF

oSigOpts := CreateObject("Chilkat.JsonObject")
oSigOpts:UpdateBool("invisibleSignature", 1)
oSigOpts:UpdateInt("signingCertificateV2", 1)
oSigOpts:UpdateInt("signingTime", 1)
nSuccess := oPdf:SignPdf(oSigOpts, "qa_output/memo_encrypted_signed.pdf")
IF (nSuccess == 0)
    ? oPdf:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    RETURN
ENDIF

//  The result is encrypted and signed.
oCheck := CreateObject("Chilkat.Pdf")
oCheck:UserPassword := "user-secret"
nSuccess := oCheck:LoadFile("qa_output/memo_encrypted_signed.pdf")
IF (nSuccess == 0)
    ? oCheck:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    RETURN
ENDIF

oEmpty := CreateObject("Chilkat.JsonObject")
oInfo := CreateObject("Chilkat.JsonObject")
nSuccess := oCheck:Protection("getInfo", oEmpty, oInfo)
IF (nSuccess == 0)
    ? oCheck:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    RETURN
ENDIF

? "algorithm: " + oInfo:StringOf("loaded.algorithm")
? "signatures: " + Str(oCheck:NumSignatures)
oSigInfo := CreateObject("Chilkat.JsonObject")
nVerified := oCheck:VerifySignature(0, oSigInfo)
? "signature verifies: " + Str(nVerified)

//  Signing an encrypted PDF.  This one was opened with only the user password, and its
//  permissions do not allow modifying, so another signature is refused.
nSuccess := oCheck:SetSigningCert(oCert)
IF (nSuccess == 0)
    ? oCheck:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    oSigInfo:destroy()
    RETURN
ENDIF

nSuccess := oCheck:SignPdf(oSigOpts, "qa_output/memo_signed_twice.pdf")
IF (nSuccess == 0)
    ? "A second signature was refused: the permissions do not allow it."
ENDIF

//  Loaded with the owner password, the same PDF can be signed.  It stays encrypted, and the
//  first signature stays valid because the new one is added as an incremental update.
oOwner := CreateObject("Chilkat.Pdf")
oOwner:UserPassword := "user-secret"
oOwner:OwnerPassword := "owner-secret"
nSuccess := oOwner:LoadFile("qa_output/memo_encrypted_signed.pdf")
IF (nSuccess == 0)
    ? oOwner:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    oSigInfo:destroy()
    oOwner:destroy()
    RETURN
ENDIF

nSuccess := oOwner:SetSigningCert(oCert)
IF (nSuccess == 0)
    ? oOwner:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    oSigInfo:destroy()
    oOwner:destroy()
    RETURN
ENDIF

nSuccess := oOwner:SignPdf(oSigOpts, "qa_output/memo_signed_twice.pdf")
IF (nSuccess == 0)
    ? oOwner:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    oSigInfo:destroy()
    oOwner:destroy()
    RETURN
ENDIF

oTwice := CreateObject("Chilkat.Pdf")
oTwice:UserPassword := "user-secret"
nSuccess := oTwice:LoadFile("qa_output/memo_signed_twice.pdf")
IF (nSuccess == 0)
    ? oTwice:LastErrorText
    oCert:destroy()
    oPdf:destroy()
    oJson:destroy()
    oJsonOut:destroy()
    oSigOpts:destroy()
    oCheck:destroy()
    oEmpty:destroy()
    oInfo:destroy()
    oSigInfo:destroy()
    oOwner:destroy()
    oTwice:destroy()
    RETURN
ENDIF

? "signatures after signing with owner rights: " + Str(oTwice:NumSignatures)
nVerified := oTwice:VerifySignature(0, oSigInfo)
? "first signature still verifies: " + Str(nVerified)
nVerified := oTwice:VerifySignature(1, oSigInfo)
? "second signature verifies: " + Str(nVerified)

//  Sample output:

//  algorithm: aes-256
//  signatures: 1
//  signature verifies: True
//  A second signature was refused: the permissions do not allow it.
//  signatures after signing with owner rights: 2
//  first signature still verifies: True
//  second signature verifies: True

oCert:destroy()
oPdf:destroy()
oJson:destroy()
oJsonOut:destroy()
oSigOpts:destroy()
oCheck:destroy()
oEmpty:destroy()
oInfo:destroy()
oSigInfo:destroy()
oOwner:destroy()
oTwice:destroy()