def set_policy(self, id_as_hex, request: http.Request): """ REST endpoint for setting a kFrag. TODO: Instead of taking a Request, use the apistar typing system to type a payload and validate / split it. TODO: Validate that the kfrag being saved is pursuant to an approved Policy (see #121). """ policy_message_kit = UmbralMessageKit.from_bytes(request.body) alice = self._alice_class.from_public_keys( {SigningPower: policy_message_kit.sender_pubkey_sig}) try: cleartext = self.verify_from(alice, policy_message_kit, decrypt=True) except self.InvalidSignature: # TODO: What do we do if the Policy isn't signed properly? pass kfrag = KFrag.from_bytes(cleartext) with ThreadedSession(self.db_engine) as session: self.datastore.attach_kfrag_to_saved_arrangement(alice, id_as_hex, kfrag, session=session) return # TODO: Return A 200, with whatever policy metadata.
def test_mocked_decentralized_grant(blockchain_alice, blockchain_bob, three_agents): # Monkey patch Policy Creation _token_agent, _miner_agent, policy_agent = three_agents policy_agent.blockchain.wait_for_receipt = MockPolicyCreation.wait_for_receipt policy_agent.contract.functions.createPolicy = MockPolicyCreation # Setup the policy details n = 3 policy_end_datetime = maya.now() + datetime.timedelta(days=5) label = b"this_is_the_path_to_which_access_is_being_granted" # Create the Policy, Grating access to Bob policy = blockchain_alice.grant(blockchain_bob, label, m=2, n=n, expiration=policy_end_datetime) # The number of accepted arrangements at least the number of Ursulas we're using (n) assert len(policy._accepted_arrangements) >= n # The number of actually enacted arrangements is exactly equal to n. assert len(policy._enacted_arrangements) == n # Let's look at the enacted arrangements. for kfrag in policy.kfrags: arrangement = policy._enacted_arrangements[kfrag] # Get the Arrangement from Ursula's datastore, looking up by hrac. # This will be changed in 180, when we use the Arrangement ID. proper_hrac = keccak_digest(bytes(blockchain_alice.stamp) + bytes(blockchain_bob.stamp) + label) retrieved_policy = arrangement.ursula.datastore.get_policy_arrangement(arrangement.id.hex().encode()) retrieved_kfrag = KFrag.from_bytes(retrieved_policy.kfrag) assert kfrag == retrieved_kfrag
def set_policy(self, id_as_hex, request: Request): """ REST endpoint for setting a kFrag. TODO: Instead of taking a Request, use the apistar typing system to type a payload and validate / split it. TODO: Validate that the kfrag being saved is pursuant to an approved Policy (see #121). """ policy_message_kit = UmbralMessageKit.from_bytes(request.body) alices_verifying_key = policy_message_kit.sender_pubkey_sig alice = self._alice_class.from_public_keys( {SigningPower: alices_verifying_key}) try: cleartext = self._verifier(alice, policy_message_kit, decrypt=True) except self.InvalidSignature: # TODO: Perhaps we log this? return Response(status_code=400) kfrag = KFrag.from_bytes(cleartext) if not kfrag.verify(signing_pubkey=alices_verifying_key): raise self.InvalidSignature("{} is invalid".format(kfrag)) with ThreadedSession(self.db_engine) as session: self.datastore.attach_kfrag_to_saved_arrangement(alice, id_as_hex, kfrag, session=session) # TODO: Sign the arrangement here. #495 return # TODO: Return A 200, with whatever policy metadata.
def test_federated_grant(federated_alice, federated_bob): # Setup the policy details m, n = 2, 3 policy_end_datetime = maya.now() + datetime.timedelta(days=5) label = b"this_is_the_path_to_which_access_is_being_granted" # Create the Policy, granting access to Bob policy = federated_alice.grant(federated_bob, label, m=m, n=n, expiration=policy_end_datetime) # The number of accepted arrangements at least the number of Ursulas we're using (n) assert len(policy._accepted_arrangements) >= n # The number of actually enacted arrangements is exactly equal to n. assert len(policy._enacted_arrangements) == n # Let's look at the enacted arrangements. for kfrag in policy.kfrags: arrangement = policy._enacted_arrangements[kfrag] # Get the Arrangement from Ursula's datastore, looking up by hrac. # This will be changed in 180, when we use the Arrangement ID. proper_hrac = keccak_digest(bytes(federated_alice.stamp) + bytes(federated_bob.stamp) + label) retrieved_policy = arrangement.ursula.datastore.get_policy_arrangement(arrangement.id.hex().encode()) retrieved_kfrag = KFrag.from_bytes(retrieved_policy.kfrag) assert kfrag == retrieved_kfrag
def test_kfrags(): vector_file = os.path.join('vectors', 'vectors_kfrags.json') try: with open(vector_file) as f: vector_suite = json.load(f) except OSError: raise verifying_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['verifying_key'])) delegating_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['delegating_key'])) receiving_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['receiving_key'])) kfrags = [ KFrag.from_bytes(bytes.fromhex(json_kfrag['kfrag'])) for json_kfrag in vector_suite['vectors'] ] for kfrag in kfrags: assert kfrag.verify(signing_pubkey=verifying_key, delegating_pubkey=delegating_key, receiving_pubkey=receiving_key), \ 'Invalid KFrag {}'.format(kfrag.to_bytes().hex())
def test_grant(alice, bob, nucypher_test_config): policy_end_datetime = maya.now() + datetime.timedelta(days=5) n = 5 uri = b"this_is_the_path_to_which_access_is_being_granted" policy = alice.grant(bob, uri, m=3, n=n, expiration=policy_end_datetime) # The number of policies is equal to the number of Ursulas we're using (n) assert len(policy._accepted_arrangements) == n # Let's look at the first Ursula. ursula = list(policy._accepted_arrangements.values())[0].ursula # Get the Policy from Ursula's datastore, looking up by hrac. proper_hrac = keccak_digest(bytes(alice.stamp) + bytes(bob.stamp) + uri) retrieved_policy = ursula.datastore.get_policy_arrangement( proper_hrac.hex().encode()) # TODO: Make this a legit KFrag, not bytes. retrieved_k_frag = KFrag.from_bytes(retrieved_policy.k_frag) # TODO: Implement KFrag.__eq__ found = False for k_frag in policy.kfrags: if bytes(k_frag) == bytes(retrieved_k_frag): found = True assert found
def test_grant(alice, bob, three_agents): # Monkey patch KFrag repr for better debugging. KFrag.__repr__ = lambda kfrag: "KFrag: {}".format(bytes(kfrag)[:10].hex()) policy_end_datetime = maya.now() + datetime.timedelta(days=5) n = 3 label = b"this_is_the_path_to_which_access_is_being_granted" _token_agent, _miner_agent, policy_agent = three_agents policy_agent.blockchain.wait_for_receipt = MockPolicyCreation.wait_for_receipt policy_agent.contract.functions.createPolicy = MockPolicyCreation policy = alice.grant(bob, label, m=2, n=n, expiration=policy_end_datetime) # The number of accepted arrangements at least the number of Ursulas we're using (n) assert len(policy._accepted_arrangements) >= n # The number of actually enacted arrangements is exactly equal to n. assert len(policy._enacted_arrangements) == n # Let's look at the enacted arrangements. for kfrag in policy.kfrags: arrangement = policy._enacted_arrangements[kfrag] ursula = _TEST_KNOWN_URSULAS_CACHE[ arrangement.ursula.rest_interface.port] # Get the Arrangement from Ursula's datastore, looking up by hrac. # This will be changed in 180, when we use the Arrangement ID. proper_hrac = keccak_digest( bytes(alice.stamp) + bytes(bob.stamp) + label) retrieved_policy = ursula.datastore.get_policy_arrangement( arrangement.id.hex().encode()) retrieved_kfrag = KFrag.from_bytes(retrieved_policy.k_frag) assert kfrag == retrieved_kfrag
def reencrypt_via_rest(self, id_as_hex, request: http.Request): from nucypher.policy.models import WorkOrder # Avoid circular import id = binascii.unhexlify(id_as_hex) work_order = WorkOrder.from_rest_payload(id, request.body) self.log.info("Work Order from {}, signed {}".format( work_order.bob, work_order.receipt_signature)) with ThreadedSession(self.db_engine) as session: kfrag_bytes = self.datastore.get_policy_arrangement( id.hex().encode(), session=session).k_frag # Careful! :-) # TODO: Push this to a lower level. kfrag = KFrag.from_bytes(kfrag_bytes) cfrag_byte_stream = b"" for capsule in work_order.capsules: # TODO: Sign the result of this. See #141. cfrag = pre.reencrypt(kfrag, capsule) self.log.info( "Re-encrypting for Capsule {}, made CFrag {}.".format( capsule, cfrag)) cfrag_byte_stream += VariableLengthBytestring(cfrag) # TODO: Put this in Ursula's datastore self._work_orders.append(work_order) headers = {'Content-Type': 'application/octet-stream'} return Response(content=cfrag_byte_stream, headers=headers)
def test_kfrag_roundtrip(d, b0, p0, p1, sig_proxy, sig_bob): k = KFrag(identifier=d, bn_key=b0, point_commitment=p0, point_precursor=p1, signature_for_proxy=sig_proxy, signature_for_bob=sig_bob) assert_kfrag_eq(k, KFrag.from_bytes(k.to_bytes()))
def set_policy(self, hrac_as_hex, request: http.Request): """ REST endpoint for setting a kFrag. TODO: Instead of taking a Request, use the apistar typing system to type a payload and validate / split it. TODO: Validate that the kfrag being saved is pursuant to an approved Policy (see #121). """ hrac = binascii.unhexlify(hrac_as_hex) policy_message_kit = MessageKit.from_bytes(request.body) # group_payload_splitter = BytestringSplitter(PublicKey) # policy_payload_splitter = BytestringSplitter((KFrag, KFRAG_LENGTH)) alice = self._alice_class.from_public_keys((SigningPower, policy_message_kit.alice_pubkey)) verified, cleartext = self.verify_from( alice, policy_message_kit, decrypt=True, signature_is_on_cleartext=True) if not verified: # TODO: What do we do if the Policy isn't signed properly? pass # # alices_signature, policy_payload =\ # BytestringSplitter(Signature)(cleartext, return_remainder=True) # TODO: If we're not adding anything else in the payload, stop using the # splitter here. # kfrag = policy_payload_splitter(policy_payload)[0] kfrag = KFrag.from_bytes(cleartext) # TODO: Query stored Contract and reconstitute policy_contract = self.keystore.get_policy_contract(hrac_as_hex.encode()) # contract_details = self._contracts[hrac.hex()] if policy_contract.alice_pubkey_sig.key_data != alice.stamp: raise self._alice_class.SuspiciousActivity # contract = Contract(alice=alice, hrac=hrac, # kfrag=kfrag, expiration=policy_contract.expiration) try: # TODO: Obviously we do this lower-level. policy_contract.k_frag = bytes(kfrag) self.keystore.session.commit() except IntegrityError: raise # Do something appropriately RESTful (ie, 4xx). return # TODO: Return A 200, with whatever policy metadata.
def test_cfrags(): vector_file = os.path.join('vectors', 'vectors_cfrags.json') try: with open(vector_file) as f: vector_suite = json.load(f) except OSError: raise params = default_params() capsule = pre.Capsule.from_bytes(bytes.fromhex(vector_suite['capsule']), params=params) verifying_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['verifying_key'])) delegating_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['delegating_key'])) receiving_key = UmbralPublicKey.from_bytes( bytes.fromhex(vector_suite['receiving_key'])) kfrags_n_cfrags = [ (KFrag.from_bytes(bytes.fromhex(json_kfrag['kfrag'])), CapsuleFrag.from_bytes(bytes.fromhex(json_kfrag['cfrag']))) for json_kfrag in vector_suite['vectors'] ] capsule.set_correctness_keys(delegating=delegating_key, receiving=receiving_key, verifying=verifying_key) for kfrag, cfrag in kfrags_n_cfrags: assert kfrag.verify(signing_pubkey=verifying_key, delegating_pubkey=delegating_key, receiving_pubkey=receiving_key), \ 'Invalid KFrag {}'.format(kfrag.to_bytes().hex()) new_cfrag = pre.reencrypt(kfrag, capsule, provide_proof=False) assert new_cfrag._point_e1 == cfrag._point_e1 assert new_cfrag._point_v1 == cfrag._point_v1 assert new_cfrag._kfrag_id == cfrag._kfrag_id assert new_cfrag._point_noninteractive == cfrag._point_noninteractive assert new_cfrag._point_xcoord == cfrag._point_xcoord assert new_cfrag.proof is None assert cfrag.to_bytes() == new_cfrag.to_bytes()
def reencrypt_via_rest(self, hrac_as_hex, request: http.Request): from nkms.policy.models import WorkOrder # Avoid circular import hrac = binascii.unhexlify(hrac_as_hex) work_order = WorkOrder.from_rest_payload(hrac, request.body) kfrag_bytes = self.keystore.get_policy_contract(hrac.hex().encode()).k_frag # Careful! :-) # TODO: Push this to a lower level. kfrag = KFrag.from_bytes(kfrag_bytes) cfrag_byte_stream = b"" for capsule in work_order.capsules: # TODO: Sign the result of this. See #141. cfrag_byte_stream += bytes(pre.reencrypt(kfrag, capsule)) # TODO: Put this in Ursula's datastore self._work_orders.append(work_order) return Response(content=cfrag_byte_stream, content_type="application/octet-stream")
def reencrypt_via_rest(self, hrac_as_hex, request: http.Request): from nkms.policy.models import WorkOrder # Avoid circular import hrac = binascii.unhexlify(hrac_as_hex) work_order = WorkOrder.from_rest_payload(hrac, request.body) with ThreadedSession(self.db_engine) as session: kfrag_bytes = self.datastore.get_policy_arrangement( hrac.hex().encode(), session=session).k_frag # Careful! :-) # TODO: Push this to a lower level. kfrag = KFrag.from_bytes(kfrag_bytes) cfrag_byte_stream = b"" for capsule in work_order.capsules: # TODO: Sign the result of this. See #141. cfrag_byte_stream += bytes(pre.reencrypt(kfrag, capsule)) # TODO: Put this in Ursula's datastore self._work_orders.append(work_order) headers = {'Content-Type': 'application/octet-stream'} return Response(content=cfrag_byte_stream, headers=headers)
def test_kfrag_serialization(alices_keys, bobs_keys, kfrags): delegating_privkey, signing_privkey = alices_keys _receiving_privkey, receiving_pubkey = bobs_keys for kfrag in kfrags: kfrag_bytes = kfrag.to_bytes() assert len(kfrag_bytes) == KFrag.expected_bytes_length() new_kfrag = KFrag.from_bytes(kfrag_bytes) assert new_kfrag._id == kfrag._id assert new_kfrag._bn_key == kfrag._bn_key assert new_kfrag._point_noninteractive == kfrag._point_noninteractive assert new_kfrag._point_commitment == kfrag._point_commitment assert new_kfrag._point_xcoord == kfrag._point_xcoord assert new_kfrag.verify(signing_pubkey=signing_privkey.get_pubkey(), delegating_pubkey=delegating_privkey.get_pubkey(), receiving_pubkey=receiving_pubkey) assert new_kfrag == kfrag
def set_policy(self, hrac_as_hex, request: http.Request): """ REST endpoint for setting a kFrag. TODO: Instead of taking a Request, use the apistar typing system to type a payload and validate / split it. TODO: Validate that the kfrag being saved is pursuant to an approved Policy (see #121). """ hrac = binascii.unhexlify(hrac_as_hex) policy_message_kit = MessageKit.from_bytes(request.body) # group_payload_splitter = BytestringSplitter(PublicKey) # policy_payload_splitter = BytestringSplitter((KFrag, KFRAG_LENGTH)) alice = self._alice_class.from_public_keys( {SigningPower: policy_message_kit.alice_pubkey}) verified, cleartext = self.verify_from(alice, policy_message_kit, decrypt=True, signature_is_on_cleartext=True) if not verified: # TODO: What do we do if the Policy isn't signed properly? pass # # alices_signature, policy_payload =\ # BytestringSplitter(Signature)(cleartext, return_remainder=True) # TODO: If we're not adding anything else in the payload, stop using the # splitter here. # kfrag = policy_payload_splitter(policy_payload)[0] kfrag = KFrag.from_bytes(cleartext) with ThreadedSession(self.db_engine) as session: self.datastore.attach_kfrag_to_saved_contract(alice, hrac_as_hex, kfrag, session=session) return # TODO: Return A 200, with whatever policy metadata.
def reencrypt_via_rest(self, id_as_hex, request: Request): from nucypher.policy.models import WorkOrder # Avoid circular import arrangement_id = binascii.unhexlify(id_as_hex) work_order = WorkOrder.from_rest_payload(arrangement_id, request.body) self.log.info("Work Order from {}, signed {}".format( work_order.bob, work_order.receipt_signature)) with ThreadedSession(self.db_engine) as session: policy_arrangement = self.datastore.get_policy_arrangement( arrangement_id=id_as_hex.encode(), session=session) kfrag_bytes = policy_arrangement.kfrag # Careful! :-) verifying_key_bytes = policy_arrangement.alice_pubkey_sig.key_data # TODO: Push this to a lower level. kfrag = KFrag.from_bytes(kfrag_bytes) alices_verifying_key = UmbralPublicKey.from_bytes(verifying_key_bytes) cfrag_byte_stream = b"" for capsule, capsule_signature in zip(work_order.capsules, work_order.capsule_signatures): # This is the capsule signed by Bob capsule_signature = bytes(capsule_signature) # Ursula signs on top of it. Now both are committed to the same capsule. capsule_signed_by_both = bytes(self._stamp(capsule_signature)) capsule.set_correctness_keys(verifying=alices_verifying_key) cfrag = pre.reencrypt(kfrag, capsule, metadata=capsule_signed_by_both) self.log.info("Re-encrypting for {}, made {}.".format( capsule, cfrag)) signature = self._stamp(bytes(cfrag) + bytes(capsule)) cfrag_byte_stream += VariableLengthBytestring(cfrag) + signature # TODO: Put this in Ursula's datastore self._work_order_tracker.append(work_order) headers = {'Content-Type': 'application/octet-stream'} return Response(content=cfrag_byte_stream, headers=headers)
def test_kfrag_serialization(alices_keys, bobs_keys, kfrags): delegating_privkey, signing_privkey = alices_keys _receiving_privkey, receiving_pubkey = bobs_keys for kfrag in kfrags: kfrag_bytes = kfrag.to_bytes() assert len(kfrag_bytes) == KFrag.expected_bytes_length() new_kfrag = KFrag.from_bytes(kfrag_bytes) assert new_kfrag.id == kfrag.id assert new_kfrag._bn_key == kfrag._bn_key assert new_kfrag._point_precursor == kfrag._point_precursor assert new_kfrag._point_commitment == kfrag._point_commitment assert new_kfrag.keys_in_signature == kfrag.keys_in_signature assert new_kfrag.signature_for_proxy == kfrag.signature_for_proxy assert new_kfrag.signature_for_bob == kfrag.signature_for_bob assert new_kfrag.verify( signing_pubkey=signing_privkey.get_pubkey(), delegating_pubkey=delegating_privkey.get_pubkey(), receiving_pubkey=receiving_pubkey) assert new_kfrag == kfrag
def test_bob_can_issue_a_work_order_to_a_specific_ursula( enacted_policy, alice, bob, ursulas, capsule_side_channel): """ Now that Bob has his list of Ursulas, he can issue a WorkOrder to one. Upon receiving the WorkOrder, Ursula saves it and responds by re-encrypting and giving Bob a cFrag. This is a multipart test; it shows proper relations between the Characters Ursula and Bob and also proper interchange between a KFrag, Capsule, and CFrag object in the context of REST-driven proxy re-encryption. """ # We pick up our story with Bob already having followed the treasure map above, ie: hrac, treasure_map = enacted_policy.hrac(), enacted_policy.treasure_map bob.treasure_maps[hrac] = treasure_map bob.follow_treasure_map(hrac) assert len(bob.known_nodes) == len(ursulas) the_hrac = enacted_policy.hrac() # Bob has no saved work orders yet, ever. assert len(bob._saved_work_orders) == 0 # We'll test against just a single Ursula - here, we make a WorkOrder for just one. # We can pass any number of capsules as args; here we pass just one. work_orders = bob.generate_work_orders(the_hrac, capsule_side_channel[0].capsule, num_ursulas=1) # Again: one Ursula, one work_order. assert len(work_orders) == 1 # Bob saved the WorkOrder. assert len(bob._saved_work_orders) == 1 # And the Ursula. assert len(bob._saved_work_orders.ursulas) == 1 networky_stuff = MockNetworkyStuff(ursulas) ursula_dht_key, work_order = list(work_orders.items())[0] # In the real world, we'll have a full Ursula node here. But in this case, we need to fake it. work_order.ursula = ursulas[0] # **** RE-ENCRYPTION HAPPENS HERE! **** cfrags = bob.get_reencrypted_c_frags(networky_stuff, work_order) # We only gave one Capsule, so we only got one cFrag. assert len(cfrags) == 1 the_cfrag = cfrags[0] # Attach the CFrag to the Capsule. capsule_side_channel[0].capsule.attach_cfrag(the_cfrag) # Having received the cFrag, Bob also saved the WorkOrder as complete. assert len(bob._saved_work_orders) == 1 # OK, so cool - Bob has his cFrag! Let's make sure everything went properly. First, we'll show that it is in fact # the correct cFrag (ie, that Ursula performed reencryption properly). ursula = work_order.ursula kfrag_bytes = ursula.datastore.get_policy_arrangement( work_order.kfrag_hrac.hex().encode()).k_frag the_kfrag = KFrag.from_bytes(kfrag_bytes) the_correct_cfrag = pre.reencrypt(the_kfrag, capsule_side_channel[0].capsule) assert bytes(the_cfrag) == bytes( the_correct_cfrag) # It's the correct cfrag! # Now we'll show that Ursula saved the correct WorkOrder. work_orders_from_bob = ursula.work_orders(bob=bob) assert len(work_orders_from_bob) == 1 assert work_orders_from_bob[0] == work_order
def test_kfrag_roundtrip(d, b0, p0, p1, p2, sig): k = KFrag(d, b0, p0, p1, p2, sig) assert_kfrag_eq(k, KFrag.from_bytes(k.to_bytes()))
def test_recepient_add_records_set(self): #Generate keys config.set_default_curve(SECP256K1) patient_private_key = keys.UmbralPrivateKey.gen_key() patient_public_key = patient_private_key.get_pubkey() recepient_private_key = keys.UmbralPrivateKey.gen_key() recepient_public_key = recepient_private_key.get_pubkey() recepient_signing_key = keys.UmbralPrivateKey.gen_key() recepient_verifying_key = recepient_signing_key.get_pubkey() recepient_signer = signing.Signer(private_key=recepient_signing_key) #Convert keys to hex hexed_patient_public_key = patient_public_key.to_bytes().hex() hexed_recepient_public_key = recepient_public_key.to_bytes().hex() hexed_recepient_verifying_key = recepient_verifying_key.to_bytes().hex() #Signup patient data = { 'first_name': 'Gordo', 'last_name': 'Freema', 'email': '*****@*****.**', 'password': '******', 'eth_address': '0x73015966604928A312F79F7E69291a656Cb88603', 'pub_key': hexed_patient_public_key } response = self.client.post('/patients/signup/', data) #Signup recepient data = { 'organisation_id': 'someseriousorganisationidentifier', 'first_name': 'Gordon', 'last_name': 'Freeman', 'email': '*****@*****.**', 'password': '******', 'eth_address': '0x73015966604928A312F79F7E69291a656Cb88603', 'pub_key': hexed_recepient_public_key } response = self.client.post('/recepients/signup/', data) #Log in as patient self.client.login(username='******', password='******') data = { 'patient_id': 2, 'recepient_id': 2 } #Delegate add records permission to recepient response = self.client.post('/patients/delegations/make/', data) #Log in as recepient self.client.login(username='******', password='******') #Encrypt message plaintext = b'Proxy Re-encryption is cool!' ciphertext, capsule = pre.encrypt(recepient_public_key, plaintext) kfrags = pre.generate_kfrags(delegating_privkey=recepient_private_key, signer=recepient_signer, receiving_pubkey=patient_public_key, threshold=10, N=20) #Add encrypted record data = { 'patient_id': 2, 'type': 'type', 'data': ciphertext.hex(), 'capsule': capsule.to_bytes().hex() } response = self.client.post('/records/add/', data) self.assertEqual(response.status_code, 201) #Add kfrags for kfrag in kfrags: data = { 'delegation_id': 1, 'bytes': kfrag.to_bytes().hex() } self.client.post('/patients/kfrags/', data) #Add verifying_key data = { 'records_set_id': 1, 'recepient_id': 3, 'verifying_key': hexed_recepient_verifying_key } response = self.client.post('/re_encryptions/', data) #Login as patient self.client.login(username='******', password='******') response = self.client.get('/me/records/') from_proxy_capsule = bytes.fromhex(response.data[0]['capsule']) from_proxy_data = bytes.fromhex(response.data[0]['data']) umbral_parameteres = UmbralParameters(SECP256K1) from_proxy_capsule = pre.Capsule.from_bytes( from_proxy_capsule, umbral_parameteres ) response = self.client.get('/patients/kfrags/') """ Patient can receive kfrags for each re_encryption """ from_proxy_kfrags = [KFrag.from_bytes(bytes.fromhex(kfrag['bytes'])) for kfrag in response.data] response = self.client.get('/re_encryptions/1/') from_proxy_verifying_key = bytes.fromhex(response.data['verifying_key']) """ Patient gets verifying_key """ from_proxy_verifying_key = keys.UmbralPublicKey.from_bytes( from_proxy_verifying_key, params=umbral_parameteres ) from_proxy_capsule.set_correctness_keys( delegating=recepient_public_key, receiving=patient_public_key, verifying=from_proxy_verifying_key ) for kfrag in from_proxy_kfrags: cfrag = pre.reencrypt(kfrag, from_proxy_capsule) from_proxy_capsule.attach_cfrag(cfrag) cleartext = pre.decrypt( ciphertext=from_proxy_data, capsule=from_proxy_capsule, decrypting_key=patient_private_key ) """ Patient opens the capsule to decrypt records organisation added. Then patient can reencrypt whole records to delegate editing and reading permissions to other organisations """ self.assertEqual(cleartext, plaintext)
def test_bob_can_issue_a_work_order_to_a_specific_ursula( enacted_federated_policy, federated_bob, federated_alice, federated_ursulas, capsule_side_channel): """ Now that Bob has his list of Ursulas, he can issue a WorkOrder to one. Upon receiving the WorkOrder, Ursula saves it and responds by re-encrypting and giving Bob a cFrag. This is a multipart test; it shows proper relations between the Characters Ursula and Bob and also proper interchange between a KFrag, Capsule, and CFrag object in the cont ext of REST-driven proxy re-encryption. """ # We pick up our story with Bob already having followed the treasure map above, ie: hrac, treasure_map = enacted_federated_policy.hrac( ), enacted_federated_policy.treasure_map map_id = treasure_map.public_id() federated_bob.treasure_maps[map_id] = treasure_map d = federated_bob.start_learning_loop() federated_bob.follow_treasure_map(map_id=map_id, block=True, timeout=1) assert len(federated_bob.known_nodes) == len(federated_ursulas) the_hrac = enacted_federated_policy.hrac() # Bob has no saved work orders yet, ever. assert len(federated_bob._saved_work_orders) == 0 # We'll test against just a single Ursula - here, we make a WorkOrder for just one. # We can pass any number of capsules as args; here we pass just one. work_orders = federated_bob.generate_work_orders( map_id, capsule_side_channel[0].capsule, num_ursulas=1) # Again: one Ursula, one work_order. assert len(work_orders) == 1 # Bob saved the WorkOrder. assert len(federated_bob._saved_work_orders) == 1 # And the Ursula. assert len(federated_bob._saved_work_orders.ursulas) == 1 ursula_id, work_order = list(work_orders.items())[0] # **** RE-ENCRYPTION HAPPENS HERE! **** cfrags = federated_bob.get_reencrypted_cfrags(work_order) # We only gave one Capsule, so we only got one cFrag. assert len(cfrags) == 1 the_cfrag = cfrags[0] # Attach the CFrag to the Capsule. capsule = capsule_side_channel[0].capsule capsule.set_correctness_keys( delegating=enacted_federated_policy.public_key, receiving=federated_bob.public_keys(EncryptingPower), verifying=federated_alice.stamp.as_umbral_pubkey()) capsule.attach_cfrag(the_cfrag) # Having received the cFrag, Bob also saved the WorkOrder as complete. assert len(federated_bob._saved_work_orders.by_ursula[ursula_id]) == 1 # OK, so cool - Bob has his cFrag! Let's make sure everything went properly. First, we'll show that it is in fact # the correct cFrag (ie, that Ursula performed reencryption properly). for u in federated_ursulas: if u.rest_information()[0].port == work_order.ursula.rest_information( )[0].port: ursula = u break else: raise RuntimeError( "We've lost track of the Ursula that has the WorkOrder. Can't really proceed." ) kfrag_bytes = ursula.datastore.get_policy_arrangement( work_order.arrangement_id.hex().encode()).k_frag the_kfrag = KFrag.from_bytes(kfrag_bytes) the_correct_cfrag = pre.reencrypt(the_kfrag, capsule) # The first CFRAG_LENGTH_WITHOUT_PROOF bytes (ie, the cfrag proper, not the proof material), are the same: assert bytes(the_cfrag)[:CapsuleFrag.expected_bytes_length()] == bytes( the_correct_cfrag)[:CapsuleFrag.expected_bytes_length( )] # It's the correct cfrag! assert the_correct_cfrag.verify_correctness(capsule) # Now we'll show that Ursula saved the correct WorkOrder. work_orders_from_bob = ursula.work_orders(bob=federated_bob) assert len(work_orders_from_bob) == 1 assert work_orders_from_bob[0] == work_order
def test_lifecycle_with_serialization(N, M, signing_mode, curve=default_curve()): """ This test is a variant of test_simple_api, but with intermediate serialization/deserialization steps, modeling how pyUmbral artifacts (such as keys, ciphertexts, etc) will actually be used. These intermediate steps are in between the different 'usage domains' in NuCypher, namely, key generation, delegation, encryption, decryption by Alice, re-encryption by Ursula, and decryption by Bob. Manually injects UmbralParameters for multi-curve testing. """ # Convenience method to avoid replicating key generation code def new_keypair_bytes(): privkey = UmbralPrivateKey.gen_key(params=params) return privkey.to_bytes(), privkey.get_pubkey().to_bytes() ## SETUP params = UmbralParameters(curve=curve) delegating_privkey_bytes, delegating_pubkey_bytes = new_keypair_bytes() signing_privkey_bytes, signing_pubkey_bytes = new_keypair_bytes() receiving_privkey_bytes, receiving_pubkey_bytes = new_keypair_bytes() ## DELEGATION DOMAIN: ## Alice delegates decryption rights to some Bob by generating a set of ## KFrags, using her delegating private key and Bob's receiving public key delegating_privkey = UmbralPrivateKey.from_bytes(delegating_privkey_bytes, params) signing_privkey = UmbralPrivateKey.from_bytes(signing_privkey_bytes, params) receiving_pubkey = UmbralPublicKey.from_bytes(receiving_pubkey_bytes, params) signer = Signer(signing_privkey) sign_delegating_key, sign_receiving_key = signing_mode kfrags = pre.generate_kfrags(delegating_privkey=delegating_privkey, receiving_pubkey=receiving_pubkey, threshold=M, N=N, signer=signer, sign_delegating_key=sign_delegating_key, sign_receiving_key=sign_receiving_key) kfrags_bytes = tuple(map(bytes, kfrags)) del kfrags del signer del delegating_privkey del signing_privkey del receiving_pubkey del params ## ENCRYPTION DOMAIN ## params = UmbralParameters(curve=curve) delegating_pubkey = UmbralPublicKey.from_bytes(delegating_pubkey_bytes, params) plain_data = b'peace at dawn' ciphertext, capsule = pre.encrypt(delegating_pubkey, plain_data) capsule_bytes = bytes(capsule) del capsule del delegating_pubkey del params ## DECRYPTION BY ALICE ## params = UmbralParameters(curve=curve) delegating_privkey = UmbralPrivateKey.from_bytes(delegating_privkey_bytes, params) capsule = pre.Capsule.from_bytes(capsule_bytes, params) cleartext = pre.decrypt(ciphertext, capsule, delegating_privkey) assert cleartext == plain_data del delegating_privkey del capsule del params ## RE-ENCRYPTION DOMAIN (i.e., Ursula's side) cfrags_bytes = list() for kfrag_bytes in kfrags_bytes: params = UmbralParameters(curve=curve) delegating_pubkey = UmbralPublicKey.from_bytes(delegating_pubkey_bytes, params) signing_pubkey = UmbralPublicKey.from_bytes(signing_pubkey_bytes, params) receiving_pubkey = UmbralPublicKey.from_bytes(receiving_pubkey_bytes, params) capsule = pre.Capsule.from_bytes(capsule_bytes, params) capsule.set_correctness_keys(delegating=delegating_pubkey, receiving=receiving_pubkey, verifying=signing_pubkey) # TODO: use params instead of curve? kfrag = KFrag.from_bytes(kfrag_bytes, params.curve) assert kfrag.verify(signing_pubkey, delegating_pubkey, receiving_pubkey, params) cfrag_bytes = bytes(pre.reencrypt(kfrag, capsule)) cfrags_bytes.append(cfrag_bytes) del capsule del kfrag del params del delegating_pubkey del signing_pubkey del receiving_pubkey ## DECRYPTION DOMAIN (i.e., Bob's side) params = UmbralParameters(curve=curve) capsule = pre.Capsule.from_bytes(capsule_bytes, params) delegating_pubkey = UmbralPublicKey.from_bytes(delegating_pubkey_bytes, params) signing_pubkey = UmbralPublicKey.from_bytes(signing_pubkey_bytes, params) receiving_privkey = UmbralPrivateKey.from_bytes(receiving_privkey_bytes, params) receiving_pubkey = receiving_privkey.get_pubkey() capsule.set_correctness_keys(delegating=delegating_pubkey, receiving=receiving_pubkey, verifying=signing_pubkey) for cfrag_bytes in cfrags_bytes: # TODO: use params instead of curve? cfrag = CapsuleFrag.from_bytes(cfrag_bytes, params.curve) capsule.attach_cfrag(cfrag) reenc_cleartext = pre.decrypt(ciphertext, capsule, receiving_privkey) assert reenc_cleartext == plain_data
def test_bob_can_issue_a_work_order_to_a_specific_ursula( enacted_policy, bob, alice, ursulas, capsule_side_channel): """ Now that Bob has his list of Ursulas, he can issue a WorkOrder to one. Upon receiving the WorkOrder, Ursula saves it and responds by re-encrypting and giving Bob a cFrag. This is a multipart test; it shows proper relations between the Characters Ursula and Bob and also proper interchange between a KFrag, Capsule, and CFrag object in the context of REST-driven proxy re-encryption. """ # We pick up our story with Bob already having followed the treasure map above, ie: hrac, treasure_map = enacted_policy.hrac(), enacted_policy.treasure_map bob.treasure_maps[hrac] = treasure_map bob.follow_treasure_map(hrac) assert len(bob.known_nodes) == len(ursulas) the_hrac = enacted_policy.hrac() # Bob has no saved work orders yet, ever. assert len(bob._saved_work_orders) == 0 # We'll test against just a single Ursula - here, we make a WorkOrder for just one. # We can pass any number of capsules as args; here we pass just one. work_orders = bob.generate_work_orders(the_hrac, capsule_side_channel[0].capsule, num_ursulas=1) # Again: one Ursula, one work_order. assert len(work_orders) == 1 # Bob saved the WorkOrder. assert len(bob._saved_work_orders) == 1 # And the Ursula. assert len(bob._saved_work_orders.ursulas) == 1 ursula_dht_key, work_order = list(work_orders.items())[0] # **** RE-ENCRYPTION HAPPENS HERE! **** cfrags = bob.get_reencrypted_c_frags(work_order) # We only gave one Capsule, so we only got one cFrag. assert len(cfrags) == 1 the_cfrag = cfrags[0] # Attach the CFrag to the Capsule. capsule = capsule_side_channel[0].capsule capsule.attach_cfrag(the_cfrag) # Having received the cFrag, Bob also saved the WorkOrder as complete. assert len(bob._saved_work_orders) == 1 # OK, so cool - Bob has his cFrag! Let's make sure everything went properly. First, we'll show that it is in fact # the correct cFrag (ie, that Ursula performed reencryption properly). for u in ursulas: # ...and to do that, we need to address the right ursula. if u.rest_port == work_order.ursula.rest_port: ursula = u break else: raise RuntimeError( "Somehow we don't know about this Ursula. Major malfunction.") kfrag_bytes = ursula.datastore.get_policy_arrangement( work_order.kfrag_hrac.hex().encode()).k_frag the_kfrag = KFrag.from_bytes(kfrag_bytes) the_correct_cfrag = pre.reencrypt(the_kfrag, capsule) # The first CFRAG_LENGTH_WITHOUT_PROOF bytes (ie, the cfrag proper, not the proof material), are the same: assert bytes(the_cfrag)[:CFRAG_LENGTH_WITHOUT_PROOF] == bytes( the_correct_cfrag )[:CFRAG_LENGTH_WITHOUT_PROOF] # It's the correct cfrag! assert the_correct_cfrag.verify_correctness( capsule, pubkey_a=enacted_policy.public_key, pubkey_b=bob.public_key(EncryptingPower)) # Now we'll show that Ursula saved the correct WorkOrder. work_orders_from_bob = ursula.work_orders(bob=bob) assert len(work_orders_from_bob) == 1 assert work_orders_from_bob[0] == work_order