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
Hi Jakub,
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...
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
Hi,
Hi Jakub,
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
+1 thanks Jakub!
Hi,
Hi Jakub,
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
Hi,
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.
Hi,
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
Hi,
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!
Hi,
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