Zig Requires Chilkat v11.7.0+
Zig
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 Zig Downloads
const std = @import("std");
const chilkat = @import("chilkat");
pub fn main(init: std.process.Init) !void {
const alloc = init.arena.allocator();
// 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.
const cert = try chilkat.Cert.init();
defer cert.deinit();
cert.loadPfxFile("qa_data/pfx/myPdfSigningCert.pfx", "secret") catch {
std.debug.print("{s}\n", .{try cert.getLastErrorText(alloc)});
return;
};
const pdf = try chilkat.Pdf.init();
defer pdf.deinit();
pdf.loadFile("qa_data/pdf/two_page_memo.pdf") catch {
std.debug.print("{s}\n", .{try pdf.getLastErrorText(alloc)});
return;
};
// Encrypt with AES-256 and do not permit modifying.
pdf.setUserPassword("user-secret");
pdf.setOwnerPassword("owner-secret");
const json = try chilkat.JsonObject.init();
defer json.deinit();
json.updateBool("permissions.modify", false) catch {};
const json_out = try chilkat.JsonObject.init();
defer json_out.deinit();
pdf.protection("encrypt", json, json_out) catch {
std.debug.print("{s}\n", .{try pdf.getLastErrorText(alloc)});
return;
};
// The encryption is still pending. SignPdf applies it first and signs the encrypted result.
pdf.setSigningCert(cert) catch {
std.debug.print("{s}\n", .{try pdf.getLastErrorText(alloc)});
return;
};
const sig_opts = try chilkat.JsonObject.init();
defer sig_opts.deinit();
sig_opts.updateBool("invisibleSignature", true) catch {};
sig_opts.updateInt("signingCertificateV2", 1) catch {};
sig_opts.updateInt("signingTime", 1) catch {};
pdf.signPdf(sig_opts, "qa_output/memo_encrypted_signed.pdf") catch {
std.debug.print("{s}\n", .{try pdf.getLastErrorText(alloc)});
return;
};
// The result is encrypted and signed.
const check = try chilkat.Pdf.init();
defer check.deinit();
check.setUserPassword("user-secret");
check.loadFile("qa_output/memo_encrypted_signed.pdf") catch {
std.debug.print("{s}\n", .{try check.getLastErrorText(alloc)});
return;
};
const empty = try chilkat.JsonObject.init();
defer empty.deinit();
const info = try chilkat.JsonObject.init();
defer info.deinit();
check.protection("getInfo", empty, info) catch {
std.debug.print("{s}\n", .{try check.getLastErrorText(alloc)});
return;
};
std.debug.print("algorithm: {s}\n", .{try info.stringOf(alloc, "loaded.algorithm")});
std.debug.print("signatures: {d}\n", .{check.getNumSignatures()});
const sig_info = try chilkat.JsonObject.init();
defer sig_info.deinit();
var verified: bool = if (check.verifySignature(0, sig_info)) true else |_| false;
std.debug.print("signature verifies: {}\n", .{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.
check.setSigningCert(cert) catch {
std.debug.print("{s}\n", .{try check.getLastErrorText(alloc)});
return;
};
check.signPdf(sig_opts, "qa_output/memo_signed_twice.pdf") catch {
std.debug.print("A second signature was refused: the permissions do not allow it.\n", .{});
};
// 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.
const owner = try chilkat.Pdf.init();
defer owner.deinit();
owner.setUserPassword("user-secret");
owner.setOwnerPassword("owner-secret");
owner.loadFile("qa_output/memo_encrypted_signed.pdf") catch {
std.debug.print("{s}\n", .{try owner.getLastErrorText(alloc)});
return;
};
owner.setSigningCert(cert) catch {
std.debug.print("{s}\n", .{try owner.getLastErrorText(alloc)});
return;
};
owner.signPdf(sig_opts, "qa_output/memo_signed_twice.pdf") catch {
std.debug.print("{s}\n", .{try owner.getLastErrorText(alloc)});
return;
};
const twice = try chilkat.Pdf.init();
defer twice.deinit();
twice.setUserPassword("user-secret");
twice.loadFile("qa_output/memo_signed_twice.pdf") catch {
std.debug.print("{s}\n", .{try twice.getLastErrorText(alloc)});
return;
};
std.debug.print("signatures after signing with owner rights: {d}\n", .{twice.getNumSignatures()});
verified = if (twice.verifySignature(0, sig_info)) true else |_| false;
std.debug.print("first signature still verifies: {}\n", .{verified});
verified = if (twice.verifySignature(1, sig_info)) true else |_| false;
std.debug.print("second signature verifies: {}\n", .{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
}