[RFC] OpenSSL AEAD support

php.internals

Jakub Zelenka

10 years ago
Hi, I would like to propose an addition to the openssl ext - extending openssl_encrypt and openssl_decrypt to support AEAD (Authenticated Encryption with Additional Data - GCM and CCM modes support). There was some discussion in past and people have been asking about that for some time so I finally finished the implementation (it's more or less rewrite of both functions) and created this RFC to discuss all concerns if there are any... https://wiki.php.net/rfc/openssl_aead Cheers Jakub

Bishop Bettini

10 years ago
Hi Jakub, On Wed, Jan 6, 2016 at 10:01 AM, Jakub Zelenka <bukka@php.net> wrote:
> Hi, > > I would like to propose an addition to the openssl ext - extending > openssl_encrypt and openssl_decrypt to support AEAD (Authenticated > Encryption with Additional Data - GCM and CCM modes support). There was > some discussion in past and people have been asking about that for some > time so I finally finished the implementation (it's more or less rewrite of > both functions) and created this RFC to discuss all concerns if there are > any... > > https://wiki.php.net/rfc/openssl_aead
I think the API might need to be more generic so that any future cipher modes with different parameters could also be passed in. The reference model I'd suggest is the "context" parameter passed to stream related-functions. Userland creates a context, then passes the context to the encrypt/decrypt functions. The context is specific to the wrapper and drives specific behavior. Encrypt can add to the context any specific cipher state that needs to be passed along to decrypt. Using this model, the openssl API might look like: $context = openssl_context_create([ 'aead' => [ 'aad' => '...', 'tag_length' => '...' ]]); $ciphertext = openssl_encrypt( $data, $method, $password, $options, $iv, $context // here is the new parameter, encapsulating all cipher specifics ); echo $context['aead']['tag']; // populated by openssl_encrypt $plaintext = openssl_decrypt( $ciphertext, $method, $password, $options, $iv, $context // fully-reversible, because all necessary data are in context ); Might also want to check in with Scott Arciszewski (copied), as he's working on a new crypto API <https://github.com/paragonie/pco_prototype> proposal. Cheers, bishop

Jakub Zelenka

10 years ago
Hi, On Wed, Jan 6, 2016 at 3:35 PM, Bishop Bettini <bishop@php.net> wrote:
> Hi Jakub, > > On Wed, Jan 6, 2016 at 10:01 AM, Jakub Zelenka <bukka@php.net> wrote: >> >> https://wiki.php.net/rfc/openssl_aead > > > I think the API might need to be more generic so that any future cipher > modes with different parameters could also be passed in. > > The reference model I'd suggest is the "context" parameter passed to > stream related-functions. Userland creates a context, then passes the > context to the encrypt/decrypt functions. The context is specific to the > wrapper and drives specific behavior. Encrypt can add to the context any > specific cipher state that needs to be passed along to decrypt. > > Using this model, the openssl API might look like: > > $context = openssl_context_create([ 'aead' => [ 'aad' => '...', > 'tag_length' => '...' ]]); > $ciphertext = openssl_encrypt( > $data, $method, $password, $options, $iv, > $context // here is the new parameter, encapsulating all cipher > specifics > ); > > echo $context['aead']['tag']; // populated by openssl_encrypt > > $plaintext = openssl_decrypt( > $ciphertext, $method, $password, $options, $iv, > $context // fully-reversible, because all necessary data are in context > ); > >
Please see note in https://wiki.php.net/rfc/openssl_aead#rejected_features . Any context related features will add a lot to the size of the implementation. In this case it would also mean introducing an object with dimension handler to the openssl ext which doesn't really match with the rest of the extension API. The proposed API is more conformant to the rest and the code addition is also limited which is very important from the maintenance point of view. I have got already an extension where you can do all of this context related stuff ( see https://github.com/bukka/php-crypto ) but I don't think that anything like this should be part of the openssl ext. I think we should concentrate on adding just the most important features with minimal code addition to openssl ext and also concentrate on the fixing the actual bugs. Bare in mind that all of this has to be maintained for very long time and when you look to the regular contributors to openssl ext, you won't see too many people... To sum it up this is a minimal proposal to add AEAD support to openssl ext. Anything context related is out of scope of this RFC. Cheers Jakub

Albert Casademont Filella

10 years ago
+1 thanks Jakub! On Wed, Jan 6, 2016 at 6:09 PM, Jakub Zelenka <bukka@php.net> wrote:

Bishop Bettini

10 years ago
On Wed, Jan 6, 2016 at 11:09 AM, Jakub Zelenka <bukka@php.net> wrote:
> Hi, > > On Wed, Jan 6, 2016 at 3:35 PM, Bishop Bettini <bishop@php.net> wrote: > >> >> I think the API might need to be more generic so that any future cipher >> modes with different parameters could also be passed in. >> >> Please see note in > https://wiki.php.net/rfc/openssl_aead#rejected_features . Any context > related features will add a lot to the size of the implementation. In this > case it would also mean introducing an object with dimension handler to the > openssl ext which doesn't really match with the rest of the extension API. > The proposed API is more conformant to the rest and the code addition is > also limited which is very important from the maintenance point of view. >
Ok, a context resource may not be pragmatic. Perhaps a compromise in the form of a thin wrapper: string openssl_encrypt_aead(string $data , string $method , string $password [, int $options = 0 [, string $iv = "" [, string &$tag = "" [, string $aad = "" [, int $tag_length = 16 ]]]]) string openssl_decrypt_aead(string $data , string $method , string $password [, int $options = 0 [, string $iv = "" [, string $tag = "" [, string $aad = "" ]]]] ) This actually feels more right anyway: openssl_encrypt only does encryption, whereas openssl_encrypt_aead does encryption *and* integrity. I would hate for users to pass a method of aes128 and think they can forgo an HMAC because they thought PHP would give them back a valid tag.

Jakub Zelenka

10 years ago
On Wed, Jan 6, 2016 at 7:28 PM, Bishop Bettini <bishop@php.net> wrote:
> On Wed, Jan 6, 2016 at 11:09 AM, Jakub Zelenka <bukka@php.net> wrote: > >> Hi, >> >> On Wed, Jan 6, 2016 at 3:35 PM, Bishop Bettini <bishop@php.net> wrote: >> >>> >>> I think the API might need to be more generic so that any future cipher >>> modes with different parameters could also be passed in. >>> >>> Please see note in >> https://wiki.php.net/rfc/openssl_aead#rejected_features . Any context >> related features will add a lot to the size of the implementation. In this >> case it would also mean introducing an object with dimension handler to the >> openssl ext which doesn't really match with the rest of the extension API. >> The proposed API is more conformant to the rest and the code addition is >> also limited which is very important from the maintenance point of view. >> > > Ok, a context resource may not be pragmatic. Perhaps a compromise in the > form of a thin wrapper: > > string openssl_encrypt_aead(string $data , string $method , string > $password [, int $options = 0 [, string $iv = "" [, string &$tag = "" [, > string $aad = "" [, int $tag_length = 16 ]]]]) > > string openssl_decrypt_aead(string $data , string $method , string > $password [, int $options = 0 [, string $iv = "" [, string $tag = "" [, > string $aad = "" ]]]] ) > > This actually feels more right anyway: openssl_encrypt only does > encryption, whereas openssl_encrypt_aead does encryption *and* > integrity. I would hate for users to pass a method of aes128 and think > they can forgo an HMAC because they thought PHP would give them back a > valid tag. >
This is a good point. I would probably go with a bit different and maybe simpler solution. How about emitting notice when $tag param is supplied for non aead mode? Thanks for the feedback! Jakub

Bishop Bettini

10 years ago
On Wed, Jan 6, 2016 at 2:59 PM, Jakub Zelenka <bukka@php.net> wrote:
> On Wed, Jan 6, 2016 at 7:28 PM, Bishop Bettini <bishop@php.net> wrote: > >> On Wed, Jan 6, 2016 at 11:09 AM, Jakub Zelenka <bukka@php.net> wrote: >> >>> Hi, >>> >>> On Wed, Jan 6, 2016 at 3:35 PM, Bishop Bettini <bishop@php.net> wrote: >>> >>>> >>>> I think the API might need to be more generic so that any future cipher >>>> modes with different parameters could also be passed in. >>>> >>>> Please see note in >>> https://wiki.php.net/rfc/openssl_aead#rejected_features . Any context >>> related features will add a lot to the size of the implementation. In this >>> case it would also mean introducing an object with dimension handler to the >>> openssl ext which doesn't really match with the rest of the extension API. >>> The proposed API is more conformant to the rest and the code addition is >>> also limited which is very important from the maintenance point of view. >>> >> >> Ok, a context resource may not be pragmatic. Perhaps a compromise in the >> form of a thin wrapper: >> >> string openssl_encrypt_aead(string $data , string $method , string >> $password [, int $options = 0 [, string $iv = "" [, string &$tag = "" [, >> string $aad = "" [, int $tag_length = 16 ]]]]) >> >> string openssl_decrypt_aead(string $data , string $method , string >> $password [, int $options = 0 [, string $iv = "" [, string $tag = "" [, >> string $aad = "" ]]]] ) >> >> This actually feels more right anyway: openssl_encrypt only does >> encryption, whereas openssl_encrypt_aead does encryption *and* >> integrity. I would hate for users to pass a method of aes128 and think >> they can forgo an HMAC because they thought PHP would give them back a >> valid tag. >> > > This is a good point. I would probably go with a bit different and maybe > simpler solution. How about emitting notice when $tag param is supplied for > non aead mode? >
I think the need for a message highlights an API design problem, and I'd rather eliminate the need with a purpose-built API. Still, AEAD is a valuable addition to the API. Thanks for submitting the RFC!

Jakub Zelenka

10 years ago
On Wed, Jan 6, 2016 at 9:32 PM, Bishop Bettini <bishop@php.net> wrote:
> On Wed, Jan 6, 2016 at 2:59 PM, Jakub Zelenka <bukka@php.net> wrote: > >> On Wed, Jan 6, 2016 at 7:28 PM, Bishop Bettini <bishop@php.net> wrote: >> >>> On Wed, Jan 6, 2016 at 11:09 AM, Jakub Zelenka <bukka@php.net> wrote: >>> >>>> Hi, >>>> >>>> On Wed, Jan 6, 2016 at 3:35 PM, Bishop Bettini <bishop@php.net> wrote: >>>> >>>>> >>>>> I think the API might need to be more generic so that any future >>>>> cipher modes with different parameters could also be passed in. >>>>> >>>>> Please see note in >>>> https://wiki.php.net/rfc/openssl_aead#rejected_features . Any context >>>> related features will add a lot to the size of the implementation. In this >>>> case it would also mean introducing an object with dimension handler to the >>>> openssl ext which doesn't really match with the rest of the extension API. >>>> The proposed API is more conformant to the rest and the code addition is >>>> also limited which is very important from the maintenance point of view. >>>> >>> >>> Ok, a context resource may not be pragmatic. Perhaps a compromise in the >>> form of a thin wrapper: >>> >>> string openssl_encrypt_aead(string $data , string $method , string >>> $password [, int $options = 0 [, string $iv = "" [, string &$tag = "" [, >>> string $aad = "" [, int $tag_length = 16 ]]]]) >>> >>> string openssl_decrypt_aead(string $data , string $method , string >>> $password [, int $options = 0 [, string $iv = "" [, string $tag = "" [, >>> string $aad = "" ]]]] ) >>> >>> This actually feels more right anyway: openssl_encrypt only does >>> encryption, whereas openssl_encrypt_aead does encryption *and* >>> integrity. I would hate for users to pass a method of aes128 and think >>> they can forgo an HMAC because they thought PHP would give them back a >>> valid tag. >>> >> >> This is a good point. I would probably go with a bit different and maybe >> simpler solution. How about emitting notice when $tag param is supplied for >> non aead mode? >> > > I think the need for a message highlights an API design problem, and I'd > rather eliminate the need with a purpose-built API. > >
I have been thinking about it and I don't think we need to add special functions that would work just for cipher algs ($method) with AEAD modes. The logic and other parameters are the same. The only difference is supplying the tag. We could compare it to the ciphers modes with IV that requires an $iv parameter. Then a notice is triggered if IV is not supplied as well as a notice is triggered if you supply IV for ECB mode. I know that this is not the same but the notices are already used in this way so I think that this is a more conforming way. This should be of course documented. There should be definitely a note that a tag will be provided only for GCM and CCM modes. It means only for following methods: aes-128-gcm aes-192-gcm aes-256-gcm aes-128-ccm aes-192-ccm aes-256-ccm and their upper case aliases of course... I will update the patch and RFC accordingly. Thanks for the feedback! Jakub