Using EVP_PKEY with EVP_EncryptInit_ex

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Using EVP_PKEY with EVP_EncryptInit_ex

Andrew Felsher
Hi,

I'm trying to do what I assumed would be a very common and typical use of OpenSSL. I'm just encrypting and decrypting some data (in code; not from command line). EVP_EncryptInit_ex (and decrypt, update, and final variants) are the standard way to do this.

However, the init functions take a char buffer. All the examples I can find use hard-coded char buffer keys. But obviously I'm not going to be hard-coding my keys. I'm generating them through a couple different means, but ultimately I have EVP_PKEYs (in my case, containing RSA private keys). And there doesn't seem to be a straightforward way to go from EVP_PKEYs to a form consumable by the EVP init functions.

EVP_PKEY_get_raw_private_key looks like it would be perfect, but it was introduced in 1.1.1 and I'm limited to 1.1.0.

This seems like it would be a very common use case, yet I can't seem to find any examples or documentation anywhere.

Am I doing something wrong or making some really off-base assumptions?

Thanks for any help, pointers, or guidance,
Andrew F
Reply | Threaded
Open this post in threaded view
|

Re: Using EVP_PKEY with EVP_EncryptInit_ex

Dmitry Belyavsky-3
Dear Andrew,

You should take a look at CMS implementation as a model. 

For example, you can generate a symmetric key for content encryption and 
algorithm-specific way to pass the symmetric key to the recipient using EVP_PKEY_encrypt.



On Wed, Apr 1, 2020 at 7:35 PM Andrew Felsher <[hidden email]> wrote:
Hi,

I'm trying to do what I assumed would be a very common and typical use of OpenSSL. I'm just encrypting and decrypting some data (in code; not from command line). EVP_EncryptInit_ex (and decrypt, update, and final variants) are the standard way to do this.

However, the init functions take a char buffer. All the examples I can find use hard-coded char buffer keys. But obviously I'm not going to be hard-coding my keys. I'm generating them through a couple different means, but ultimately I have EVP_PKEYs (in my case, containing RSA private keys). And there doesn't seem to be a straightforward way to go from EVP_PKEYs to a form consumable by the EVP init functions.

EVP_PKEY_get_raw_private_key looks like it would be perfect, but it was introduced in 1.1.1 and I'm limited to 1.1.0.

This seems like it would be a very common use case, yet I can't seem to find any examples or documentation anywhere.

Am I doing something wrong or making some really off-base assumptions?

Thanks for any help, pointers, or guidance,
Andrew F


--
SY, Dmitry Belyavsky
Reply | Threaded
Open this post in threaded view
|

Re: Using EVP_PKEY with EVP_EncryptInit_ex

Matt Caswell-2
In reply to this post by Andrew Felsher


On 01/04/2020 17:34, Andrew Felsher wrote:

> Hi,
>
> I'm trying to do what I assumed would be a very common and typical use
> of OpenSSL. I'm just encrypting and decrypting some data (in code; not
> from command line). EVP_EncryptInit_ex (and decrypt, update, and final
> variants) are the standard way to do this.
>
> However, the init functions take a char buffer. All the examples I can
> find use hard-coded char buffer keys. But obviously I'm not going to be
> hard-coding my keys. I'm generating them through a couple different
> means, but ultimately I have EVP_PKEYs (in my case, containing RSA
> private keys). And there doesn't seem to be a straightforward way to go
> from EVP_PKEYs to a form consumable by the EVP init functions.
>
> EVP_PKEY_get_raw_private_key looks like it would be perfect, but it was
> introduced in 1.1.1 and I'm limited to 1.1.0.
>
> This seems like it would be a very common use case, yet I can't seem to
> find any examples or documentation anywhere.
>
> Am I doing something wrong or making some really off-base assumptions?

EVP_EncryptInit_ex does *symmetric* encryption, i.e. both sides of the
communication share the same private key. An RSA key in an EVP_PKEY does
*asymmetric* encryption. Typically anyone can encrypt using the public
RSA key, but only the owner of the private RSA key can decrypt.

Asymmetric encryption using RSA is limited because it can only encrypt a
very small amount of data. It is also very slow compared to symmetric
encryption. Therefore, typically, if you want to encrypt data via an RSA
key you generate a random symmetric key and encrypt that using your RSA
key. Then you encrypt the data using the randomly generated symmetric key.

OpenSSL has a built in high level API for doing this combined operation.
To encrypt you can use the EVP_Seal*() functions. To decrypt use the
EVP_Open*() functions. See:

https://www.openssl.org/docs/man1.1.1/man3/EVP_SealInit.html
https://www.openssl.org/docs/man1.1.1/man3/EVP_OpenInit.html

It is also possible to encrypt directly in RSA using EVP_PKEY_encrypt():

https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_encrypt.html


Matt

Reply | Threaded
Open this post in threaded view
|

Re: Using EVP_PKEY with EVP_EncryptInit_ex

Andrew Felsher
I'm aware of the symmetric/asymmetric differences. But the EVP_Enrypt... API takes the key as a bunch of bytes. It shouldn't care whether it's an RSA key or not, correct? (Though perhaps it would truncate to, in my case, the first 128 bits since I'm using AES-128-XTS.)

But assuming that I can't somehow use the RSA private key's bits as my symmetric key, how should I generate a key without requiring user interaction? Simply calling RAND_bytes?

-Andrew

On Wed, Apr 1, 2020 at 12:53 PM Matt Caswell <[hidden email]> wrote:


On 01/04/2020 17:34, Andrew Felsher wrote:
> Hi,
>
> I'm trying to do what I assumed would be a very common and typical use
> of OpenSSL. I'm just encrypting and decrypting some data (in code; not
> from command line). EVP_EncryptInit_ex (and decrypt, update, and final
> variants) are the standard way to do this.
>
> However, the init functions take a char buffer. All the examples I can
> find use hard-coded char buffer keys. But obviously I'm not going to be
> hard-coding my keys. I'm generating them through a couple different
> means, but ultimately I have EVP_PKEYs (in my case, containing RSA
> private keys). And there doesn't seem to be a straightforward way to go
> from EVP_PKEYs to a form consumable by the EVP init functions.
>
> EVP_PKEY_get_raw_private_key looks like it would be perfect, but it was
> introduced in 1.1.1 and I'm limited to 1.1.0.
>
> This seems like it would be a very common use case, yet I can't seem to
> find any examples or documentation anywhere.
>
> Am I doing something wrong or making some really off-base assumptions?

EVP_EncryptInit_ex does *symmetric* encryption, i.e. both sides of the
communication share the same private key. An RSA key in an EVP_PKEY does
*asymmetric* encryption. Typically anyone can encrypt using the public
RSA key, but only the owner of the private RSA key can decrypt.

Asymmetric encryption using RSA is limited because it can only encrypt a
very small amount of data. It is also very slow compared to symmetric
encryption. Therefore, typically, if you want to encrypt data via an RSA
key you generate a random symmetric key and encrypt that using your RSA
key. Then you encrypt the data using the randomly generated symmetric key.

OpenSSL has a built in high level API for doing this combined operation.
To encrypt you can use the EVP_Seal*() functions. To decrypt use the
EVP_Open*() functions. See:

https://www.openssl.org/docs/man1.1.1/man3/EVP_SealInit.html
https://www.openssl.org/docs/man1.1.1/man3/EVP_OpenInit.html

It is also possible to encrypt directly in RSA using EVP_PKEY_encrypt():

https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_encrypt.html


Matt

Reply | Threaded
Open this post in threaded view
|

Re: Using EVP_PKEY with EVP_EncryptInit_ex

Matt Caswell-2


On 01/04/2020 18:01, Andrew Felsher wrote:
> I'm aware of the symmetric/asymmetric differences. But the EVP_Enrypt...
> API takes the key as a bunch of bytes. It shouldn't care whether it's an
> RSA key or not, correct? (Though perhaps it would truncate to, in my
> case, the first 128 bits since I'm using AES-128-XTS.)

No - you must not do that.

On a side note XTS is a funny mode - it requires a double length key. So
AES-128-XTS requires you to supply a 256 bit key. See the description of
XTS on this page:

https://www.openssl.org/docs/man1.1.1/man3/EVP_aes_128_xts.html


On a 2nd side note - XTS has another quirk that you should be aware of.
It does not support streaming. That is you should only call
EVP_EncryptUpdate() once per EVP_EncryptInit_ex() call. The "IV" in the
EVP_EncryptInit_ex() parameter list is actually the XTS "tweak".

>
> But assuming that I can't somehow use the RSA private key's bits as my
> symmetric key, how should I generate a key without requiring user
> interaction? Simply calling RAND_bytes?

Preferrably symmetric keys are generated via RAND_priv_bytes() - but
RAND_bytes() would also work.

It's not clear from your description though how you intend to use the
RSA key in this case. Perhaps just to encrypt the symmetric key you
generated above?

Matt

>
> -Andrew
>
> On Wed, Apr 1, 2020 at 12:53 PM Matt Caswell <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>
>
>     On 01/04/2020 17:34, Andrew Felsher wrote:
>     > Hi,
>     >
>     > I'm trying to do what I assumed would be a very common and typical use
>     > of OpenSSL. I'm just encrypting and decrypting some data (in code; not
>     > from command line). EVP_EncryptInit_ex (and decrypt, update, and final
>     > variants) are the standard way to do this.
>     >
>     > However, the init functions take a char buffer. All the examples I can
>     > find use hard-coded char buffer keys. But obviously I'm not going
>     to be
>     > hard-coding my keys. I'm generating them through a couple different
>     > means, but ultimately I have EVP_PKEYs (in my case, containing RSA
>     > private keys). And there doesn't seem to be a straightforward way
>     to go
>     > from EVP_PKEYs to a form consumable by the EVP init functions.
>     >
>     > EVP_PKEY_get_raw_private_key looks like it would be perfect, but
>     it was
>     > introduced in 1.1.1 and I'm limited to 1.1.0.
>     >
>     > This seems like it would be a very common use case, yet I can't
>     seem to
>     > find any examples or documentation anywhere.
>     >
>     > Am I doing something wrong or making some really off-base assumptions?
>
>     EVP_EncryptInit_ex does *symmetric* encryption, i.e. both sides of the
>     communication share the same private key. An RSA key in an EVP_PKEY does
>     *asymmetric* encryption. Typically anyone can encrypt using the public
>     RSA key, but only the owner of the private RSA key can decrypt.
>
>     Asymmetric encryption using RSA is limited because it can only encrypt a
>     very small amount of data. It is also very slow compared to symmetric
>     encryption. Therefore, typically, if you want to encrypt data via an RSA
>     key you generate a random symmetric key and encrypt that using your RSA
>     key. Then you encrypt the data using the randomly generated
>     symmetric key.
>
>     OpenSSL has a built in high level API for doing this combined operation.
>     To encrypt you can use the EVP_Seal*() functions. To decrypt use the
>     EVP_Open*() functions. See:
>
>     https://www.openssl.org/docs/man1.1.1/man3/EVP_SealInit.html
>     https://www.openssl.org/docs/man1.1.1/man3/EVP_OpenInit.html
>
>     It is also possible to encrypt directly in RSA using EVP_PKEY_encrypt():
>
>     https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_encrypt.html
>
>
>     Matt
>