def create_session_with_n_members_batched(num_members: int) -> List[Session]:
    other_keystores = [LocalKeyStoreMock(f'{0}')]
    other_keystores[-1].register_keypair(str(0).encode('ascii'), str(0).encode('ascii'))
    other_sessions = [Session.from_empty(other_keystores[0], '0', 'teeest')]

    messages_per_session: Dict[int, List[Union[AddMessage, WelcomeInfoMessage]]] = {0: []}

    for i in range(1, num_members, 1):
        other_keystores.append(LocalKeyStoreMock(f'{i}'))
        other_keystores[-1].register_keypair(str(i).encode('ascii'), str(i).encode('ascii'))

        welcome, add = other_sessions[0].add_member(f'{i}', str(i).encode('ascii'))
        messages_per_session[i] = [welcome]

        for key in messages_per_session.keys():
            messages_per_session[key].append(add)

    for index, messages in messages_per_session.items():

        if index != 0:
            session = Session.from_welcome(messages[0], other_keystores[index], f'{index}')
            messages = messages[1:]
            other_sessions.append(session)

        for message in messages:
            other_sessions[index].process_add(message)

    return other_sessions
def test_update_message():
    # init user keys
    alice_store = LocalKeyStoreMock('alice')
    alice_store.register_keypair(b'0', b'0')

    bob_store = LocalKeyStoreMock('bob')
    bob_store.register_keypair(b'1', b'1')

    # setup session
    alice_session = Session.from_empty(alice_store, 'alice', 'test')
    welcome, add = alice_session.add_member('bob', b'1')
    bob_session = Session.from_welcome(welcome, bob_store, 'bob')

    alice_session.process_add(add_message=add)
    bob_session.process_add(add_message=add)

    update: UpdateMessage = alice_session.update()

    # assert that this update contains two nodes: The leaf and the root node
    assert len(update.direct_path) == 2

    # assert that the leaf node (node[0]) does not contain an encrypted path secret
    assert update.direct_path[0].encrypted_path_secret == [], "leaf node must not contain an encrypted path secret"
    # assert that the root node (node[1] contains one encrypted path secret for bob
    assert len(update.direct_path[1].encrypted_path_secret) == 1

    bob_session.process_update(0, update)

    alice_tree = alice_session.get_state().get_tree()
    bob_tree = bob_session.get_state().get_tree()

    # assert that the public keys of the nodes are equal
    assert alice_tree == bob_tree

    # assert that the new, shared secret has been distributed
    assert alice_tree.get_node(1).get_private_key() == bob_tree.get_node(1).get_private_key()
    assert alice_tree.get_node(1).get_public_key() == bob_tree.get_node(1).get_public_key()

    # but make sure that bob does not know alice's private key
    assert bob_tree.get_node(0).get_private_key() is None
    assert alice_tree.get_node(0).get_public_key() == bob_tree.get_node(0).get_public_key()

    # compare tree hashses
    assert alice_tree.get_tree_hash() == bob_tree.get_tree_hash()

    # compare key schedule secrets
    assert alice_session.get_state().get_key_schedule().get_epoch_secret() == \
           bob_session.get_state().get_key_schedule().get_epoch_secret()

    assert alice_session.get_state().get_group_context() == \
           bob_session.get_state().get_group_context()
def test_session_can_be_created_from_welcome():
    """
    test todo:
    If "index < n" and the leaf node at position "index" is
       not blank, then the recipient MUST reject the Add as malformed.
    """

    # init user keys
    alice_store = LocalKeyStoreMock('alice')
    alice_store.register_keypair(b'0', b'0')

    bob_store = LocalKeyStoreMock('bob')
    bob_store.register_keypair(b'1', b'1')

    # setup session
    alice_session = Session.from_empty(alice_store, 'alice', 'test')
    welcome, add = alice_session.add_member('bob', b'1')
    bob_session = Session.from_welcome(welcome, bob_store, 'bob')

    # assert add message correctly created
    assert add.index == 1 and add.init_key == b'1'
    # assert bob did not get alice's private key
    for node in welcome.tree:
        assert node.get_private_key() is None

    alice_state = alice_session.get_state()
    bob_state = bob_session.get_state()

    # assert that alice session only contains herself before processing the add
    assert alice_state.get_tree().get_num_nodes() == 1 and alice_state.get_tree().get_num_leaves() == 1
    # assert that bob received the pre-add session tree
    assert alice_state.get_tree() == bob_state.get_tree()

    # assert both group context are equal
    assert alice_state.get_group_context() == bob_state.get_group_context()

    # process adds
    alice_session.process_add(add_message=add)
    bob_session.process_add(add_message=add)

    # assert that both sessions have the same state after adds
    assert alice_state.get_tree().get_num_nodes() == 3 and alice_state.get_tree().get_num_leaves() == 2
    assert bob_state.get_tree().get_num_nodes() == 3 and bob_state.get_tree().get_num_leaves() == 2
    assert alice_state.get_tree() == bob_state.get_tree()

    # compare key schedule secrets
    assert alice_session.get_state().get_key_schedule().get_epoch_secret() == \
           bob_session.get_state().get_key_schedule().get_epoch_secret()
def create_session_with_n_members(num_members: int) -> List[Session]:
    other_keystores = [LocalKeyStoreMock(f'{0}')]
    other_keystores[-1].register_keypair(str(0).encode('ascii'), str(0).encode('ascii'))
    other_sessions = [Session.from_empty(other_keystores[0], '0', 'teeest')]

    for i in range(1, num_members, 1):
        other_keystores.append(LocalKeyStoreMock(f'{i}'))
        other_keystores[-1].register_keypair(str(i).encode('ascii'), str(i).encode('ascii'))

        welcome, add = other_sessions[0].add_member(f'{i}', str(i).encode('ascii'))

        other_sessions.append(Session.from_welcome(welcome, other_keystores[-1], f'{i}'))
        for session in other_sessions:
            session.process_add(add_message=add)

    return other_sessions
Esempio n. 5
0
    def get_messages(self, user: str, device: str):
        """
        Requests messages from dirserver using own identity
        :return:
        """
        try:
            params = {"user": user, "device": device}
            response = requests.get("http://" + self.dir_server + "/message",
                                    params=params)

            # print(response.content)

            if response.status_code != 200:
                raise RuntimeError(
                    f'GetMessage status code {response.status_code}')

            messages: Dict = json.loads(response.content)
            print(f"Got {len(messages)} messages!")

            for message in messages:
                print(message)
                message_wrapper = message['message']
                is_welcome: bool = message_wrapper['is_welcome']
                message_content: bytes = bytes.fromhex(
                    message_wrapper['message'])

                if is_welcome:
                    session: Session = Session.from_welcome(
                        WelcomeInfoMessage.from_bytes(message_content),
                        self.keystore, self.user)
                    chat_name = session.get_state().get_group_context(
                    ).group_id.decode('ASCII')
                    self.chats[chat_name] = Chat.from_welcome([], chat_name,
                                                              session)
                    print("Got added to group " + chat_name)
                    continue

                name = Session.get_groupid_from_cipher(
                    data=message_content).decode('UTF-8')
                self.chats[name].session.process_message(
                    message=MLSCiphertext.from_bytes(message_content),
                    handler=self)
            return len(messages)
        except requests.exceptions.ConnectionError:
            raise ConnectionError
def test_handshake_processing():
    alice_store = LocalKeyStoreMock('alice')
    alice_store.register_keypair(b'0', b'0')

    bob_store = LocalKeyStoreMock('bob')
    bob_store.register_keypair(b'1', b'1')

    # setup session
    alice_session = Session.from_empty(alice_store, 'alice', 'test')
    welcome, add = alice_session.add_member('bob', b'1')

    welcome = WelcomeInfoMessage.from_bytes(welcome.pack())

    encrypted_add = alice_session.encrypt_handshake_message(GroupOperation.from_instance(add))

    bob_session = Session.from_welcome(welcome, bob_store, 'bob')
    bob_session.process_message(encrypted_add, StubHandler())
    alice_session.process_message(encrypted_add, StubHandler())

    # assert that both sessions have the same state after adds
    assert alice_session.get_state().get_tree().get_num_nodes() == 3
    assert bob_session.get_state().get_tree().get_num_nodes() == 3
def test_double_update():
    alice_store = LocalKeyStoreMock('alice')
    alice_store.register_keypair(b'0', b'0')

    bob_store = LocalKeyStoreMock('bob')
    bob_store.register_keypair(b'1', b'1')

    # setup session
    alice_session = Session.from_empty(alice_store, 'alice', 'test')
    welcome, add = alice_session.add_member('bob', b'1')
    bob_session = Session.from_welcome(welcome, bob_store, 'bob')

    alice_session.process_add(add_message=add)
    bob_session.process_add(add_message=add)

    update_op1 = GroupOperation(msg_type=GroupOperationType.UPDATE, operation=alice_session.update())
    cipher1 = alice_session.encrypt_handshake_message(update_op1)

    my_handler = StubHandler()
    alice_session.process_message(cipher1, my_handler)
    bob_session.process_message(cipher1, my_handler)

    update_op2 = GroupOperation(msg_type=GroupOperationType.UPDATE, operation=alice_session.update())
    cipher2 = alice_session.encrypt_handshake_message(update_op2)

    alice_session.process_message(cipher2, my_handler)
    bob_session.process_message(cipher2, my_handler)

    # compare tree hashses
    assert alice_session.get_state().get_tree().get_tree_hash() == bob_session.get_state().get_tree().get_tree_hash()

    # compare key schedule secrets
    assert alice_session.get_state().get_key_schedule().get_epoch_secret() == \
           bob_session.get_state().get_key_schedule().get_epoch_secret()

    assert alice_session.get_state().get_group_context() == \
           bob_session.get_state().get_group_context()
def test_update_message_with_one_member():
    alice_store = LocalKeyStoreMock('alice')
    alice_store.register_keypair(b'0', b'0')

    alice_session = Session.from_empty(alice_store, 'alice', 'test')

    first_hash = alice_session.get_state().get_tree().get_tree_hash()
    update_op = GroupOperation(msg_type=GroupOperationType.UPDATE, operation=alice_session.update())
    second_hash = alice_session.get_state().get_tree().get_tree_hash()

    assert second_hash != first_hash
    cipher = alice_session.encrypt_handshake_message(update_op)

    my_handler = StubHandler()
    alice_session.process_message(cipher, my_handler)
    third_hash = alice_session.get_state().get_tree().get_tree_hash()

    assert third_hash == second_hash
Esempio n. 9
0
    def on_group_welcome(self, session: Session):

        groupname = session.get_state().get_group_context().group_id.decode(
            'ASCII')
        chat = Chat.from_welcome(
            chat_users=[],
            groupname=groupname,
            session=session,
        )

        self.chats[groupname] = chat

        message = Message(description="Welcome Message:",
                          message=groupname,
                          protocol=True)
        message.state_path = self.dump_state_image(groupname)

        self.chats[groupname].messages.append(message)
Esempio n. 10
0
def test_add_after_update_with_many_members():
    for i in range(1, 10, 1):
        other_sessions = create_session_with_n_members(i)

        update_msg = other_sessions[0].update()
        for session in other_sessions[1:]:
            session.process_update(0, update_msg)

        alice_store = LocalKeyStoreMock('alice')

        alice_store.register_keypair(b'alice', b'alice')
        welcome, add = other_sessions[len(other_sessions) - 1].add_member('alice', b'1')
        alice_session = Session.from_welcome(welcome, alice_store, 'alice')
        alice_session.process_add(add)

        for session in other_sessions:
            session.process_add(add)

        for session in other_sessions:
            assert other_sessions[0].get_state().get_tree() == session.get_state().get_tree()
            assert other_sessions[0].get_state().get_group_context() == session.get_state().get_group_context()

        assert alice_session.get_state().get_tree() == other_sessions[0].get_state().get_tree()