Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: encrypted chat #488

Merged
merged 11 commits into from
Nov 7, 2023
Merged

feat: encrypted chat #488

merged 11 commits into from
Nov 7, 2023

Conversation

agazso
Copy link
Contributor

@agazso agazso commented Nov 3, 2023

This is a breaking change

Basic encrypted chat. When sharing an invite link the public key is shared instead of the address, therefore it is possible to create a shared secret with ECDH that is used as a symmetric encryption key. The waku topic is the hash of a value derived from the symmetric encryption key. The localStorage is also encrypted, both the keys and the values.

Known issues:

  • The chat id is the actual encryption key and it is used in the URL for both private chats and group chats. Therefore if someone takes a picture of the screen may be able to decrypt a conversation. This can be fixed by using a different value derived from the chat id in the URL.
  • The invite messages are put in a special topic derived from the invited user's public key and they are encrypted, but they are encrypted with a key derived from the invited user's public key. So if you know someone then you can see who invites them to a chat (but not the actuals conversations, because that is encrypted with the ECDH shared secret). This can be fixed by using ECIES with an ephemeral public key for the invites so that only the invitee can see the actual invite messages.
  • The messages are currently not signed, so in a group chat it is possible to impersonate others. The fix could be to use signing for the messages.

Copy link

vercel bot commented Nov 3, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
waku-objects-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 7, 2023 11:47am

Copy link
Contributor

@vojtechsimetka vojtechsimetka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it and it works quite well! I found two things that broke:

  • when someone starts chatting with me (private chat), I am no longer redirected from the invite page to the chat
  • If i already have private a chat with someone and I past the invite link, I am not redirected to that chat. Instead I see the invite screen with options Start new chat and Decline

@@ -35,6 +35,7 @@ export interface WakuObjectState {
readonly exchangeRates: Map<string, ExchangeRateRecord>
readonly fiatSymbol: FiatSymbol
readonly chatName: string
readonly chatType: ChatType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition!

Comment on lines 26 to 34
export function hash(data: Uint8Array): Hex {
const hashBytes = keccak_256(data)
return bytesToHex(hashBytes)
}

export function hashHex(data: Hex): Hex {
const bytes = hexToBytes(data)
return hash(bytes)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be cleaner as single function that takes both Uint8Array and Hex types. It would make it easier to use in code.

Suggested change
export function hash(data: Uint8Array): Hex {
const hashBytes = keccak_256(data)
return bytesToHex(hashBytes)
}
export function hashHex(data: Hex): Hex {
const bytes = hexToBytes(data)
return hash(bytes)
}
export function hash(data: Hex | Uint8Array): Hex {
const bytes = typeof data === 'string' ? hexToBytes(data) | data
const hashBytes = keccak_256(data)
return bytesToHex(hashBytes)
}

@agazso
Copy link
Contributor Author

agazso commented Nov 7, 2023

I tried it and it works quite well! I found two things that broke:

* when someone starts chatting with me (private chat), I am no longer redirected from the invite page to the chat

* If i already have private a chat with someone and I past the invite link, I am not redirected to that chat. Instead I see the invite screen with options `Start new chat` and `Decline`

I fixed the second one.

Regarding the first one, there is only a redirect if you are on the invite page (e.g. showing your QR code) otherwise it could be bad UX if the app would just redirect when you are typing in a different chat. On the invite page it is working for me, can you please check if it is working for you?

@vojtechsimetka
Copy link
Contributor

Yes it works now, I get this screen as the person who is inviting someone once the chat is created.

Screenshot 2023-11-07 at 11 46 18

const ownPublicKey = wallet.signingKey.compressedPublicKey

const ownPublicEncryptionKey = hexToBytes(hashHex(ownPublicKey))
const ownPrivateEncryptionKey = hexToBytes(hashHex(wallet.privateKey))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work with external wallets like MetaMask. Not necessarily a huge problem, but good to keep in mind in case we want to support these at some point.

Also, what's the point of encrypting the localStorage if you can just get the wallet's private key and decrypt it anyways? Or where is the wallet stored?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point regarding external wallets.

When you disconnect the mnemonic is deleted from the localstorage, but your other data is not. This way if you are paranoid you can use the app by connecting with your mnemonic and disconnecting when you are done, but your data may stay in the localstorage and you can still keep you contacts etc. Or you can have multiple accounts and change between them easily.

The alternative would be to delete everything from the localstorage when you disconnect, but that would make multiple accounts less convenient, so I choose to use encryption instead.

@agazso agazso merged commit cb46f2a into main Nov 7, 2023
3 checks passed
@agazso agazso deleted the feat/encrypted-chat branch November 7, 2023 12:06
filoozom pushed a commit that referenced this pull request Nov 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

3 participants