1

Here, I have c++ program which encodes the string and I have to decrypt in php. I have verified that the key and the iv are same in both programs, still getting false in openssl_decrypt() command.

    int main(int argc, char** args)
    {
        unsigned char *salt = (unsigned char*)"12345678";                        
        unsigned char *data = (unsigned char*)"123456789123450";                 
        unsigned int count        = 5;                                           
        int dlen                  = strlen((char*)data);                         
        unsigned int ksize        = 16;
        unsigned int vsize        = 12;                                          
        unsigned char *key        = new unsigned char[ksize];                    
        unsigned char *iv         = new unsigned char[vsize];                    

        int ret = EVP_BytesToKey( EVP_aes_128_gcm() , EVP_sha1(), salt, data, dlen, count, key, iv);

        const EVP_CIPHER*     m_cipher = EVP_aes_128_gcm();
        EVP_CIPHER_CTX* m_encode;                                                
        EVP_CIPHER_CTX* m_decode;                                                
        if (!(m_encode = EVP_CIPHER_CTX_new()))                                  
           cout << "ERROR :: In encode Initiallization"<< endl; 

        EVP_EncryptInit_ex(m_encode, m_cipher, NULL, key, iv);

        if (!(m_decode = EVP_CIPHER_CTX_new()))
            cout << "ERROR :: In decode Initiallization"<< endl;
        EVP_DecryptInit_ex(m_decode, m_cipher, NULL, key, iv);
        unsigned char* plain = (unsigned char*)"My Name IS  DON !!!";
        int len  = strlen((char*)plain);
        unsigned char* encData = new unsigned char[len];

        int c_len = len;
        int f_len = 0;
        EVP_EncryptInit_ex(m_encode, NULL, NULL, NULL, NULL);
        EVP_EncryptUpdate(m_encode, encData, &c_len, plain, len);
        EVP_EncryptFinal_ex(m_encode, encData + c_len, &f_len);

        len = c_len + f_len;

        cout << string( encData, encData + len)<< endl;
    }

And the following is decryption code in php. "./abc_enc.txt" contains encryption string of c++ code. As I mentioned above I am getting same key and iv for both programs but openssl_decrypt function returns false. Can someone figure out what is the mistake?

    <?
    function EVP_BytesToKey($salt, $password) {
        $ivlen = 12;
        $keylen = 16;
        $iterations = 5;
        $hash = "";
        $hdata = "";
        while(strlen($hash)<$ivlen+$keylen)
        {
            $hdata .= $password.$salt;
            $md_buf = openssl_digest($hdata, 'sha1');
            for ($i = 1; $i < $iterations; $i++) {
                $md_buf = openssl_digest ( hex2bin($md_buf),'sha1');
            }
            $hdata = hex2bin($md_buf);
            $hash.= $hdata;
         }
         return $hash;
    }
    function decrypt($ivHashCiphertext, $password) {
         $method = "aes-128-gcm";
         $salt = "12345678";
         $iterations = 5;
         $ivlen = openssl_cipher_iv_length($method);
         $ciphertext = $ivHashCiphertext;
         $genKeyData = EVP_BytesToKey($salt, $password);
         $keylen = 16;
         $key = substr($genKeyData,0,$keylen);
         $iv  = substr($genKeyData,$keylen,$ivlen);
         //var_dump($key);
         //var_dump($iv);
         $ret = openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
         var_dump($ret);
         return $ret;
    }
    $file = './abc_enc.txt';
    $fileData = (file_get_contents($file));
    $encrypted = $fileData;
    $decrypted = decrypt($encrypted, '123456789123450');
    ?>
Smit Modi
  • 13
  • 3
  • Check https://stackoverflow.com/questions/12644437/php-encrypt-and-windows-decrypt – Michael Chourdakis May 30 '19 at 10:56
  • which version of php your are using ? have to tried with `openssl_pbkdf2` or ref. https://www.php.net/manual/en/function.openssl-pbkdf2.php – SagarPPanchal May 30 '19 at 11:04
  • @SagarPPanchal I am using 7.1.29. openssl_pbkdf2 generated only password but I want to generate password and iv both from secret key. Also after using EVP_BytesToKey both programs give same iv and password so that's might not be an issue! – Smit Modi May 30 '19 at 11:18

2 Answers2

0

In short

I'm neither an openSSL nor a PHP specialist. But at first sight, it appears that you might experience problems because you read and write binary data using files in text mode.

More infos about the potential problem

The encrypted data resulting from your C++ code is binary data. Your code does not show how you write the file. But unless you explicitly request the file to be in binary mode, you will get a file in text mode.

This might cause multiple issues when writing the data, since text mode allows for OS-dependent transformations to happen. Typical examples are characters with value 0x0A (new lines), skipping trailing 0x20 (space character), adding a 0x0A at the end of the file if there isn't and similar undesired transformation.

Your PHP code might open the file in an incompatible default mode, which might add further transformation if it's text mode, or avoid reverting transformations if it's binary.

This means that in the end, the string you try to decode might not be the original encrypted string !

How to solve it ?

First inspect with a binary editor the content of the file to see if it matches the expectations. Or check the expected length of the encrypted source data, the length of the file, and the length of the loaded content. If they all match, my answer is not relevant.

If it is relevant, or if you intend sooner or later to allow cross platform exchanges (e.g. windows client communicating with a linux server), then you could:

  • either add the necessary statements to use binary mode on both sides.
  • or add a Base64 encoding to transform binary into a robust ascii string on the writing side, and retransforming Base64 into binary on the reading side (openssl provides for base64 encoding and PHP has everything needed as well)
Christophe
  • 54,708
  • 5
  • 52
  • 107
0

The GCM-mode provides both, confidentiality and authenticity. To verify authenticity the GCM-mode uses an authentication tag and defines a length between incl. 12 and 16 Byte for the tag. The authentication strength depends on the length of the tag, i.e. the longer the tag, the more secure the proof of authenticity.

However, in the current C++-code the authentication tag is not determined! This means that one of the main functionalities of the GCM-mode, authentication, is not used.

While the decryption in C++ using EVP is independent from the authentication (this means that the decryption is also performed even if the authentication tags differ), the decryption in PHP using openssl_decrypt is only done if the authentication is successful, i.e. in PHP the authentication tag is mandatory for decryption. Therefore, the authentication tag must be determined in the C++-code. For this purpose, the following code must be added after the EVP_EncryptFinal_ex-call:

unsigned int tsize = 16;
unsigned char *tag = new unsigned char[tsize];
EVP_CIPHER_CTX_ctrl(m_encode, EVP_CTRL_GCM_GET_TAG, tsize, tag);

Here a tagsize of 16 Byte is used. In addition, the authentication tag must be used in the PHP-code for decryption. This is done by passing the authentication tag as the 6th parameter of the openssl_decrypt-method:

$ret = openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);

Decryption can only be performed if the tag used for decryption matches the tag used for encryption.

For the data in the posted example the C++-code generates the following authentication tag (as hexadecimal string):

f7c18e8b99587f3063383d68230c0e35

Finally, a more detailed explanation for AES-GCM with OpenSSL can be found here for encryption and decryption (including the consideration of the authentication tag).

Topaco
  • 18,591
  • 2
  • 12
  • 39
  • thank you very much. After using same tag in both programs, I am able to decrypt file in php which was encrypted using c++. – Smit Modi Jun 03 '19 at 12:15
  • I have one more doubt, In c++ we can do decryption in GCM mode without tag. But using OpenSSL in PHP we have to provide tag for decryption. Is there any other way in PHP to do decryption without tag in GCM mode? – Smit Modi Jun 03 '19 at 13:04
  • To the best of my knowledge, no. In the documentation of [`openssl_decrypt`](https://www.php.net/manual/en/function.openssl-decrypt.php) the parameter `tag` is described as follows: _tag: The authentication tag in AEAD cipher mode. If it is incorrect, the authentication fails and the function returns FALSE._ – Topaco Jun 03 '19 at 15:43