After reading some information on the way iMessage works I have been working on writing some code to try my hand at securely transferring messages in a similar manner and I wanted to confirm that the technique I'm using is considered secure and preferably best practice.
This process assumes that the sender and receiver have already exchanged public keys in a secure way and they are satisfied that the public keys are correct for the person they wish to communicate with.
I am using the following asymmetric keys:
- RSA 1280-bit for encryption
- ECDSA 256-bit for signing
The encryption process:
- Prefix the plain text with the sender and receivers public RSA keys (to be used for confirmation by the receiver).
- Get the SHA256 hash of the data from step 1 (public keys and plain text).
- Sign the hash with senders private ECDSA key.
- Prefix the original plain text with the signature.
- Generate a random 128-bit key and 128-bit IV using a cryptographically secure RNG.
- Encrypt the data from step 4 (signature and original plain text) using AES-128 in CTR mode with PKCS7 padding.
- Encrypt the key and IV using the receivers public RSA key and prefix it to the encrypted message from step 7.
- Send the encrypted data from step 7 to the other uses, preferably over a secure channel.
The decryption process:
- Use the receivers private RSA key to decrypt the key and IV.
- Decrypt the remainder of the message in AES-128 using the key and IV from step 1.
- Extract the plain text message from the data in step 2 and prefix it with the expected sender and receivers public RSA key.
- Get the SHA256 hash of the data from step 3 (public keys and plain text).
- Extract the signature from the data in step 2 and verify the signature against the SHA256 hash.
- If the signature in step 5 is not valid either the message has been altered or the expected sender / receiver was not correct, in which case abort.
- Return the plain text message to the user.
From what I've been reading this seems to be the correct way to transfer the data securely from one party to another. I've not worked out if there is a better way to verify that the expected sender and receiver are correct.
Are there any changes I should be making to this process or is this the correct method to use?