8

I'm using the openssl_encrypt / decrypt method in my website but i'm having some troubles with the $tag option

openssl_encrypt ( $data, $method, $key, $options, $iv, $tag )
openssl_decrypt ( $data, $method, $key, $options, $iv, $tag )

from http://php.net/manual/en/function.openssl-encrypt.php, the definition of tag is: The authentication tag passed by reference when using AEAD cipher mode (GCM or CCM). But i didn't understand it.

I tried it in my codes

$data = "text to be encrypted";
$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);

if (in_array($cipher, openssl_get_cipher_methods())){       
    $encryptedData = openssl_encrypt($data,$cipher,$key,$option,$iv,$tag);
    echo $encryptedData;

    $decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
    echo $decryptedData;
}

i got this result:

encrypted text: Vlx/yKkPhg0DpD0YKvnFKRiCh/I=
decrypted text: text to be encrypted

which is correct. but if i directly decrypt the encrypted text this way:

$data = "text to be encrypted";
$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);

if (in_array($cipher, openssl_get_cipher_methods())){
    $encryptedData = "Vlx/yKkPhg0DpD0YKvnFKRiCh/I=";

    $decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
    echo $decryptedData;
}

i'm getting:

Notice: Undefined variable: tag

if someone could explain to me why this is happening and what should be the value of $tags. thanks

Joey Azar
  • 132
  • 1
  • 13

1 Answers1

7

The tag that PHP is complaining about is an essential aspect of AES when using GCM mode of operation. In this mode, not only does the AES block cipher get applied, but an authentication tag gets calculated as well. It is an array of bytes that represents a MAC (Message Authentication Code) that can be used to verify the integrity of the data and wen decrypting. That same tag needs to be provided to do that verification. See the Wikipedia page about Galois/Counter Mode for more details.

So in order to successfully decrypt that ciphertext, you need to capture the $tag variable resulting from the openssl_encrypt() invocation and feed it into the openssl_decrypt() invocation. You did not do that, hence the complaint about the missing tag. Note that the tag (typically) contains non-readable characters so it is more convenient to store it in a base64 encoded format.

In addition to the $tag variable, you should also provide the same value for the $iv variable to the openssl_decrypt() method as you used in the openssl_encrypt() invocation. Again, base64 encoding makes that easier.

A quick test below demonstrates all this, where I first modified your script to print more stuff and then used the provided script to decrypt:

$ php test1.php 
iv base64-ed: vBKbi8c6vCyvWonV
plaintext: text to be encrypted
ciphertext base64-ed: z28spOd3UEDmj+3a8n/WK11ls7w=
GCM tag base64-ed: OIAggQCGUbPgmPN6lFjQ8g==
$ php test2.php 
decrypted ciphertext: text to be encrypted

where the code for test2.php is the following:

$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$iv = base64_decode("vBKbi8c6vCyvWonV");

if (in_array($cipher, openssl_get_cipher_methods())){       

    $encryptedData = "z28spOd3UEDmj+3a8n/WK11ls7w=";
    $tag = base64_decode("OIAggQCGUbPgmPN6lFjQ8g==");

    $decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
    echo("decrypted ciphertext: ".$decryptedData."\n");
}
Reinier Torenbeek
  • 16,669
  • 7
  • 46
  • 69
  • thank you, but if i understand correctly, every time i need to decrypt using aes-128-gcm, i will have to capture the $tag first? – Joey Azar Aug 24 '18 at 07:05
  • Using the `$tag` provides you the authentication. If you do not need that then it is possible to decrypt without it, using the "plain" `aes-128-ctr` mode, by slightly adjusting the `$iv`. See for example [AES GCM decryption bypassing authentication in JAVA](https://stackoverflow.com/questions/49228671/aes-gcm-decryption-bypassing-authentication-in-java). You will always need to capture the `$iv` though. – Reinier Torenbeek Aug 24 '18 at 07:19
  • yes i kinda figure it out yesterday and i used the "aes-256-cbc", it worked perfectly without the $tag. Anw big thanks – Joey Azar Aug 24 '18 at 07:27
  • Note that the tag is a MAC, but not HMAC (as mentioned in the answer). – MartinSuecia Aug 20 '21 at 10:10
  • 1
    @MartinSuecia thanks for pointing that out, I corrected it. – Reinier Torenbeek Aug 20 '21 at 12:55