Zig Requires Chilkat v11.0.0+
Zig
Validate a .pkpass Archive
See more Digital Signatures Examples
Opens a .pkpass archive (which is just a .zip renamed to .pkpass) and validates the contents. The hashes in the manifest are compared with the computed hash values for each individual file. If all computed hash values match, then the signature is verified.Chilkat Zig Downloads
const std = @import("std");
const chilkat = @import("chilkat");
pub fn main(init: std.process.Init) !void {
const alloc = init.arena.allocator();
var success: bool = false;
// This example assumes the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
const crypt = try chilkat.Crypt2.init();
defer crypt.deinit();
const zip = try chilkat.Zip.init();
defer zip.deinit();
success = if (zip.openZip("qa_data/pkpass/invalid.pkpass")) true else |_| false;
if (!success) {
std.debug.print("{s}\n", .{try zip.getLastErrorText(alloc)});
return;
}
// Get the contents of the manifest.json file, which contains something like this:
// {
// "icon.png" : "0296b01347b3173e98438a003b0e88986340b2d8",
// "logo.png" : "25de09e2d3b01ce1fe00c2ca9a90a2be1aaa05cf",
// "icon@2x.png" : "5afd9585b08c65fdf105a90c8bd643407cba2787",
// "pass.json" : "145ea5a5db784fff485126c77ecf7a1fc2a88ee7",
// "strip@2x.png" : "468fa7bc93e6b55342b56fda09bdce7c829d7d46",
// "strip.png" : "736d01f84cb73d06e8a9932e43076d68f19461ff"
// }
const ent = try chilkat.ZipEntry.init();
defer ent.deinit();
success = zip.entryOf("manifest.json", ent);
if (!success) {
std.debug.print("{s}\n", .{try zip.getLastErrorText(alloc)});
return;
}
// Get the exact content of the manifest.json for later signature verification.
const bd_manifest = try chilkat.BinData.init();
defer bd_manifest.deinit();
success = if (ent.unzipToBd(bd_manifest)) true else |_| false;
const json = try chilkat.JsonObject.init();
defer json.deinit();
json.setEmitCompact(false);
json.load(try ent.unzipToString(alloc, 0, "utf-8")) catch {};
std.debug.print("{s}\n", .{try json.emit(alloc)});
// For each file in the JSON, get the filename and hex hash value.
crypt.setEncodingMode("hexlower");
crypt.setHashAlgorithm("sha1");
var some_hashes_failed: bool = false;
var filename: [:0]const u8 = "";
const sb_hash_hex = try chilkat.StringBuilder.init();
defer sb_hash_hex.deinit();
const bd_file_data = try chilkat.BinData.init();
defer bd_file_data.deinit();
const num_members = json.getSize();
var i: i32 = 0;
while (i < num_members) {
filename = try json.nameAt(alloc, i);
sb_hash_hex.clear();
sb_hash_hex.append(try json.stringAt(alloc, i)) catch {};
success = zip.entryOf(filename, ent);
if (!success) {
std.debug.print("{s}\n", .{try zip.getLastErrorText(alloc)});
return;
}
// Get the data for this file.
bd_file_data.clear() catch {};
success = if (ent.unzipToBd(bd_file_data)) true else |_| false;
const computed_hash_hex = try crypt.hashBdENC(alloc, bd_file_data);
if (!sb_hash_hex.contentsEqual(computed_hash_hex, false)) {
std.debug.print("Computed hash does not match stored hash for {s}\n", .{filename});
std.debug.print(" computed: {s}\n", .{computed_hash_hex});
std.debug.print(" stored: {s}\n", .{try sb_hash_hex.getAsString(alloc)});
some_hashes_failed = true;
} else {
std.debug.print("hash verified for {s}({s})\n", .{ filename, computed_hash_hex });
}
i = i + 1;
}
if (some_hashes_failed) {
std.debug.print("Some hashes failed.\n", .{});
return;
}
// Let's verify the signature..
// First get the signature.
success = zip.entryOf("signature", ent);
if (!success) {
std.debug.print("{s}\n", .{try zip.getLastErrorText(alloc)});
return;
}
const bd_signature = try chilkat.BinData.init();
defer bd_signature.deinit();
success = if (ent.unzipToBd(bd_signature)) true else |_| false;
// Show the contents of the signature in base64 encoding.
std.debug.print("Signature:\n", .{});
std.debug.print("{s}\n", .{try bd_signature.getEncoded(alloc, "base64_mime")});
std.debug.print("----\n", .{});
// Verify the signature against the manifest.json
crypt.setEncodingMode("base64");
const verified = if (crypt.verifyBdENC(bd_manifest, try bd_signature.getEncoded(alloc, "base64"))) true else |_| false;
if (!verified) {
std.debug.print("{s}\n", .{try crypt.getLastErrorText(alloc)});
}
std.debug.print("signature verified = {}\n", .{verified});
}