Search code examples
javaandroidencryptionrsaprivacy

How to encrypt/decrypt sent/received messages in Android?


We are building a chat client (something like Whatsapp, etc.) for sending and receiving private messages. For the sake of privacy we decided to encrypt and decrypt the messages upon arrival and sending.

I figured we could use RSA private and public keys for encryption. I understand that we usually need two pairs of keys, one of which residing on the server and one on the phone. This brings up some questions which I'm asking here.

  1. How to generate a key pair in android?
  2. How should they be stored?
  3. Do I need different key pairs for every user on the server as well as on the clients?

Please feel free to add any useful information for I am a complete newbie in security.


Solution

  • You will need a central server which provides certificates for each user to authenticate users (otherwise you will always be vulnerable to a man in the middle attack). So for two users (Joe and Sally), there will be three certificates: 1) the certificate authenticating your central server, 2) the certificate authenticating Joe and 3) the certificate authenticating Sally.

    So when Joe wants to initiate communication with Sally the following should happen:

    1. Joe requests Sally's public key from the central server.
      1. Joe authenticates the server via the server's public key (by checking the digital certificate).
      2. Joe uses the server's public key to encrypt a shared secret key and then sends the encrypted shared secret key to the server.
      3. Only the server can decrypt Joe's shared secret key and thus uses this shared secret key to encrypt (via Symmetric Cryptography) Sally's public key and sends Sally's public key, encrypted via Joe's proposed shared secret key, to Joe.
      4. Joe now has Sally's public key; authenticated because it came from an authenticated server.
    2. Joe sends a request to Sally to initiate communication identifying themselves as "Joe" along with a digital certificate.
      1. Sally authenticates "Joe" via the central server.
      2. Sally retrieves Joe's public key in the same way that Joe obtained Sally's public key from the central server.
    3. Sally sends a shared secret key to Joe.
      1. Sally uses Joe's public key to encrypt a multi-part message which includes 1) the shared secret key and 2) a digital certificate encrypted with Sally's private key.
    4. Joe receives Sally's encrypted message (which only Joe can decrypt since it was encrypted with Joe's public key).
      1. Joe decrypts the message and receives Sally's proposed shared secret key.
      2. Joe receives Sally's digital certificate, encrypted with Joe's public key, and attempts to decrypt with Sally's public key obtained previously from the central server.
      3. If Joe successfully decrypts the digital certificate, then Joe can be assured that Sally is the one who proposed the shared secret key.
      4. Joe sends an acknowledgement of the shared secret to Sally via symmetric cryptography, using the shared secret key.
    5. Sally receives Joe's acknowledgement via Sally's proposed shared secret key.
    6. Sally and Joe can now communicate back and forth using symmetric cryptography via Sally's originally proposed shared secret key.

    So why is all of this necessary? First, you need a "trusted" broker (that's the central server). Otherwise you can never be sure who you are communicating with. You may ask: why does Sally need to sign her shared secret key when only Joe can decrypt it anyway (if Sally uses Joe's public key to encrypt)? The reason is that anyone can encrypt a shared secret key via Joe's public key! Therefore if Joe receives an unsigned shared secret key, he may start communicating with a man in the middle who simply generated a shared secret key using Joe's public key. Just as Sally needs some confirmation that Joe is the actual entity trying to communicate with her, Joe needs some assurance that the shared secret key he receives is actually from Sally (hence why she needs to sign with her private key).

    RSA is not safe!!! Given enough traffic, it is possible to decrypt messages encoded by RSA. Thus, you should have a protocol in place for periodically updating public/private keys used for authentication. This is simple for users: your central server will hold the public keys for each user. Periodically your server should request that each user generate a new private/public key pair and send the public key to the server to be updated (this communication can be done via the previous private/public key used by each user).

    It's a little more "difficult" for the central server itself. If your central server wishes to change its private/public key (authenticating the server), then it needs to communicate with every user to make each user aware of the change. When a user changes his/her private/public key, it's a one-to-one communication (just between the user and the server) but when the server wants to change its private/public key, it must communicate with all users!

    Caveat:

    I don't claim that what I proposed above is the "canonical" pattern. What I claim, is that if you follow the above, you will will ensure both authenticity and integrity. I.e. you can be guaranteed to be communicating with the entity the central server considers to be "Joe" and "Sally" and you can guarantee that only Joe and Sally can communicate because no one, including the central server, knows the shared secret key used by Joe and Sally to communicate (except for Joe and Sally of course).