Skip to content

Commit 3a790f0

Browse files
committed
fix: One more example
1 parent d868db5 commit 3a790f0

File tree

2 files changed

+134
-15
lines changed

2 files changed

+134
-15
lines changed

examples/sign.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@
1111
# each license.
1212

1313
# This example shows how to sign an image with a C2PA manifest
14-
# and read the metadata added to the image.
14+
# using a callback signer and read the metadata added to the image.
1515

1616
import os
1717
import c2pa
18+
from cryptography.hazmat.primitives import hashes, serialization
19+
from cryptography.hazmat.primitives.asymmetric import ec
20+
from cryptography.hazmat.backends import default_backend
1821

1922
fixtures_dir = os.path.join(os.path.dirname(__file__), "../tests/fixtures/")
2023
output_dir = os.path.join(os.path.dirname(__file__), "../output/")
2124

22-
# ensure the output directory exists
25+
# Ensure the output directory exists
2326
if not os.path.exists(output_dir):
2427
os.makedirs(output_dir)
2528

@@ -33,26 +36,43 @@
3336
reader = c2pa.Reader("image/jpeg", file)
3437
print(reader.json())
3538

36-
# Create a signer from certificate and key files
39+
# Load certificates and private key (here from the test fixtures)
40+
# This is OK for development, but in production you should use a
41+
# secure way to load the certificates and private key.
3742
certs = open(fixtures_dir + "es256_certs.pem", "rb").read()
3843
key = open(fixtures_dir + "es256_private.key", "rb").read()
3944

40-
signer_info = c2pa.C2paSignerInfo(
41-
alg=b"es256", # Use bytes instead of encoded string
42-
sign_cert=certs,
43-
private_key=key,
44-
ta_url=b"http://timestamp.digicert.com" # Use bytes and add timestamp URL
45-
)
45+
# Define a callback signer function
46+
def callback_signer_es256(data: bytes) -> bytes:
47+
"""Callback function that signs data using ES256 algorithm."""
48+
private_key = serialization.load_pem_private_key(
49+
key,
50+
password=None,
51+
backend=default_backend()
52+
)
53+
signature = private_key.sign(
54+
data,
55+
ec.ECDSA(hashes.SHA256())
56+
)
57+
return signature
4658

47-
signer = c2pa.Signer.from_info(signer_info)
59+
# Create a signer using the callback function we defined
60+
signer = c2pa.Signer.from_callback(
61+
callback=callback_signer_es256,
62+
alg=c2pa.C2paSigningAlg.ES256,
63+
certs=certs.decode('utf-8'),
64+
tsa_url="http://timestamp.digicert.com"
65+
)
4866

4967
# Create a manifest definition as a dictionary
68+
# This manifest follows the V2 manifest format
5069
manifest_definition = {
5170
"claim_generator": "python_example",
5271
"claim_generator_info": [{
5372
"name": "python_example",
5473
"version": "0.0.1",
5574
}],
75+
"claim_version": 2,
5676
"format": "image/jpeg",
5777
"title": "Python Example Image",
5878
"ingredients": [],
@@ -73,13 +93,20 @@
7393
]
7494
}
7595

96+
# Create the builder with the manifest definition
7697
builder = c2pa.Builder(manifest_definition)
7798

78-
# Sign the image
79-
print("\nSigning the image...")
80-
with open(fixtures_dir + "C.jpg", "rb") as source:
81-
with open(output_dir + "C_signed.jpg", "wb") as dest:
82-
result = builder.sign(signer, "image/jpeg", source, dest)
99+
# Sign the image with the signer created above,
100+
# which will use the callback signer
101+
print("\nSigning the image file...")
102+
builder.sign_file(
103+
source_path=fixtures_dir + "C.jpg",
104+
dest_path=output_dir + "C_signed.jpg",
105+
signer=signer
106+
)
107+
108+
# Clean up the signer
109+
signer.close()
83110

84111
# Read the signed image to verify
85112
print("\nReading signed image metadata:")

examples/sign_using_signer_info.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Copyright 2025 Adobe. All rights reserved.
2+
# This file is licensed to you under the Apache License,
3+
# Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4+
# or the MIT license (http://opensource.org/licenses/MIT),
5+
# at your option.
6+
# Unless required by applicable law or agreed to in writing,
7+
# this software is distributed on an "AS IS" BASIS, WITHOUT
8+
# WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
9+
# implied. See the LICENSE-MIT and LICENSE-APACHE files for the
10+
# specific language governing permissions and limitations under
11+
# each license.
12+
13+
# This example shows how to sign an image with a C2PA manifest
14+
# and read the metadata added to the image.
15+
16+
import os
17+
import c2pa
18+
19+
fixtures_dir = os.path.join(os.path.dirname(__file__), "../tests/fixtures/")
20+
output_dir = os.path.join(os.path.dirname(__file__), "../output/")
21+
22+
# Ensure the output directory exists
23+
if not os.path.exists(output_dir):
24+
os.makedirs(output_dir)
25+
26+
print("c2pa version:")
27+
version = c2pa.sdk_version()
28+
print(version)
29+
30+
# Read existing C2PA metadata from the file
31+
print("\nReading existing C2PA metadata:")
32+
with open(fixtures_dir + "C.jpg", "rb") as file:
33+
reader = c2pa.Reader("image/jpeg", file)
34+
print(reader.json())
35+
36+
# Create a signer from certificate and key files
37+
certs = open(fixtures_dir + "es256_certs.pem", "rb").read()
38+
key = open(fixtures_dir + "es256_private.key", "rb").read()
39+
40+
signer_info = c2pa.C2paSignerInfo(
41+
alg=b"es256", # Use bytes instead of encoded string
42+
sign_cert=certs,
43+
private_key=key,
44+
ta_url=b"http://timestamp.digicert.com" # Use bytes and add timestamp URL
45+
)
46+
47+
signer = c2pa.Signer.from_info(signer_info)
48+
49+
# Create a manifest definition as a dictionary
50+
# This examples signs using a V1 manifest
51+
manifest_definition = {
52+
"claim_generator": "python_example",
53+
"claim_generator_info": [{
54+
"name": "python_example",
55+
"version": "0.0.1",
56+
}],
57+
"format": "image/jpeg",
58+
"title": "Python Example Image",
59+
"ingredients": [],
60+
"assertions": [
61+
{
62+
"label": "c2pa.actions",
63+
"data": {
64+
"actions": [
65+
{
66+
"action": "c2pa.created",
67+
"parameters": {
68+
# could hold additional information about this step
69+
}
70+
}
71+
]
72+
}
73+
}
74+
]
75+
}
76+
77+
builder = c2pa.Builder(manifest_definition)
78+
79+
# Sign the image
80+
print("\nSigning the image...")
81+
with open(fixtures_dir + "C.jpg", "rb") as source:
82+
with open(output_dir + "C_signed.jpg", "wb") as dest:
83+
result = builder.sign(signer, "image/jpeg", source, dest)
84+
85+
# Read the signed image to verify
86+
print("\nReading signed image metadata:")
87+
with open(output_dir + "C_signed.jpg", "rb") as file:
88+
reader = c2pa.Reader("image/jpeg", file)
89+
print(reader.json())
90+
91+
print("\nExample completed successfully!")
92+

0 commit comments

Comments
 (0)