C2PA + OpenTDF integration library in Rust - combining content authenticity with trusted data encryption.
This library bridges C2PA (Coalition for Content Provenance and Authenticity) with OpenTDF (Open Trusted Data Format), enabling you to:
- Sign content with C2PA manifests to establish provenance and authenticity
- Encrypt signed content using OpenTDF for access control and data protection
- Decrypt and verify content to ensure both data integrity and authentic provenance
- Secure media distribution: Sign images/video with C2PA provenance, then encrypt with attribute-based access control
- Confidential content authenticity: Prove content origin while keeping it encrypted until authorized access
- Compliance workflows: Combine tamper-evident provenance with policy-enforced encryption
Add to your Cargo.toml
:
[dependencies]
c2pa_opentdf = { path = "../c2pa-opentdf-rs" }
For KAS (Key Access Service) support:
[dependencies]
c2pa_opentdf = { path = "../c2pa-opentdf-rs", features = ["kas"] }
use c2pa_opentdf::{C2paOpenTdf, Policy};
// Configure C2PA signing and OpenTDF encryption
let c2pa_tdf = C2paOpenTdf::builder()
.certificate_and_key("cert.pem", "private.pem")
.kas_url("https://kas.example.com")
.build()?;
// Read your content (must be a supported media type like PNG, JPG, etc.)
let image_data = std::fs::read("input.png")?;
// Sign with C2PA and encrypt with OpenTDF
let encrypted = c2pa_tdf.sign_and_encrypt(
&image_data,
"My Authenticated Image",
"output.tdf"
)?;
use c2pa_opentdf::{C2paOpenTdf, Policy};
let policy = Policy::new(
"unique-id".to_string(),
vec![], // attributes
vec!["user@example.com".to_string()], // dissemination list
);
let c2pa_tdf = C2paOpenTdf::builder()
.certificate_and_key("cert.pem", "private.pem")
.kas_url("https://kas.example.com")
.policy(policy)
.build()?;
let encrypted = c2pa_tdf.sign_and_encrypt(
&image_data,
"Confidential Report",
"report.tdf"
)?;
use c2pa_opentdf::{C2paOpenTdf, kas::KasClient};
// Create KAS client for decryption
let kas_client = KasClient::new("https://kas.example.com", "auth-token")?;
let c2pa_tdf = C2paOpenTdf::builder()
.certificate_and_key("cert.pem", "private.pem")
.kas_url("https://kas.example.com")
.build()?;
// Decrypt and verify C2PA provenance
let original_data = c2pa_tdf.decrypt_and_verify("report.tdf", &kas_client).await?;
The library follows the OpenTDF specification to integrate C2PA provenance with TDF encryption:
- C2PA Signing: Content is signed using ES256 (ECDSA with SHA-256), embedding provenance manifests directly in the media file
- Data Hashing: SHA-256 hash of the original data is stored as a C2PA assertion (
org.arkavo.c2pa_opentdf.data_hash
) - TDF Encryption: The C2PA-signed content is encrypted using OpenTDF's AES-256-GCM segmented encryption
- Manifest Storage: OpenTDF manifest includes C2PA metadata via MIME type and assertions
- Verification Chain: Decryption validates both TDF integrity (segments + GMAC) and C2PA provenance
Original Content → C2PA Sign → Signed Content → TDF Encrypt → Encrypted TDF
↓ ↓
Manifest Policy + KAS
Encrypted TDF → TDF Decrypt → Signed Content → C2PA Verify → Original Content
↓ ↓
KAS Manifest Check
- ✅ C2PA signing with ES256
- ✅ OpenTDF encryption with segmented AES-256-GCM
- ✅ Builder pattern for easy configuration
- ✅ Custom C2PA assertions for data integrity
- ✅ Integration with OpenTDF policy and KAS
- ✅ Decrypt and verify workflow (with
kas
feature) - 📋 Support for additional C2PA signing algorithms
- 📋 Custom assertion schemas for enhanced metadata
cargo build
cargo test
cargo test test_sign_and_encrypt
Test certificates are stored in tests/data/
. For production:
- Obtain proper C2PA signing certificates
- Source: https://github.com/contentauth/c2pa-rs/tree/main/sdk/tests/fixtures/certs
- Use ES256 (ECDSA with SHA-256) for signing
This library depends on opentdf-rs located at ../opentdf-rs
. Ensure the repository is cloned in the correct location.
Apache-2.0 (same as opentdf-rs)
See opentdf/spec for TDF3/ZTDF specification details.