@@ -36,19 +36,18 @@ manifest_json = json.dumps({
36
36
37
37
## Signing function
38
38
39
- The ` sign_ps256 ` function is [ defined in the library] ( https://github.com/contentauth/c2pa-python/blob/main/c2pa/c2pa_api/c2pa_api.py#L209 ) is used in both file-based and stream-based methods and is reproduced here to show how signing is performed.
39
+ The ` sign_ps256 ` function is [ defined in the library] ( https://github.com/contentauth/c2pa-python/blob/main/c2pa/c2pa_api/c2pa_api.py#L244 ) and used in both file-based and stream-based methods. It's reproduced here to show how signing is performed.
40
40
41
41
``` py
42
42
# Example of using Python crypto to sign data using openssl with Ps256
43
43
from cryptography.hazmat.primitives import hashes, serialization
44
44
from cryptography.hazmat.primitives.asymmetric import padding
45
45
46
- def sign_ps256 (data : bytes , key_path : str ) -> bytes :
47
- with open (key_path, " rb" ) as key_file:
48
- private_key = serialization.load_pem_private_key(
49
- key_file.read(),
50
- password = None ,
51
- )
46
+ def sign_ps256 (data : bytes , key : bytes ) -> bytes :
47
+ private_key = serialization.load_pem_private_key(
48
+ key,
49
+ password = None ,
50
+ )
52
51
signature = private_key.sign(
53
52
data,
54
53
padding.PSS(
78
77
reader = c2pa.Reader.from_file(" path/to/media_file.jpg" )
79
78
80
79
# Print the JSON for a manifest.
81
- print (" manifest store:" , reader.json())
80
+ print (" Manifest store:" , reader.json())
82
81
83
82
# Get the active manifest.
84
83
manifest = reader.get_active_manifest()
@@ -99,52 +98,51 @@ except Exception as err:
99
98
Use a ` Builder ` to add a manifest to an asset:
100
99
101
100
``` py
102
- try :
103
- # Define a function to sign the claim bytes
104
- # In this case we are using a pre-defined sign_ps256 method, passing in our private cert
105
- # Normally this cert would be kept safe in some other location
106
- def private_sign (data : bytes ) -> bytes :
107
- return sign_ps256(data, " tests/fixtures/ps256.pem" )
108
-
109
- # read our public certs into memory
110
- certs = open (data_dir + " ps256.pub" , " rb" ).read()
111
-
112
- # Create a signer from the private signer, certs and a time stamp service url
113
- signer = create_signer(private_sign, SigningAlg.PS256 , certs, " http://timestamp.digicert.com" )
114
-
115
- # Create a builder add a thumbnail resource and an ingredient file.
116
- builder = Builder(manifest_json)
117
-
118
- # The uri provided here "thumbnail" must match an identifier in the manifest definition.
119
- builder.add_resource_file(" thumbnail" , " tests/fixtures/A_thumbnail.jpg" )
120
-
121
- # Define an ingredient, in this case a parent ingredient named A.jpg, with a thumbnail
122
- ingredient_json = {
123
- " title" : " A.jpg" ,
124
- " relationship" : " parentOf" , # "parentOf", "componentOf" or "inputTo"
125
- " thumbnail" : {
126
- " identifier" : " thumbnail" ,
127
- " format" : " image/jpeg"
128
- }
129
- }
130
-
131
- # Add the ingredient to the builder loading information from a source file.
132
- builder.add_ingredient_file(ingredient_json, " tests/fixtures/A.jpg" )
133
-
134
- # At this point we could archive or unarchive our Builder to continue later.
135
- # In this example we use a bytearray for the archive stream.
136
- # all ingredients and resources will be saved in the archive
137
- archive = io.BytesIO(bytearray ())
138
- builder.to_archive(archive)
139
- archive.seek()
140
- builder = builder.from_archive(archive)
141
-
142
- # Sign and add our manifest to a source file, writing it to an output file.
143
- # This returns the binary manifest data that could be uploaded to cloud storage.
144
- c2pa_data = builder.sign_file(signer, " tests/fixtures/A.jpg" , " target/out.jpg" )
145
-
146
- except Exception as err:
147
- print (err)
101
+ def test_v2_sign (self ):
102
+ # Define source folder for any assets being read.
103
+ data_dir = " tests/fixtures/"
104
+ try :
105
+ key = open (data_dir + " ps256.pem" , " rb" ).read()
106
+ def sign (data : bytes ) -> bytes :
107
+ return sign_ps256(data, key)
108
+
109
+ certs = open (data_dir + " ps256.pub" , " rb" ).read()
110
+ # Create a local signer from a certificate pem file.
111
+ signer = create_signer(sign, SigningAlg.PS256 , certs, " http://timestamp.digicert.com" )
112
+
113
+ builder = Builder(manifest_def)
114
+
115
+ builder.add_ingredient_file(ingredient_def, data_dir + " A.jpg" )
116
+
117
+ builder.add_resource_file(" A.jpg" , data_dir + " A.jpg" )
118
+
119
+ builder.to_archive(open (" target/archive.zip" , " wb" ))
120
+
121
+ builder = Builder.from_archive(open (" target/archive.zip" , " rb" ))
122
+
123
+ with tempfile.TemporaryDirectory() as output_dir:
124
+ output_path = output_dir + " out.jpg"
125
+ if os.path.exists(output_path):
126
+ os.remove(output_path)
127
+ c2pa_data = builder.sign_file(signer, data_dir + " A.jpg" , output_dir + " out.jpg" )
128
+ assert len (c2pa_data) > 0
129
+
130
+ reader = Reader.from_file(output_dir + " out.jpg" )
131
+ print (reader.json())
132
+ manifest_store = json.loads(reader.json())
133
+ manifest = manifest_store[" manifests" ][manifest_store[" active_manifest" ]]
134
+ assert " python_test" in manifest[" claim_generator" ]
135
+ # Check custom title and format.
136
+ assert manifest[" title" ]== " My Title"
137
+ assert manifest,[" format" ] == " image/jpeg"
138
+ # There should be no validation status errors.
139
+ assert manifest.get(" validation_status" ) == None
140
+ assert manifest[" ingredients" ][0 ][" relationship" ] == " parentOf"
141
+ assert manifest[" ingredients" ][0 ][" title" ] == " A.jpg"
142
+
143
+ except Exception as e:
144
+ print (" Failed to sign manifest store: " + str (e))
145
+ exit (1 )
148
146
```
149
147
150
148
## Stream-based operation
@@ -182,54 +180,39 @@ except Exception as err:
182
180
Use a ` Builder ` to add a manifest to an asset:
183
181
184
182
``` py
183
+ from c2pa import Builder, Error, Reader, SigningAlg, create_signer, sdk_version, sign_ps256, version
184
+ ...
185
+ data_dir = " tests/fixtures/"
185
186
try :
186
- # Define a function to sign the claim bytes
187
- # In this case we are using a pre-defined sign_ps256 method, passing in our private cert
188
- # Normally this cert would be kept safe in some other location
189
- def private_sign (data : bytes ) -> bytes :
190
- return sign_ps256(data, " tests/fixtures/ps256.pem" )
191
-
192
- # read our public certs into memory
193
- certs = open (data_dir + " ps256.pub" , " rb" ).read()
194
-
195
- # Create a signer from the private signer, certs and a time stamp service url
196
- signer = create_signer(private_sign, SigningAlg.PS256 , certs, " http://timestamp.digicert.com" )
197
-
198
- # Create a builder add a thumbnail resource and an ingredient file.
199
- builder = Builder(manifest_json)
200
-
201
- # Add the resource from a stream
202
- a_thumbnail_jpg_stream = open (" tests/fixtures/A_thumbnail.jpg" , " rb" )
203
- builder.add_resource(" image/jpeg" , a_thumbnail_jpg_stream)
204
-
205
- # Define an ingredient, in this case a parent ingredient named A.jpg, with a thumbnail
206
- ingredient_json = {
207
- " title" : " A.jpg" ,
208
- " relationship" : " parentOf" , # "parentOf", "componentOf" or "inputTo"
209
- " thumbnail" : {
210
- " identifier" : " thumbnail" ,
211
- " format" : " image/jpeg"
212
- }
213
- }
214
-
215
- # Add the ingredient from a stream
216
- a_jpg_stream = open (" tests/fixtures/A.jpg" , " rb" )
217
- builder.add_ingredient(" image/jpeg" , a_jpg_stream)
218
-
219
- # At this point we could archive or unarchive our Builder to continue later.
220
- # In this example we use a bytearray for the archive stream.
221
- # all ingredients and resources will be saved in the archive
222
- archive = io.BytesIO(bytearray ())
223
- builder.to_archive(archive)
224
- archive.seek()
225
- builder = builder.from_archive(archive)
226
-
227
- # Sign the builder with a stream and output it to a stream
228
- # This returns the binary manifest data that could be uploaded to cloud storage.
229
- input_stream = open (" tests/fixtures/A.jpg" , " rb" )
230
- output_stream = open (" target/out.jpg" , " wb" )
231
- c2pa_data = builder.sign(signer, " image/jpeg" , input_stream, output_stream)
232
-
233
- except Exception as err:
234
- print (err)
187
+ key = open (data_dir + " ps256.pem" , " rb" ).read()
188
+ def sign (data : bytes ) -> bytes :
189
+ return sign_ps256(data, key)
190
+
191
+ certs = open (data_dir + " ps256.pub" , " rb" ).read()
192
+ # Create a local signer from a certificate pem file
193
+ signer = create_signer(sign, SigningAlg.PS256 , certs, " http://timestamp.digicert.com" )
194
+
195
+ builder = Builder(manifest_def)
196
+
197
+ builder.add_ingredient_file(ingredient_def, data_dir + " A.jpg" )
198
+ builder.add_resource_file(" A.jpg" , data_dir + " A.jpg" )
199
+ builder.to_archive(open (" target/archive.zip" , " wb" ))
200
+
201
+ builder = Builder.from_archive(open (" target/archive.zip" , " rb" ))
202
+
203
+ with tempfile.TemporaryDirectory() as output_dir:
204
+ output_path = output_dir + " out.jpg"
205
+ if os.path.exists(output_path):
206
+ os.remove(output_path)
207
+ c2pa_data = builder.sign_file(signer, data_dir + " A.jpg" , output_dir + " out.jpg" )
208
+ assert len (c2pa_data) > 0
209
+
210
+ reader = Reader.from_file(output_dir + " out.jpg" )
211
+ print (reader.json())
212
+ manifest_store = json.loads(reader.json())
213
+ manifest = manifest_store[" manifests" ][manifest_store[" active_manifest" ]]
214
+
215
+ except Exception as e:
216
+ print (" Failed to sign manifest store: " + str (e))
217
+ exit (1 )
235
218
```
0 commit comments