Xbase++ Requires Chilkat v11.7.0+
Xbase++
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
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()