Doubt about openssl_encrypt security

Asked

Viewed 126 times

0

Hello, I have some doubts about this method of encrypting data, because I intend to use between version 5.6 and the current version of PHP and I have doubts if it will run smoothly. I have the following Code below, in case someone has any suggestions to improve it, because I intend to use to encode texts and decode them and it will be a lot of words. Thanks in advance!

function encode($data)
{
    $pass = 'my serial key';
    $IV1   = base64_encode(openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC')));
    $IV2   = substr($IV1, 0, openssl_cipher_iv_length('AES-256-CBC'));
    $enc = openssl_encrypt($data, 'AES-256-CBC', $pass, 0, $IV2);
    return trim(base64_encode($enc . '::' . $IV2), '=');
}

function decode($data)
{
    $pass = 'my serial key';
    $IV1   = base64_encode(openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC')));
    list($data, $IV1) = explode('::', base64_decode($data), 2);
    $IV2   = substr($IV1, 0, openssl_cipher_iv_length('AES-256-CBC'));
    $dec = openssl_decrypt($data, 'AES-256-CBC', $pass, 0, $IV2);
    return trim($dec);
}

1 answer

3

In short I will list the "problems" you have in your code:

  • Its maximum entropy decreased from 128 to 96 because of the base64, without any advantage.
  • Your chosen cipher (AES-CBC) does not protect against text edits.
  • Your "key" seems to be a password, not a key.
  • Supporting obsolete versions does not seem to me to be an advantage.

First, I think it’s best to eliminate support for PHP5.6 and PHP 7 for two reasons:

  • PHP 5.6 and PHP 7.0 are no longer supported by PHP itself.
  • PHP 5.6 (up to PHP 5.6.12) has a vulnerability in openssl_random_pseudo_bytes, who wore the RAND_pseudo_bytes Openssl, which is insecure.

Second, you don’t say the goal you want to accomplish, nor the attacks you intend to mitigate, so without a list of attack vectors it is impossible to "improve it". But one thing you can notice is that your code DOES NOT protect against text edits, you can decipher an altered text without any sign that the text has changed or not. Is that a problem for you? We don’t know.


Third, you’re using the base64_encode meaningless and is decreasing the maximum entropy of IV. Note the following lines:

$IV1 = base64_encode(openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC')));
$IV2 = substr($IV1, 0, openssl_cipher_iv_length('AES-256-CBC'));

The AES-256-CBC needs a initialization vector (IV) 16 bytes. $IV1 will have 24 bytes, however each byte will only have 6 useful bits (after all for every 3 bytes is 4 bytes of Base64). Therefore, its maximum entropy dropped from 128 bits to 96 bits, without any advantage or clear reason for such.


Fourth, you seem to use a password. Password are not keys (if you want to use passwords as keys you will have to use some PBKDF, such as Argon2id). If it is not passwords, create a uniformly random key. I don’t know if this was just an example, however the name of $pass raised me such suspicion.


Discarding support for such versions, could use the random_bytes and could use Libsodium (which uses Salsa20 instead of AES, and uses Poly1305 for authentication).

$chave = "\xDE\xAD\xBE\xEF\xFE\xED\xDE\xAD\xBE\xEF\xFE\xED\xDE\xAD\xBE\xEF\xFE\xED\xDE\xAD\xBE\xEF\xFE\xED"
// Sua chave

function encode($data) {
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    return unpack("H*", $nonce)[1] . sodium_crypto_secretbox($data, $nonce, $chave);
}

function decode($data) {
    $nonce = pack("H*", substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES * 2));
    return sodium_crypto_secretbox_open($data, $nonce, $chave);
}

If support for PHP 5.6 is really necessary, not much to do (except fix Base64), but PHP 5.6 does not natively support AES-GCM, as far as I know, it would have to do some "gambiarra" using AES-CBC + HMAC.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.