# Is this a secure (and correct) sign-then-encrypt technique for transferring messages?

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:

1. Prefix the plain text with the sender and receivers public RSA keys (to be used for confirmation by the receiver).
2. Get the SHA256 hash of the data from step 1 (public keys and plain text).
3. Sign the hash with senders private ECDSA key.
4. Prefix the original plain text with the signature.
5. Generate a random 128-bit key and 128-bit IV using a cryptographically secure RNG.
6. Encrypt the data from step 4 (signature and original plain text) using AES-128 in CTR mode with PKCS7 padding.
7. Encrypt the key and IV using the receivers public RSA key and prefix it to the encrypted message from step 7.
8. Send the encrypted data from step 7 to the other uses, preferably over a secure channel.

The decryption process:

1. Use the receivers private RSA key to decrypt the key and IV.
2. Decrypt the remainder of the message in AES-128 using the key and IV from step 1.
3. Extract the plain text message from the data in step 2 and prefix it with the expected sender and receivers public RSA key.
4. Get the SHA256 hash of the data from step 3 (public keys and plain text).
5. Extract the signature from the data in step 2 and verify the signature against the SHA256 hash.
6. 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.
7. 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?

-
IMO it's a silly design. 1280 bit RSA sucks for confidentiality but might be good enough for authentication. ECDSA on the other hand is trickier to use than RSA encryption, since it needs good randomness for each signature (unless you use an uncommon deterministic variant). Using EC-DH (256 bit) for key-exchange (and thus encryption) and RSA for signing would be a far better choice. Or just one algorithm for both. –  CodesInChaos Mar 18 '14 at 14:40
@CodesInChaos The keys were picked as I was trying to see if I could replicate way iMessage currently works, which also uses these keys according to their security whitepaper. The complexity in the implementation of the actual algorithms isn't an issue as I will be using methods from an existing library. I was under the impression that RSA was faster for encryption and ECDSA was better for validation. link –  Robert Davey Mar 18 '14 at 16:15
RSA is very fast for encryption and signature verification (public key operations) and slow for decryption and signing (private key operations). ECC has decent performance for all operations. If you sum the cost of encryption and decryption, RSA is certainly much slower than than its ECC equivalent (by a factor 10 or so). –  CodesInChaos Mar 18 '14 at 16:19
The signatures should use RMX, so that they don't need full collision-resistance. $\:$ The symmetric encryption part should use authenticated encryption. $\:$ Also, your technique should be modified so that it will still work and be secure when there are multiple users, there is no "expected sender", and each user only has one encryption key and one signing key. $\;\;\;\;$ –  Ricky Demer Mar 18 '14 at 22:47
Assuming the signature hash algorithm is changed to something that is not susceptible to length extension, would the signature not be acceptable in place of authenticated encryption? –  Richie Frame Mar 19 '14 at 10:43