How to require two PRIVATE keyholders to decrypt a document?

Consider 3 entities A,B and C. I want A to be able to encrypt a document that can be decrypted only when keys of both B and C are combined. This question talks about a similar problem, but it uses AES.

In my usecase, I don't want the keys to be shared across the entities. There is one solution that was coming to my mind: A encrypts the document (with RSA) first using public key of B and then public key of C. Then the document is decrypted using private key of C and then private key of B.

Is this approach feasible? Is there a better way?

Note: I tried doing this but got this error when I was doing encryption for the 2nd time: Data must not be longer than 117 bytes.

Yes, you can use a symmetric secret sharing scheme, where the parts required for secret sharing are encrypted with the keys of B and C. Once B and C decrypt the parts they can combine their parts to create a symmetric data key, which is the key that is used to encrypt the document.

The very simplest way of sharing a key between two parties is to create a random data key and encrypt the document. Then create a random byte array with the same size as the data key, call it the key part of B. XOR this key part with the data key; the result is key part of C.

Now simply encrypt the key parts of the respective parties with their public keys. Now they can only access it using their private keys. For sharing, they can decrypt their part and send their key part to the other party, if required encrypted with the other parties public key. That way the final party that gets the ciphertext and both key parts encrypted with their public key. They can decrypt, combine the key parts using XOR, giving the data key. Finally they can decipher the ciphertext.

This will also solve the issue with the size of the plaintext message. RSA is limited to a certain amount of data, so in case of a 1024 bit key, you only get 117 bytes of plaintext message. However, if you use AES/GCM and RSA/OAEP in the secret sharing scheme above, then you can encrypt a message of any size with the symmetric cipher.

Note that 1024 keys are not considered all that secure anymore; you should use a key size of 3072 bits or higher. PKCS#1 v1.5 padding, that you are using, is also considered less secure nowadays due to the Bleichenbacher attacks on it.

It sounds like you want a method where you encrypt to two different public keys, so that the two holders of the private keys must cooperate to decrypt, and that it is important to make the encoding as short as possible.

One method that comes to mind would be to extend IES to use multiple keys, as follows:

• With normal IES (with Elliptic Curves; important to make things short), the encryptor selects a random $$r$$, and then computes $$rG$$ (where $$G$$ is the curve generator), and places that into the ciphertext. And then, he computes $$rP$$ (where $$P$$ is the public key he is encrypting to), sends the value $$rP$$ through a key derivation function $$KDF(rP)$$, and then uses that to generate symmetric keys which are used to encrypt the message (and that symmetric encryption is also placed into the ciphertext). The total overhead taken is the space taken by the $$rG$$ value (32 bytes for Curve25519), plus the overhead used by the symmetric cipher (perhaps 16 bytes), and so it is relatively minimal (for a public key encryption method).

• To decrypt an IES message, the decryptor knows the value $$p$$ such that $$pG = P$$. With this value, he takes the value $$rG$$ in the ciphertext, and computes $$p(rG) = r(pG) = rP$$. He then passes that through the KDF to generate the symmetric keys; he then uses those keys to decrypt the symmetric encryption in the ciphertext, resulting in the original message.

• With this multi-IES, to encrypt a message $$M$$ to two different public keys, the encryptor selects a random $$r$$ and computes $$rG$$) and places that into the ciphertext (just like in IES). Then, he computes $$rP_{a}$$ and $$rP_{b}$$ (where $$P_a, P_b$$ are the public keys), and sends both of them through KDF $$KDF(rP_a, rP_b)$$; and then use that to generate symmetric encryption keys (just like in IES).

That is, the ciphertext corresponding to plaintext message $$M$$ is:

$$rG, \text{Encrypt}_K(M)$$

where $$K = KDF( rP_a, rP_b)$$, and $$\text{Encrypt}$$ is your favorite AEAD symmetric cipher.

The overhead is exactly the same as standard IES (unless if you want to add something to tell people exactly which public keys were used - it's not obvious from the encoding). And, without the cooperation of both holders of the private keys $$p_aG = P_a$$, $$p_bG = P_b$$), you cannot evaluate the inputs to the KDF to generate the symmetric keys, and so cannot read the message.

• I assume that this is near identical to my answer, but using ECIES and a KDF instead of RSA encryption and XOR? Not a critique - just a question, I like more modern constructs such as above. Apr 6, 2020 at 13:19
• @MaartenBodewes: yes, they're certainly similar. However, with this approach, you don't need to give different ciphertexts for the different public keys (and the OP highlighted the need to limit ciphertext size - without that, there are lots of different options) Apr 6, 2020 at 13:24
• Well you have to share the ephemeral public keys, but just with normal ECIES I presume that will still be smaller than the RSA alternative. No difference there really :) Apr 6, 2020 at 13:35