flutterdartencryptionaesend-to-end-encryption

End-to-end encryption Flutter + Firebase real-time database


I am making a chat application where:

  1. A user can be in a group with multiple other users.
  2. All messages must be encrypted with end-to-end

I am using firebase-realtime-database to store data.


What I have

This is probably wrong. I would need clarification if I need to get a derived key from the user's password or if this is sufficient.


What I need

The shared-secret key shares something in common with every personal key, right? So the messages encrypted by any of the participants can be decrypted by any other.

How can I generate the shared-secret key?


Code Blocks Needed

generateKeyPair() {
    // Generate a private - public keypair for each user
    // ...somehow used to make the `shared-secret key`?
}

generateSharedSecretKey() {
    // Saved to database as the group's shared secret key.
    // only participants can use it to decrypt messages
}

sendMessage() {
    // 1. Encrypt the message (**code needed**)...using
    //    which combination of keys?
    // 2. Save to database (I already handle this)
}

receiveMessage() {
    // 1. Read from database (I already handle this)
    // 2. Decrypt the message (**code needed**)...using
    //    which combination of keys?
}

Considerations


I have read about the Diffie–Hellman key exchange, key pairs, etc. But I don't really understand all the concepts as I am quite new.

I would need:

  1. Clarification on basic end-to-end encryption concepts (in case something in my explanation was wrong)
  2. Simple code samples of every key generation step
  3. The code blocks have to work no matter which user is sending a message or receiving. That dynamism is what confuses me. How can you encrypt something taking into account that any of 50 users can read it?

I just want encryption of simple data (strings) with multiple users through a database. Is there is an easier way than end-to-end?


Solution

  • Group Chat

    First the group admin (or whoever creates the group) must generate a single key for the group. This uses symmetric encryption where a single key is used for decryption and encryption. This key should be shared with all the participants.

    enter image description here

    When a participant wants to send the message, it is encrypted using this key and sent to the server, which simply retransmits it to the participants inbox.

    enter image description here

    Since user 2 and 3 already have the shared secret key, they decrypt it client side. There are many choices for this kind of encryption, you can google any "Symmetric Encryption Algorithm" (Eg: AES) and pick one that is available on pub.dev.

    Things to Note:

    1. For server side retransmitting, you could use a simple firebase cloud function or eliminate the server entirely (not recommended) by allowing the client to send the messages to each participant

    EDIT: If you want to encrypt the transport of the Shared Secret Key, you could leverage your existing 1 to 1 architecture and the group admin can send the key to each of the participants by encrypting using the participants public key (which of course they will decrypt on their end). As long as you handle the sendGroupSharedSecretKeyToParticipants() properly on senders side and onReceiveGroupSharedSecretKey() on receivers end, you should be fine. This may complicate things a tad bit (handling of sharing the key differently from a typical chat message) but this would be a simple way to do it.

    1 to 1 Chat

    Each user can have a private key and a public key, messages are sent by encrypting using the receivers public key and the receiver will decrypt it using their own private key, pretty basic stuff which you've already figured out or refer to @Jabbar's answer https://stackoverflow.com/a/74809596/4481095