# How to implement correctly an Integrated Encryption Scheme?

I am developing a REST client (from an Android Point Of Sale) where I'm given a public RSA 2048-bit key and I need to encrypt transaction information. Since that single block cannot be encrypted (and AFAIK it should not) with the public key, we need to encrypt it using AES 128-bit. So we generate a random key (using KeyGenerator class), encrypt the info and send the AES key encrypted under their public key. AES is in ECB mode for their requirement which I know is insecure.

So the question would be: what pitfalls (apart from ECB) this method has?

My idea was to implement a kind of ECIES (but without Elliptic Curve) where a key derivation function is used (altough I'm a noob and don't know how to implement it) and using an authenticated encryption method like AES-GCM.

To extend the question I will like some context as I think I have sparse information and need to "connect altogether".

• Any reason why not to use a existing protocol/format? CMS with RSA-KEM or JWE with RSEES OAEP comes to mind (if you really need to use RSA) – eckes Apr 15 at 23:00
• The reason was the unknowledge of existing protocols/formats for this case. Those two are great suggestions and I found an existing open-source implementation of JWE for Java/Android: github.com/jwtk/jjwt. I'm also reading about KEM, our implementation of RSA uses PKCS#1 Padding which, correct me if I'm wroing, is a form of OAEP. But as I can read on Wikipedia article (en.wikipedia.org/wiki/Key_encapsulation) just encrypting a random generated AES key with the public key is not enough, so a key derivation function is needed (similar to ECIES). – Guillermo Garcia Maynez Apr 16 at 19:54
• OAEP tries to fix some of the shortcomings of the PKCS1.5 padding. It is a bit unclear if it is needed but some compliance regulations go in that direction. – eckes Apr 16 at 19:57
• @eckes PKCS1v1.5 encryption is practically impossible to use correctly due to its extreme sensitivity to timing. See Bleichenbacher's 1998 paper, Coron 2000, too many follow-ups to list, 2018 return, even his CAT, … Don't use it. OAEP is definitely needed (or RSAKEM). – Gilles Apr 17 at 19:03
• @gilles yes that’s why I recommended it. PKCSv15 padding is risky if you don’t use an established implementation (however TLS use case allows an particular easy Oracle which is less of an issue for message based scenarios) – eckes Apr 17 at 19:46

You have the right idea! There's a very general construction for public-key encryption called KEM/DEM that works as follows to encrypt a message $$m$$:

1. Key encapsulation mechanism, KEM: Generate a key $$k$$ and an encapsulation $$y$$ using a public key.
2. Data encapsulation mechanism, DEM: Use $$k$$ to authenticate and encrypt $$m$$ giving an authenticated ciphertext $$c$$.
3. Transmit the encapsulation $$y$$ along with the ciphertext $$c$$.

The recipient, with the secret key, can recover $$k$$ from $$y$$ and then decrypt $$c$$.

For RSA, you can make a KEM as follows with a public key $$n$$:

• Pick an integer $$x$$ between $$0$$ and $$n$$ uniformly at random.
• Compute $$y = x^3 \bmod n$$.
• Compute $$k = H(x)$$, where $$H$$ is (say) SHA-256.

The recipient uses secret knowledge of the solution $$d$$ to $$3d \equiv 1 \pmod{\lambda(n)}$$, where $$\lambda(n) = \operatorname{lcm}(p - 1, q - 1)$$ if $$n = pq$$, to recover $$x = y^d \bmod n$$, and then computes the same $$k = H(x)$$.

The security requirement for a DEM is modest. An authenticated cipher like AES-GCM or NaCl crypto_secretbox_xsalsa20poly1305, with nonce set to zero, will do just fine. (I recommend AES-256 if you must use AES, to avoid multi-target attacks; I recommend crypto_secretbox_xsalsa20poly1305 over AES-GCM, to avoid side channel attacks on AES and GHASH in fast software implementations.)

ECIES is an example of the KEM/DEM structure—for a public key $$A$$ on an elliptic curve with standard base point $$B$$, you pick a scalar $$t$$ uniformly at random, compute $$T = [t]B$$, derive the key $$k = H([t]A)$$, and use $$T$$ as the encapsulation of the secret key $$k$$ which you use in an authenticated cipher to encrypt the message; the recipient knows the secret $$a$$ such that $$A = [a]B$$, and given $$T$$ recovers $$H([a]T) = H([a\cdot t] B) = H([t\cdot a]B) = H([t]A) = k$$ to decrypt the authenticated ciphertext.

You can also generate $$k$$ independently and shoe-horn it into an encapsulation like RSAES-OAEP. But, while this is probably the most common way to do RSA encryption out of inertia, it is more complicated than necessary.

• Note that the exponent 3 is an example. Not every library allows 3 as exponent, if you're worried about compatibility you might want to use F4 (65537 or 0x010001 in hex). 0, 1 and N should probably not in the range for x but that really doesn't matter much with any secure RSA key size (checking for 0 could however remove some problems where the RNG produces exclusively 0 bits). – Maarten Bodewes Apr 19 at 12:29

So in order to give an answer to the actual question and with the help of @eckes:

ECIES is a good option, a good library for implementing it in C# is Inferno: https://securitydriven.net/inferno

In Java (and also C#) there is BouncyCastle, altough author of Inferno bashes it saying that is "a huge (145k LOC), poorly-performing museum catalogue of crypto (some of it ancient), with old Java implementations ported to equally-old .NET (2.0?)". This is relevant since its known that altough cryptographic algorithms can be safe in their definition, poor implementations lead to unsecure systems.

• Just saw the answer of Squeamish :) – Guillermo Garcia Maynez Apr 17 at 17:29
• This doesn't answer your own question, as you specified RSA as requirement. Just copying somebody's strongly opinionated site doesn't seem to be good practice to me, especially if it bashes a crypto library, which is not even the topic of your question. – Maarten Bodewes Apr 19 at 12:34
• I'm looking forward to get the guidelines of avoiding common pitfalls in systems security, kind of: if you go trough the red light, there is a very high chance you'll crash, because many developers (like me) do not have a strong security background. While RSA is a requirement, it can be negotiated with the other end the change to a more secure implementation. RSA many times is chosen because is what they know... – Guillermo Garcia Maynez Apr 20 at 17:45