Implements the ZIP embedding method from the C2PA Technical Specification. Many document formats are ZIP archives with a fixed internal layout — EPUB, Office Open XML (DOCX/XLSX/PPTX), OpenDocument (ODT/ODS/ODP) and OpenXPS — and all embed a C2PA Manifest Store through this single transport.
The Manifest Store is stored as a dedicated ZIP entry at a fixed location:
| Property | Value |
|---|---|
| Path | META-INF/content_credential.c2pa |
| Compression | Stored (method 0, uncompressed) |
| Encryption | None |
| General-purpose bit flag | 0 |
| Media type | As recommended for external manifests |
Embedding appends the manifest entry before the central directory, so existing entries keep their byte offsets; the central directory and end-of-central-directory record are then rebuilt. All parsing is bounds-checked against untrusted input, and ZIP64 archives are rejected (fail-closed) rather than mis-parsed.
Zero dependencies.
[dependencies]
c2pa-zip = "0.1"use c2pa_zip::embed_manifest;
let doc: &[u8] = /* .epub / .docx / .odt / .oxps bytes */;
let manifest: &[u8] = /* C2PA Manifest Store bytes */;
// Insert (or replace) the manifest entry; existing entries stay byte-stable.
let signed = embed_manifest(doc, manifest).unwrap();use c2pa_zip::read_manifest;
// Some(bytes) when a manifest is present, None when the archive has none.
let manifest = read_manifest(&signed).unwrap();use c2pa_zip::remove_manifest;
let stripped = remove_manifest(&signed).unwrap();use c2pa_zip::verify;
let report = verify(&signed).unwrap();
// report.has_manifest, report.manifest_len, report.is_valid_zip- The Manifest Store is a single stored (uncompressed) ZIP entry at
META-INF/content_credential.c2pa embed_manifestreplaces any existing manifest entry, so the archive always carries at most one; when none is present the existing entries keep their exact byte offsetsremove_manifestrebuilds the archive without the manifest entry, recomputing local-header offsets and the central directoryverifyreports transport-level structure only: whether the archive parses and whether a manifest is present- ZIP64 archives (identified by sentinel values in the EOCD or central directory) are rejected; a trailing ZIP comment is tolerated when locating the EOCD
This crate is the ZIP transport only: it reads, writes, and removes a C2PA Manifest Store stored as a ZIP entry. Manifest construction, signing, and hard/soft binding (the collection-data-hash) are out of scope; use the c2pa SDK for those. verify performs structural checks (presence + parseability), not hard-binding validation.
| Crate | Description |
|---|---|
| c2pa-fonts | OpenType/TrueType (SFNT) font embedding |
| c2pa-warc | WARC web archive embedding (ISO 28500) |
| c2pa-structured-text | Structured text embedding via ASCII armour delimiters |
| c2pa-text-binding | Soft binding and content fingerprinting for text assets |
| c2pa-rs | Official C2PA SDK |
Found a vulnerability? Please report it privately — see SECURITY.md.
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Built by WritersLogic