PureBasic Requires Chilkat v11.7.0+
PureBasic
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 PureBasic Downloads
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 signing certificate, with its private key.
cert.i = CkCert::ckCreate()
If cert.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkCert::ckLoadPfxFile(cert,"qa_data/pfx/myPdfSigningCert.pfx","secret")
If success = 0
Debug CkCert::ckLastErrorText(cert)
CkCert::ckDispose(cert)
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(cert)
CkPdf::ckDispose(pdf)
ProcedureReturn
EndIf
; Encrypt with AES-256 and do not permit modifying.
CkPdf::setCkUserPassword(pdf, "user-secret")
CkPdf::setCkOwnerPassword(pdf, "owner-secret")
json.i = CkJsonObject::ckCreate()
If json.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkJsonObject::ckUpdateBool(json,"permissions.modify",0)
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(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
ProcedureReturn
EndIf
; The encryption is still pending. SignPdf applies it first and signs the encrypted result.
success = CkPdf::ckSetSigningCert(pdf,cert)
If success = 0
Debug CkPdf::ckLastErrorText(pdf)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
ProcedureReturn
EndIf
sigOpts.i = CkJsonObject::ckCreate()
If sigOpts.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkJsonObject::ckUpdateBool(sigOpts,"invisibleSignature",1)
CkJsonObject::ckUpdateInt(sigOpts,"signingCertificateV2",1)
CkJsonObject::ckUpdateInt(sigOpts,"signingTime",1)
success = CkPdf::ckSignPdf(pdf,sigOpts,"qa_output/memo_encrypted_signed.pdf")
If success = 0
Debug CkPdf::ckLastErrorText(pdf)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
ProcedureReturn
EndIf
; The result is encrypted and signed.
check.i = CkPdf::ckCreate()
If check.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkPdf::setCkUserPassword(check, "user-secret")
success = CkPdf::ckLoadFile(check,"qa_output/memo_encrypted_signed.pdf")
If success = 0
Debug CkPdf::ckLastErrorText(check)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
ProcedureReturn
EndIf
empty.i = CkJsonObject::ckCreate()
If empty.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::ckProtection(check,"getInfo",empty,info)
If success = 0
Debug CkPdf::ckLastErrorText(check)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
ProcedureReturn
EndIf
Debug "algorithm: " + CkJsonObject::ckStringOf(info,"loaded.algorithm")
Debug "signatures: " + Str(CkPdf::ckNumSignatures(check))
sigInfo.i = CkJsonObject::ckCreate()
If sigInfo.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
verified.i = CkPdf::ckVerifySignature(check,0,sigInfo)
Debug "signature verifies: " + Str(verified)
; 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.
success = CkPdf::ckSetSigningCert(check,cert)
If success = 0
Debug CkPdf::ckLastErrorText(check)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
ProcedureReturn
EndIf
success = CkPdf::ckSignPdf(check,sigOpts,"qa_output/memo_signed_twice.pdf")
If success = 0
Debug "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.
owner.i = CkPdf::ckCreate()
If owner.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkPdf::setCkUserPassword(owner, "user-secret")
CkPdf::setCkOwnerPassword(owner, "owner-secret")
success = CkPdf::ckLoadFile(owner,"qa_output/memo_encrypted_signed.pdf")
If success = 0
Debug CkPdf::ckLastErrorText(owner)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
CkPdf::ckDispose(owner)
ProcedureReturn
EndIf
success = CkPdf::ckSetSigningCert(owner,cert)
If success = 0
Debug CkPdf::ckLastErrorText(owner)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
CkPdf::ckDispose(owner)
ProcedureReturn
EndIf
success = CkPdf::ckSignPdf(owner,sigOpts,"qa_output/memo_signed_twice.pdf")
If success = 0
Debug CkPdf::ckLastErrorText(owner)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
CkPdf::ckDispose(owner)
ProcedureReturn
EndIf
twice.i = CkPdf::ckCreate()
If twice.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkPdf::setCkUserPassword(twice, "user-secret")
success = CkPdf::ckLoadFile(twice,"qa_output/memo_signed_twice.pdf")
If success = 0
Debug CkPdf::ckLastErrorText(twice)
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
CkPdf::ckDispose(owner)
CkPdf::ckDispose(twice)
ProcedureReturn
EndIf
Debug "signatures after signing with owner rights: " + Str(CkPdf::ckNumSignatures(twice))
verified = CkPdf::ckVerifySignature(twice,0,sigInfo)
Debug "first signature still verifies: " + Str(verified)
verified = CkPdf::ckVerifySignature(twice,1,sigInfo)
Debug "second signature verifies: " + Str(verified)
; 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
CkCert::ckDispose(cert)
CkPdf::ckDispose(pdf)
CkJsonObject::ckDispose(json)
CkJsonObject::ckDispose(jsonOut)
CkJsonObject::ckDispose(sigOpts)
CkPdf::ckDispose(check)
CkJsonObject::ckDispose(empty)
CkJsonObject::ckDispose(info)
CkJsonObject::ckDispose(sigInfo)
CkPdf::ckDispose(owner)
CkPdf::ckDispose(twice)
ProcedureReturn
EndProcedure