Search code examples
javascriptencryptionrsap2pend-to-end

How does the sender decrypt his own encrypted message


I'm working on a chat application where messages will be end-to-end encrypted. To achieve this I'm using RSA key's with the node-forge library. I can now encrypt a message with the public key of the recipient and decrypt it only with his private key. The problem is that I want the sender to be able to decrypt the message they send, not just the receiver. How can I achieve that?

Here I have some example code and the output.

var simulateMessageSend = (function () {
            var plainText = "This is a test message that is going to be encrypted. "
            console.log(plainText);

            var encrypted = publickey2.encrypt(this.$forge.util.encodeUtf8(plainText));
            console.log("Encryption: ");
            console.log(encrypted)

            simulateMessageReceived(encrypted)

        }.bind(this))

var simulateMessageReceived = (function (encrypted) {

    var decrypted = this.$forge.util.decodeUtf8(privatekey2.decrypt(encrypted));

    console.log("Decryption: ");
    console.log(decrypted);

}.bind(this))

output: enter image description here


Solution

  • The answer to "how can the sender also decrypt" is to use a hybrid crypto system.

    (directly encrypting with RSA is not a good idea as there will be data loss should you encrypt a data payload larger than the modulus n, where the modulus is the product of the two primes p and q, for RSA-2048 we use two 1024-bit prime numbers, for RSA-4096 we use two 2048-bit prime numbers).

    Instead,

    1. generate a strong, high entropy symmetric key.
    2. encrypt the payload with this symmetric key using a modern symmetric cipher.
    3. encrypt the symmetric key using each recipients public RSA key (in this case the sender and receiver).
    4. attach the encrypted symmetric key to the payload, send payload of encrypted message + encrypted symmetric key(s).
    5. recover symmetric key(s) with each private key counterpart.
    6. use symmetric key to decrypt message.

    This is still bad engineering, because:

    1. you're not using ephemeral keys, you are using static:static RSA, (instead one should use temporary keys for each message).
    2. don't use RSA use ECC over a strong curve such as curve25519, performing ECDHE to agree symmetric primitives for message encryption, (request ephemeral public key, perform ECDHE with your ephemeral private key, dispatch payload with your ephemeral public key so recipient may also use ECDHE with their ephemeral private key to generate ephemeral symmetric key).
    3. authenticate with static Ed25519 keys or 3XDH.

    Overall, strong E2E messaging systems are hard to engineer. Tread carefully if you are using this home-brew solution against a serious threat model.

    Please take a read, but if you have further questions don't hesitate to ask below. I'm happy to provide more detail in simple language.