# Doing RSA-KEM with RSA-OAEP

I am fiddling around with the JS Web Crypto API and creating a hybrid encryption system that uses a symmetric key to encrypt form data with AES256-CBC and and a public/private key-pair to wrap/encapsulate the symmetric key using RSA-OAEP.

Currently I am simply generating a random 256bit key that will get padded and wrapped by RSA-OAEP.

I stumbled across RSA-KEM in RFC 5990 and love the fact that I can derive both the encryption key and iv (and many other keys) from it via HKDF. HKDF is a supported algorithm in the Web Crypto API but RSA-KEM says I should use "simple RSA" without any padding to encrypt the random element for key derivation which is surprisingly an algorithm not mentioned in the W3C specifications.

Can I encrypt the random element used for key derivation with RSA-OAEP (even the padding is not needed) or are there any security concerns? Should I stick to my current implementation?

If what you have is a machine that computes RSAES-OAEP and not a machine that computes $x \mapsto x^e \bmod n$, you don't really have the tools to do RSA-KEM. You're better off doing what you were doing in the first place—unless I can talk you out of going near the incoherent minefield of hysterical raisins without meaningful guidance that is the WebCrypto API.

Now, it is technically possible to abuse RSAES-OAEP to give the simulacrum of an RSA-KEM implementation. It might even be compatible with RSA-KEM implementations on either side, but you really shouldn't try to simulate RSA-KEM using RSAES-OAEP unless you are desperate and your RSAES-OAEP machine accepts the OAEP randomization as a parameter and returns it on decryption and you have a separate subroutine to compute OAEP alone without the RSA part.

For a message $m$ to an RSA modulus $n$, the sender could do:

1. Pick $k_0 \in \{0,1\}^{256}$ and $r \in \{0,1\}^{256}$ uniformly at random.
2. Compute $x = \operatorname{OAEP}_n(k_0, r)$. (This is the padded element of $\mathbb Z/n\mathbb Z$ before we compute modular exponentiation, raising it to the power of the public exponent $e$.)
3. Compute $k = H(x)$ (e.g., use HKDF).
4. Compute $y = \operatorname{RSAES-OAEP}_n(k_0, r)$ so that $y = x^3 \bmod n$.
5. Yield the key $k$ and its encapsulation $y$.

On receipt of $y$, the recipient could do:

1. Compute $(k_0, r) = \operatorname{RSAES-OAEP}_n^{-1}(y)$ or reject if RSAES-OAEP decryption fails. (Beware padding oracle attacks!)
2. Compute $x = \operatorname{OAEP}_n(k_0, r)$.
3. Compute and yield the key $k = H(x)$.

Note that this also requires a subroutine to compute OAEP itself, and requires the public key operation $\operatorname{RSAES-OAEP}_n$ to accept the OAEP randomization $r$ as a parameter alongside the short string to be encrypted, and requires the private key operation $\operatorname{RSAES-OAEP}_n^{-1}$ to yield the OAEP randomization $r$ that was encrypted alongside the short string.

So in the end, although as a black box this is probably (unless I made a mistake) indistinguishable from RSA-KEM, it's much more complicated to implement than just encapsulating the randomly generated key $k_0$ with RSAES-OAEP as a sort of ‘RSAES-OAEP-KEM’ as you were doing in the first place.

• Thank you very much for your explanation! If I understand correctly I should do the KDF over the "OAEP-padded n". Would it be possible to choose an $x \in \{0,1\}^{2048}$ instead and use these to calculate $k = H(x)$ and $y = \operatorname{RSAES-OAEP}_n(x)$? – HenningCash May 8 '18 at 9:46
• @HenningCash No, you should do what you were doing oriignally: pick $k \in \{0,1\}^{2048}$, transmit $y = \operatorname{RSAES-OAEP}_n(k)$, and forget about RSA-KEM for this context unless you actually do have access to a machine that computes $x \mapsto x^3 \bmod n$ rather than RSAES-OAEP. – Squeamish Ossifrage May 8 '18 at 12:46
• @HenningCash I meant pick $k \in \{0,1\}^{256}$, not $k \in \{0,1\}^{2048}$, sorry, but it's too late to edit the comment now. I.e., just use RSAES-OAEP like you are doing anyway and forget about RSA-KEM. – Squeamish Ossifrage May 9 '18 at 3:21

You should probably stick to your current implementation. Of course, if you need to generate an IV as well you can always include it into the OAEP encryption. And you might just put in a seed into OAEP which you can put into any KDF to derive a key and IV as well.

The advantage of RSA-KEM is that it is relatively easy to implement and thus secure. RSA-OAEP is however also thought to be secure if correctly implemented.

There is little difference if you perform a KDF over 256 bits or, say, 2048 bits, so there is no reason to choose RSA-KEM over OAEP because it creates a larger seed.