@@ -36,19 +36,18 @@ manifest_json = json.dumps({
3636
3737## Signing function
3838
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.
4040
4141``` py
4242# Example of using Python crypto to sign data using openssl with Ps256
4343from cryptography.hazmat.primitives import hashes, serialization
4444from cryptography.hazmat.primitives.asymmetric import padding
4545
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+ )
5251 signature = private_key.sign(
5352 data,
5453 padding.PSS(
7877 reader = c2pa.Reader.from_file(" path/to/media_file.jpg" )
7978
8079 # Print the JSON for a manifest.
81- print (" manifest store:" , reader.json())
80+ print (" Manifest store:" , reader.json())
8281
8382 # Get the active manifest.
8483 manifest = reader.get_active_manifest()
@@ -99,52 +98,51 @@ except Exception as err:
9998Use a ` Builder ` to add a manifest to an asset:
10099
101100``` 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 )
148146```
149147
150148## Stream-based operation
0 commit comments