PFS and wallet recovery

Hello everyone,
as you know we are working on PFS. The main idea is that we will exchange an x3dh bundle and encrypt message using the double ratchet algorithm.

https://signal.org/docs/specifications/x3dh/

https://signal.org/docs/specifications/doubleratchet/

A problem that we need to solve is wallet recovery and how to handle this.

When a user recover their wallet they will lose all the contacts and messages.

Currently if a contact sends a message to a user who has just recovered their account everything works as expected and the user is able to decrypt the message.

Because X3DH/DR is a stateful process it means that when a user that has just recovered their wallet receive a message from a previous contact, he will not be able to decrypt it (which is the desired behavior otherwise it would break pfs), but he will know that a message has been received.

We need a UX solution on how to explain this to the user.

The most basic thing I can think of is:

When such messages are received, we display a popup/message/chat/whatever to the user, saying:

“{Name generated from public key} has sent you a message, but it looks like the information they have are outdated, would you like to (re)establish a secure channel with them?”
OK/Ignore ,

ignore will not prompt you anymore upon receiving messages from the same user, OK, will establish a secure channel with the user and (possibly) add it back to your contact list.

I would like to introduce the concept of “secure channels” to the user as it is something that we will need in some other scenario, as sometimes we might not be able to ensure PFS and a similar message could be displayed.

What do you think?

3 Likes

I like the idea of accurately communicating the type of connection established wherever we have the opportunity. We currently have a message upon starting a New chat.

Any messages you send here are encrypted and can only be read by you and <contact name>

Has a lock icon to communicate secure. Would this still apply for 1:1 chats or are you saying we would have different chat types? (cc @Obi2020 @maciej)

Some questions to make sure I fully understand the use case as it may impact whether a given copy/design makes sense:

  1. When is an account recovered?
  • When Status is updated
  • When Status is reinstalled
  • Both
  1. What name is generated from the public key?
  • Random name
  • User provided Display name
  • ENS?
  • Could be any of the above?
  1. Is there anyway for us to know this discrepency exists or is this only known to the client upon decryption? In other words, is there any way to let the sender know they have outdated information?

  2. related to this, which is the most accurate description of what we know about a message that has been sent:
    a nothing
    b delivered
    c decrypted
    d read
    e other
    (for all we could possibly also only have a negative, i.e., not delivered, not decrypted, not read, etc.)

Here are some reference how other apps handle contact requests:

WeChat, lets you know how the person found you if they invited you via a group chat. Screenshot_20180822-115955_WeChat

It also give the user a space whereby they can reply to the invite message before adding the user as a contact.

What’s app puts the users in a chat, makes it clear if/if not user is in contact list or from a group.
Screenshot_20180822-120032_WhatsApp

Telegram also will let you know if you have a group in common.
Screenshot_20180822-120239_Telegram

1 Like

thanks for the reply,

we would have a more secure version of that, and there will need to be a discussion on whether we want to keep the old less secure chats or force the user to establish a secure channel in some cases where we can’t do that automatically ( this will be a different topic of discussion probably).

  1. an account is recovered when a user uninstall/install the app, or installs the app on a new device, it s not a day-to-day operation

  2. random generated, ens is also fine if a record exist, we could also potentially display the user set name, but it can be set arbitrarly, so not really useful to prove the identity of the sending user ( public key / identicon are the only ones to be trusted)

  3. possible but we don’t want to do it as it would mean that some automatic action is taken (message sent) on the user behalf, which can be exploited to reduce darkness

  4. currently we send a “seen” receipt if the user sees it.
    Personally i am strongly against it as i find it a very annoying feature ( forces you to reply to messages, and adds a different layer of social interactions).
    having said that the sending user knows if the user has read the message (therefore decrypted).

{Name generated from public key} sent you a message. Would you like to establish a secure channel with them?”
Ignore / Connect

@cammellos further simplied version of what you wrote. I removed " information they have is outdated" because it hinting as what might be info that’s non-essential to the user.

In fact, could it be used anytime someone is trying to contact you (not just after recovery?

From an product/ experience standpoint, is important to indicate that you were connected to the person before recovery? @Graeme @hester

We’re working on the account recovery flow & trying to better set user expectations - including helping them understand that contacts are not recovered. https://github.com/status-im/status-react/issues/5554

@Obi2020 thanks for the reply,

In fact, could it be used anytime someone is trying to contact you (not just after recovery?

Yes, basically once we implement PFS, most of the times the user will be able to send messages without the need of a confirmation from the receiving user, but in some cases a confirmation from the receiving user is necessary.

From an product/ experience standpoint, is important to indicate that you were connected to the person before recovery?

On this we need to be careful as it’s a bit complicated. Essentially we don’t really know if the users were connected before.

In non-malicious usage that is certain to be true, but a malicious user (who has never been in your contacts), could just send a message that could not be decrypted and trigger the same message.

It goes even a bit deeper than that, as we can’t even be sure the message is originating from that particular user as anyone might be able to send a fake message pretending to be someone else, if we implement another property called “plausible deniability” https://en.wikipedia.org/wiki/Deniable_encryption , but that’s probably something to be discussed at later stages.

@Obi2020 I think it is important to know where or how a contact came to find a user from an interaction point of view. i.e user contacted you via #status public group chat.

@cammellos raises a good point about how the feature could be abused and I think it speaks to a deeper issue of identity on the blockchain and how we could persist contacts when a user uninstalls status.

@cammellos we could either make this a privacy setting, or change this to Delivered. Helpful to the sender and no downside for receiver?

Another Q (apologies for overlooking this info somewhere): what is that changes when a user recovers their wallet, with PFS? I know the key changes—but is that the shared secret key or the user’s public key, e.g. their chat ID? e.g. I will have a new chat ID in my profile each time I recover?

1 Like

@rachel having this in privacy settings sounds like a good solution to me, changing to delivered is a bit worse as then a malicious user can use it to “probe” for the user and thus decreasing darkness (any automatic response can be used maliciously, seen is “semi-automatic” as you still have to open the chat, unless you are already on that chat).

With PFS only the encryption keys are lost, the user public key remains the same (just as of now), it’s basically the same as it is now from a user perspective.
The only difference is when receiving a new message from a previous contact, as we won’t be able to read it, so we need to notify the user and they will have to "reset’ the conversation ( currently the message can be read).

Ok, seems like there’s no objection on the method proposed, to recap:

  1. If a user receives a message that cannot be decrypted, it will be prompted with a message (I will go with @Obi2020 suggestion but can be polished/refined at any stage if necessary), asking the user to establish a secure channel or ignore.
  2. Ignore will not prompt the user anymore
  3. Establishing a secure channel will allow the user to communicate again, the sending user might be prompted to re-send the message.

Any objection or we can go ahead an implement this flow?

But if they actually decide to revert that and establish the secure channel (because, for example, they meet in person and confirmed their identities), how can they do that?

@adam it’s a good point,
basically I think eventually this can be solved by having a section of the app where you manage your contacts, there you can have the various option (block, unblock etc), I would push out the first implementation without this and then we can iterate over it

PFS enabled build with wallet recovery flow, with the flow described above, for anyone interested, they don’t upgrade correctly from other PFS enabled builds, but upgrade fine from develop/nightly/release .

To trigger the behavior:

  1. Have A & B exchange 1-to-1 message.

  2. Recover B, do not join public chats or else

  3. Send a message from A to B, you should see the pop up.

  4. Click Connect

  5. Send a message from A to B again, this time B is able to read it.

If at step 3 you are just able to read the message, recover with the other account.

Things that are to be polished still: multiple messages trigger multiple pop up, ignore only closes the pop up. https://status-im.ams3.digitaloceanspaces.com/StatusIm.180830.115553.e07699.pr.apk