def test_enrico_web_character_control_encrypt_message(
        enrico_web_controller_test_client, encrypt_control_request):
    method_name, params = encrypt_control_request
    endpoint = f'/{method_name}'
    response = enrico_web_controller_test_client.post(endpoint,
                                                      data=json.dumps(params))
    assert response.status_code == 200

    response_data = json.loads(response.data)
    assert 'message_kit' in response_data['result']

    # Check that it serializes correctly.
    MessageKit.from_bytes(b64decode(response_data['result']['message_kit']))

    # Send bad data to assert error return
    response = enrico_web_controller_test_client.post('/encrypt_message',
                                                      data=json.dumps(
                                                          {'bad': 'input'}))
    assert response.status_code == 400

    bad_params = dict(params)
    del (bad_params['message'])
    response = enrico_web_controller_test_client.post('/encrypt_message',
                                                      data=bad_params)
    assert response.status_code == 400
Example #2
0
 def _deserialize(self, value, attr, data, **kwargs):
     try:
         message_kit_bytes = super()._deserialize(value, attr, data,
                                                  **kwargs)
         return MessageKitClass.from_bytes(message_kit_bytes)
     except Exception as e:
         raise InvalidInputData(
             f"Could not parse {self.name} as MessageKit: {e}")
Example #3
0
    def decrypt_message_kit(self, message_kit: MessageKit) -> bytes:
        """
        Decrypt data encrypted with Umbral.

        :return: bytes
        """
        try:
            return message_kit.decrypt(self._privkey)
        except ValueError as e:
            raise self.DecryptionFailed() from e
Example #4
0
def test_retrieval_kit_field(get_random_checksum_address):
    field = RetrievalKit()

    def run_tests_on_kit(kit: RetrievalKitClass):
        serialized = field._serialize(value=kit, attr=None, obj=None)
        assert serialized == b64encode(bytes(kit)).decode()

        deserialized = field._deserialize(value=serialized,
                                          attr=None,
                                          data=None)
        assert isinstance(deserialized, RetrievalKitClass)
        assert deserialized.capsule == kit.capsule
        assert deserialized.queried_addresses == kit.queried_addresses

    # kit with list of ursulas
    encrypting_key = SecretKey.random().public_key()
    capsule = MessageKit(encrypting_key,
                         b'testing retrieval kit with 2 ursulas').capsule
    ursulas = [get_random_checksum_address(), get_random_checksum_address()]
    run_tests_on_kit(kit=RetrievalKitClass(
        capsule, {to_canonical_address(ursula)
                  for ursula in ursulas}))

    # kit with no ursulas
    encrypting_key = SecretKey.random().public_key()
    capsule = MessageKit(encrypting_key,
                         b'testing retrieval kit with no ursulas').capsule
    run_tests_on_kit(kit=RetrievalKitClass(capsule, set()))

    with pytest.raises(InvalidInputData):
        field._deserialize(value=b"non_base_64_data", attr=None, data=None)

    with pytest.raises(InvalidInputData):
        field._deserialize(
            value=b64encode(b"invalid_retrieval_kit_bytes").decode(),
            attr=None,
            data=None)
Example #5
0
def fragments():
    delegating_privkey = SecretKey.random()
    delegating_pubkey = delegating_privkey.public_key()
    signing_privkey = SecretKey.random()
    signer = Signer(signing_privkey)
    priv_key_bob = SecretKey.random()
    pub_key_bob = priv_key_bob.public_key()
    kfrags = generate_kfrags(delegating_sk=delegating_privkey,
                             signer=signer,
                             receiving_pk=pub_key_bob,
                             threshold=2,
                             shares=4,
                             sign_delegating_key=False,
                             sign_receiving_key=False)

    capsule = MessageKit(delegating_pubkey, b'unused').capsule
    cfrag = reencrypt(capsule, kfrags[0])
    return capsule, cfrag
Example #6
0
def test_message_kit(enacted_federated_policy, federated_alice):
    # Setup
    enrico = Enrico.from_alice(federated_alice, label=enacted_federated_policy.label)
    message = 'this is a message'
    plaintext_bytes = bytes(message, encoding='utf-8')
    message_kit = enrico.encrypt_message(plaintext=plaintext_bytes)
    message_kit_bytes = bytes(message_kit)
    message_kit = MessageKitClass.from_bytes(message_kit_bytes)

    # Test
    field = MessageKit()
    serialized = field._serialize(value=message_kit, attr=None, obj=None)
    assert serialized == b64encode(bytes(message_kit)).decode()

    deserialized = field._deserialize(value=serialized, attr=None, data=None)
    deserialized_plaintext = federated_alice.decrypt_message_kit(enacted_federated_policy.label, deserialized)[0]
    assert deserialized_plaintext == plaintext_bytes

    with pytest.raises(InvalidInputData):
        field._deserialize(value=b"MessageKit", attr=None, data=None)
Example #7
0
def test_message_kit_serialization_via_enrico(federated_alice):

    mock_label = b'this is a label'

    # Enrico
    enrico = Enrico.from_alice(federated_alice, label=mock_label)

    # Plaintext
    message = 'this is a message'
    plaintext_bytes = bytes(message, encoding='utf-8')

    # Create
    message_kit = enrico.encrypt_message(plaintext=plaintext_bytes)

    # Serialize
    message_kit_bytes = bytes(message_kit)

    # Deserialize
    the_same_message_kit = MessageKit.from_bytes(message_kit_bytes)

    # Confirm
    assert message_kit_bytes == bytes(the_same_message_kit)
Example #8
0
    def encrypt_for(
        self,
        recipient: 'Character',
        plaintext: bytes,
    ) -> MessageKit:
        """
        Encrypts plaintext for recipient actor. Optionally signs the message as well.

        :param recipient: The character whose public key will be used to encrypt
            cleartext.
        :param plaintext: The secret to be encrypted.
        :param sign_plaintext: the cleartext is signed if this is
            True,  Otherwise, the resulting ciphertext is signed.

        :return: the message kit.
        """

        # TODO: who even uses this method except for tests?

        message_kit = MessageKit(
            policy_encrypting_key=recipient.public_keys(DecryptingPower),
            plaintext=plaintext)
        return message_kit
Example #9
0
    policy_data = json.load(f)

policy_pubkey = PublicKey.from_bytes(
    bytes.fromhex(policy_data["policy_pubkey"]))
alices_sig_pubkey = PublicKey.from_bytes(
    bytes.fromhex(policy_data["alice_sig_pubkey"]))
label = policy_data["label"].encode()
treasure_map = EncryptedTreasureMap.from_bytes(
    base64.b64decode(policy_data["treasure_map"].encode()))

# The Doctor can retrieve encrypted data which he can decrypt with his private key.
# But first we need some encrypted data!
# Let's read the file produced by the heart monitor and unpack the MessageKits,
# which are the individual ciphertexts.
data = msgpack.load(open("heart_data.msgpack", "rb"), raw=False)
message_kits = (MessageKit.from_bytes(k) for k in data['kits'])

# Now he can ask the NuCypher network to get a re-encrypted version of each MessageKit.
for message_kit in message_kits:
    start = timer()
    retrieved_plaintexts = doctor.retrieve_and_decrypt(
        [message_kit],
        alice_verifying_key=alices_sig_pubkey,
        encrypted_treasure_map=treasure_map)
    end = timer()

    plaintext = msgpack.loads(retrieved_plaintexts[0], raw=False)

    # Now we can get the heart rate and the associated timestamp,
    # generated by the heart rate monitor.
    heart_rate = plaintext['heart_rate']
def test_web_character_control_lifecycle(alice_web_controller_test_client,
                                         bob_web_controller_test_client,
                                         enrico_web_controller_from_alice,
                                         blockchain_alice, blockchain_bob,
                                         blockchain_ursulas,
                                         random_policy_label):
    random_label = random_policy_label.decode()  # Unicode string

    bob_keys_response = bob_web_controller_test_client.get('/public_keys')
    assert bob_keys_response.status_code == 200

    response_data = json.loads(bob_keys_response.data)
    assert str(nucypher.__version__) == response_data['version']
    bob_keys = response_data['result']
    assert 'bob_encrypting_key' in bob_keys
    assert 'bob_verifying_key' in bob_keys

    bob_encrypting_key_hex = bob_keys['bob_encrypting_key']
    bob_verifying_key_hex = bob_keys['bob_verifying_key']

    # Create a policy via Alice control
    alice_request_data = {
        'bob_encrypting_key': bob_encrypting_key_hex,
        'bob_verifying_key': bob_verifying_key_hex,
        'threshold': 1,
        'shares': 1,
        'label': random_label,
        'expiration': (maya.now() + datetime.timedelta(days=35)).iso8601(),
        'value': 3 * 10**10
    }

    response = alice_web_controller_test_client.put(
        '/grant', data=json.dumps(alice_request_data))
    assert response.status_code == 200

    # Check Response Keys
    alice_response_data = json.loads(response.data)
    assert 'treasure_map' in alice_response_data['result']
    assert 'policy_encrypting_key' in alice_response_data['result']
    assert 'alice_verifying_key' in alice_response_data['result']
    assert 'version' in alice_response_data
    assert str(nucypher.__version__) == alice_response_data['version']

    # This is sidechannel policy metadata. It should be given to Bob by the
    # application developer at some point.
    alice_verifying_key_hex = alice_response_data['result'][
        'alice_verifying_key']

    # Encrypt some data via Enrico control
    # Alice will also be Enrico via Enrico.from_alice
    # (see enrico_control_from_alice fixture)

    plaintext = "I'm bereaved, not a sap!"  # type: str
    enrico_request_data = {
        'message': b64encode(bytes(plaintext, encoding='utf-8')).decode(),
    }

    response = enrico_web_controller_from_alice.post(
        '/encrypt_message', data=json.dumps(enrico_request_data))
    assert response.status_code == 200

    enrico_response_data = json.loads(response.data)
    assert 'message_kit' in enrico_response_data['result']

    kit_bytes = b64decode(
        enrico_response_data['result']['message_kit'].encode())
    bob_message_kit = MessageKit.from_bytes(kit_bytes)

    # Retrieve data via Bob control
    encoded_message_kit = b64encode(bytes(bob_message_kit)).decode()

    bob_request_data = {
        'alice_verifying_key': alice_verifying_key_hex,
        'message_kits': [encoded_message_kit],
        'encrypted_treasure_map': alice_response_data['result']['treasure_map']
    }

    # Give bob a node to remember
    teacher = list(blockchain_ursulas)[1]
    blockchain_bob.remember_node(teacher)

    response = bob_web_controller_test_client.post(
        '/retrieve_and_decrypt', data=json.dumps(bob_request_data))
    assert response.status_code == 200

    bob_response_data = json.loads(response.data)
    assert 'cleartexts' in bob_response_data['result']

    for cleartext in bob_response_data['result']['cleartexts']:
        assert b64decode(cleartext.encode()).decode() == plaintext