示例#1
0
def test_example_doc():
    # Each client must generate a long-term identity key pair.
    # This should be stored somewhere safe and persistent.
    identity_key_pair = identity_key.IdentityKeyPair.generate()

    # Clients must generate prekeys. The example here is generating a
    # single prekey, but clients will generate many as they are one-time use
    # and consumed when a message from a new chat participant is sent. See issue #7.
    pre_key_pair = curve.KeyPair.generate()

    # Clients must generate a registration_id and store it somewhere safe and persistent.
    registration_id = 12  # TODO generate (not yet supported in upstream crate)

    # The InMemSignalProtocolStore is a single object which provide the four storage
    # interfaces required: IdentityKeyStore (for one's own identity key state and the (public)
    # identity keys for other chat participants), PreKeyStore (for one's own prekey state),
    # SignedPreKeyStore (for one's own signed prekeys), and SessionStore (for established sessions
    # with chat participants).
    store = storage.InMemSignalProtocolStore(identity_key_pair,
                                             registration_id)

    # Clients should also generate a signed prekey.
    signed_pre_key_pair = curve.KeyPair.generate()
    serialized_signed_pre_pub_key = signed_pre_key_pair.public_key().serialize(
    )
    signed_pre_key_signature = (store.get_identity_key_pair().private_key(
    ).calculate_signature(serialized_signed_pre_pub_key))

    # Clients should store their prekeys (both one-time and signed) in the protocol store along
    # with IDs that can be used to retrieve them later.
    pre_key_id = 10
    pre_key_record = state.PreKeyRecord(pre_key_id, pre_key_pair)
    store.save_pre_key(pre_key_id, pre_key_record)

    signed_pre_key_id = 33
    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,  # This is a timestamp since the signed prekeys should be periodically rotated
        signed_pre_key_pair,
        signed_pre_key_signature,
    )
    store.save_signed_pre_key(signed_pre_key_id, signed_prekey)
示例#2
0
def create_pre_key_bundle(store):
    pre_key_pair = curve.KeyPair.generate()
    signed_pre_key_pair = curve.KeyPair.generate()

    signed_pre_key_public = signed_pre_key_pair.public_key().serialize()
    signed_pre_key_signature = (
        store.get_identity_key_pair()
        .private_key()
        .calculate_signature(signed_pre_key_public)
    )

    device_id = random.randint(1, 10000)
    pre_key_id = random.randint(1, 10000)
    signed_pre_key_id = random.randint(1, 10000)

    pre_key_bundle = state.PreKeyBundle(
        store.get_local_registration_id(),
        device_id,
        pre_key_id,
        pre_key_pair.public_key(),
        signed_pre_key_id,
        signed_pre_key_pair.public_key(),
        signed_pre_key_signature,
        store.get_identity_key_pair().identity_key(),
    )

    store.save_pre_key(pre_key_id, state.PreKeyRecord(pre_key_id, pre_key_pair))

    timestamp = random.randint(1, 10000)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        timestamp,
        signed_pre_key_pair,
        signed_pre_key_signature,
    )
    store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    return pre_key_bundle
# Store should be persisted to disk
store = storage.InMemSignalProtocolStore(identity_key_pair, registration_id)
# Store this somewhere
signed_pre_key_id = 233
signed_pre_key_pair = curve.KeyPair.generate()
signed_pre_key_public = signed_pre_key_pair.public_key().serialize()
signed_pre_key_signature = (store.get_identity_key_pair().private_key().
                            calculate_signature(signed_pre_key_public))
signed_prekey_timestamp = int(time.time())

# prekey = state.PreKeyRecord(pre_key_id, pre_key_pair)
# store.save_pre_key(pre_key_id, prekey)

signed_prekey = state.SignedPreKeyRecord(
    signed_pre_key_id,
    signed_prekey_timestamp,
    signed_pre_key_pair,
    signed_pre_key_signature,
)
store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

print("done! now attempting registration with the server...")
resp = requests.post('http://127.0.0.1:8081/api/v2/register',
                     data=json.dumps({
                         "signed_prekey_id":
                         signed_pre_key_id,
                         "signed_prekey":
                         signed_pre_key_public.hex(),
                         "signed_prekey_timestamp":
                         signed_prekey_timestamp,
                         "identity_key":
                         identity_key_pair.public_key().serialize().hex(),
示例#4
0
def test_optional_one_time_prekey():
    alice_address = address.ProtocolAddress("+14151111111", DEVICE_ID)
    bob_address = address.ProtocolAddress("+14151111112", DEVICE_ID)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    bob_identity_key_pair = identity_key.IdentityKeyPair.generate()

    alice_registration_id = 1  # TODO: generate these
    bob_registration_id = 2

    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)
    bob_store = storage.InMemSignalProtocolStore(bob_identity_key_pair,
                                                 bob_registration_id)

    bob_signed_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )
    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        None,  # No prekey
        None,  # No prekey
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    assert alice_store.load_session(bob_address).session_version() == 3

    original_message = b"Hobgoblins hold themselves to high standards of military honor"

    outgoing_message = session_cipher.message_encrypt(alice_store, bob_address,
                                                      original_message)
    outgoing_message.message_type() == 3  # 3 == CiphertextMessageType::PreKey

    incoming_message = protocol.PreKeySignalMessage.try_from(
        outgoing_message.serialize())

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )
    bob_store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    plaintext = session_cipher.message_decrypt(bob_store, alice_address,
                                               incoming_message)
    assert original_message == plaintext
示例#5
0
def test_bad_message_bundle():
    alice_address = address.ProtocolAddress("+14151111111", DEVICE_ID)
    bob_address = address.ProtocolAddress("+14151111112", DEVICE_ID)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    bob_identity_key_pair = identity_key.IdentityKeyPair.generate()

    alice_registration_id = 1  # TODO: generate these
    bob_registration_id = 2

    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)
    bob_store = storage.InMemSignalProtocolStore(bob_identity_key_pair,
                                                 bob_registration_id)

    bob_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_pair = curve.KeyPair.generate()

    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )

    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    pre_key_id = 31337
    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    bob_prekey = state.PreKeyRecord(pre_key_id, bob_pre_key_pair)
    bob_store.save_pre_key(pre_key_id, bob_prekey)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )
    bob_store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    assert alice_store.load_session(bob_address)
    assert alice_store.load_session(bob_address).session_version() == 3

    original_message = b"Hobgoblins hold themselves to high standards of military honor"

    assert bob_store.get_pre_key(pre_key_id)

    outgoing_message = session_cipher.message_encrypt(alice_store, bob_address,
                                                      original_message)
    outgoing_message.message_type() == 3  # 3 == CiphertextMessageType::PreKey
    outgoing_message_wire = outgoing_message.serialize()

    edit_point = len(outgoing_message_wire) - 10
    corrupted_message = (outgoing_message_wire[:edit_point] +
                         bytes([outgoing_message_wire[edit_point] ^ 0x01]) +
                         outgoing_message_wire[edit_point + 1:])

    incoming_message = protocol.PreKeySignalMessage.try_from(corrupted_message)

    # This incoming message is corrupted, so we expect an exception to be raised
    with pytest.raises(SignalProtocolException):
        session_cipher.message_decrypt(bob_store, alice_address,
                                       incoming_message)

    assert bob_store.get_pre_key(pre_key_id)

    incoming_message = protocol.PreKeySignalMessage.try_from(
        outgoing_message_wire)

    plaintext = session_cipher.message_decrypt(bob_store, alice_address,
                                               incoming_message)

    assert original_message == plaintext

    # Trying to get the prekey will now fail, as the prekey has been used and removed from the store
    with pytest.raises(SignalProtocolException,
                       match="invalid prekey identifier"):
        assert bob_store.get_pre_key(pre_key_id)
示例#6
0
def test_repeat_bundle_message_v3():
    alice_address = address.ProtocolAddress("+14151111111", DEVICE_ID)
    bob_address = address.ProtocolAddress("+14151111112", DEVICE_ID)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    bob_identity_key_pair = identity_key.IdentityKeyPair.generate()

    alice_registration_id = 1  # TODO: generate these
    bob_registration_id = 2

    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)
    bob_store = storage.InMemSignalProtocolStore(bob_identity_key_pair,
                                                 bob_registration_id)

    bob_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_pair = curve.KeyPair.generate()

    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )

    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    pre_key_id = 31337
    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    assert alice_store.load_session(bob_address)
    assert alice_store.load_session(bob_address).session_version() == 3

    original_message = b"Hobgoblins hold themselves to high standards of military honor"

    outgoing_message1 = session_cipher.message_encrypt(alice_store,
                                                       bob_address,
                                                       original_message)
    outgoing_message2 = session_cipher.message_encrypt(alice_store,
                                                       bob_address,
                                                       original_message)
    outgoing_message1.message_type() == 3  # 3 == CiphertextMessageType::PreKey
    outgoing_message2.message_type() == 3  # 3 == CiphertextMessageType::PreKey

    incoming_message = protocol.PreKeySignalMessage.try_from(
        outgoing_message1.serialize())

    bob_prekey = state.PreKeyRecord(pre_key_id, bob_pre_key_pair)
    bob_store.save_pre_key(pre_key_id, bob_prekey)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )
    bob_store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    ptext = session_cipher.message_decrypt(bob_store, alice_address,
                                           incoming_message)
    assert original_message == ptext

    bob_outgoing = session_cipher.message_encrypt(bob_store, alice_address,
                                                  original_message)
    assert bob_outgoing.message_type(
    ) == 2  # 2 == CiphertextMessageType::Whisper

    alice_decrypts = session_cipher.message_decrypt(alice_store, bob_address,
                                                    bob_outgoing)
    assert alice_decrypts == original_message

    # Verify the second message can be processed

    incoming_message2 = protocol.PreKeySignalMessage.try_from(
        outgoing_message2.serialize())
    ptext = session_cipher.message_decrypt(bob_store, alice_address,
                                           incoming_message2)
    assert original_message == ptext

    bob_outgoing = session_cipher.message_encrypt(bob_store, alice_address,
                                                  original_message)
    alice_decrypts = session_cipher.message_decrypt(alice_store, bob_address,
                                                    bob_outgoing)
    assert alice_decrypts == original_message
示例#7
0
def test_basic_prekey_v3():
    alice_address = address.ProtocolAddress("+14151111111", DEVICE_ID)
    bob_address = address.ProtocolAddress("+14151111112", DEVICE_ID)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    bob_identity_key_pair = identity_key.IdentityKeyPair.generate()

    alice_registration_id = 1  # TODO: generate these
    bob_registration_id = 2

    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)
    bob_store = storage.InMemSignalProtocolStore(bob_identity_key_pair,
                                                 bob_registration_id)

    bob_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_pair = curve.KeyPair.generate()

    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )

    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    pre_key_id = 31337
    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    assert alice_store.load_session(bob_address) is None

    # Below standalone function would make more sense as a method on alice_store?
    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    assert alice_store.load_session(bob_address)
    assert alice_store.load_session(bob_address).session_version() == 3

    original_message = b"Hobgoblins hold themselves to high standards of military honor"

    outgoing_message = session_cipher.message_encrypt(alice_store, bob_address,
                                                      original_message)
    outgoing_message.message_type() == 3  # 3 == CiphertextMessageType::PreKey
    outgoing_message_wire = outgoing_message.serialize()

    # Now over to fake Bob for processing the first message

    incoming_message = protocol.PreKeySignalMessage.try_from(
        outgoing_message_wire)

    bob_prekey = state.PreKeyRecord(pre_key_id, bob_pre_key_pair)
    bob_store.save_pre_key(pre_key_id, bob_prekey)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )

    bob_store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    assert bob_store.load_session(alice_address) is None

    plaintext = session_cipher.message_decrypt(bob_store, alice_address,
                                               incoming_message)

    assert original_message == plaintext

    bobs_response = b"Who watches the watchers?"

    assert bob_store.load_session(alice_address)

    bobs_session_with_alice = bob_store.load_session(alice_address)
    assert bobs_session_with_alice.session_version() == 3
    assert len(bobs_session_with_alice.alice_base_key()) == 32 + 1

    bob_outgoing = session_cipher.message_encrypt(bob_store, alice_address,
                                                  bobs_response)
    assert bob_outgoing.message_type(
    ) == 2  # 2 == CiphertextMessageType::Whisper

    # Now back to fake alice

    alice_decrypts = session_cipher.message_decrypt(alice_store, bob_address,
                                                    bob_outgoing)
    assert alice_decrypts == bobs_response

    run_interaction(alice_store, alice_address, bob_store, bob_address)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    alice_registration_id = 1  # TODO: generate these
    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)

    bob_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )

    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    pre_key_id = 31337
    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id + 1,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id + 1,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    bob_prekey = state.PreKeyRecord(pre_key_id + 1, bob_pre_key_pair)
    bob_store.save_pre_key(pre_key_id + 1, bob_prekey)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id + 1,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )
    bob_store.save_signed_pre_key(signed_pre_key_id + 1, signed_prekey)

    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    outgoing_message = session_cipher.message_encrypt(alice_store, bob_address,
                                                      original_message)

    with pytest.raises(SignalProtocolException, match="untrusted identity"):
        session_cipher.message_decrypt(bob_store, alice_address,
                                       outgoing_message)

    assert bob_store.save_identity(
        alice_address,
        alice_store.get_identity_key_pair().identity_key())

    decrypted = session_cipher.message_decrypt(bob_store, alice_address,
                                               outgoing_message)
    assert decrypted == original_message

    # Sign pre-key with wrong key
    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        alice_store.get_identity_key_pair().identity_key(),
    )

    with pytest.raises(SignalProtocolException):
        session.process_prekey_bundle(bob_address, alice_store,
                                      bob_pre_key_bundle)
示例#8
0
def test_basic_large_message():
    alice_address = address.ProtocolAddress("+14151111111", DEVICE_ID)
    bob_address = address.ProtocolAddress("+14151111112", DEVICE_ID)

    alice_identity_key_pair = identity_key.IdentityKeyPair.generate()
    bob_identity_key_pair = identity_key.IdentityKeyPair.generate()

    alice_registration_id = 1  # TODO: generate these
    bob_registration_id = 2

    alice_store = storage.InMemSignalProtocolStore(alice_identity_key_pair,
                                                   alice_registration_id)
    bob_store = storage.InMemSignalProtocolStore(bob_identity_key_pair,
                                                 bob_registration_id)

    bob_pre_key_pair = curve.KeyPair.generate()
    bob_signed_pre_key_pair = curve.KeyPair.generate()

    bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key().serialize(
    )

    bob_signed_pre_key_signature = (bob_store.get_identity_key_pair(
    ).private_key().calculate_signature(bob_signed_pre_key_public))

    pre_key_id = 31337
    signed_pre_key_id = 22

    bob_pre_key_bundle = state.PreKeyBundle(
        bob_store.get_local_registration_id(),
        DEVICE_ID,
        pre_key_id,
        bob_pre_key_pair.public_key(),
        signed_pre_key_id,
        bob_signed_pre_key_pair.public_key(),
        bob_signed_pre_key_signature,
        bob_store.get_identity_key_pair().identity_key(),
    )

    assert alice_store.load_session(bob_address) is None

    # Below standalone function would make more sense as a method on alice_store?
    session.process_prekey_bundle(
        bob_address,
        alice_store,
        bob_pre_key_bundle,
    )

    assert alice_store.load_session(bob_address)
    assert alice_store.load_session(bob_address).session_version() == 3

    original_message = bytes(1024 * 1000)  # 1 MB empty attachment

    outgoing_message = session_cipher.message_encrypt(alice_store, bob_address,
                                                      original_message)
    outgoing_message.message_type() == 3  # 3 == CiphertextMessageType::PreKey
    outgoing_message_wire = outgoing_message.serialize()

    incoming_message = protocol.PreKeySignalMessage.try_from(
        outgoing_message_wire)

    bob_prekey = state.PreKeyRecord(pre_key_id, bob_pre_key_pair)
    bob_store.save_pre_key(pre_key_id, bob_prekey)

    signed_prekey = state.SignedPreKeyRecord(
        signed_pre_key_id,
        42,
        bob_signed_pre_key_pair,
        bob_signed_pre_key_signature,
    )

    bob_store.save_signed_pre_key(signed_pre_key_id, signed_prekey)

    plaintext = session_cipher.message_decrypt(bob_store, alice_address,
                                               incoming_message)

    assert original_message == plaintext