How to decrypt an encrypted string using openssl_decrypt

Viewed 219

I am trying to develop a php program that encrypts some data which can later be decrypted. However, I am having trouble decrypting the data with PHP using AES-256-CBC algorithm by using the openssl_decrypt() method in PHP. The encryption works but when I try to decrypt it gives me an error:-
hash_equals(): Expected known_string to be a string, bool given on line 44.

My code below:

<?php

class Encryption{
    
    protected $data, $encryption_type, $key, $iv;

    public function __construct(){
        $mydata = "Is this safe";
        $encryption = $this->secured_encryption($mydata);

        // Decrypting data
        $data_to_decrypt = $encryption;
        $this->decrypt_data($data_to_decrypt);
    }

    public function secured_encryption($data){
        $this->data = $data;
        $this->encryption_type = "AES-256-CBC"; // cipher algorithm
        $this->key = ['6d2d823df2e08c0d3cdf70f148998d49', 'fdb3a18c7b0a322fdb3a18c7b0a320d3'];
        $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->encryption_type));
        $encrypted_data = openssl_encrypt($this->data, $this->encryption_type, $this->key[0], OPENSSL_RAW_DATA, $this->iv);
        $final_encryption = hash_hmac('SHA3-512', $encrypted_data, $this->key[1], true);
        $output = base64_encode($this->iv.$final_encryption.$encrypted_data);

        if($output):
            print("Encrypted data: {$output}<br/>");
        else:
            print("Error in encrypting data");
        endif;
    }

    public function decrypt_data($data){
        $this->data = base64_decode($data);
        $this->encryption_type = "AES-256-CBC"; // cipher algorithm
        $this->key = ['6d2d823df2e08c0d3cdf70f148998d49', 'fdb3a18c7b0a322fdb3a18c7b0a320d3'];
        $ivlen = openssl_cipher_iv_length($this->encryption_type);
        $this->iv = substr($this->data, 0, $ivlen);
        $hmac = substr($this->data, $ivlen, $sha2len = 32);
        $decrypt_data = substr($this->data, $ivlen, $sha2len);
        $final_decryption = openssl_decrypt($decrypt_data, $this->encryption_type, $this->key[0], OPENSSL_RAW_DATA, $this->iv);
        $calcmac = hash_hmac('SHA3-512', $decrypt_data, $this->key[1], true);

        if(hash_equals($hmac, $calcmac)):
            print($final_decryption);
        else:
            print("Error in decrypting data");
        endif;
    }
}

$encryption = Encryption();

?> 

Anybody to help me

1 Answers

There are a few minor issues in the code:

  • There is a return statement missing in the secured_encryption method. This is the trigger for the error message (hash_equals(): Expected known_string to be a string, bool given), since $hmac does not contain a string but is false. So at the end of secured_encryption you have to add:

    return $output;
    

    With this, encryption works, but decryption does not work yet.

  • When separating the HMac in decrypt_data the wrong length is used. SHA3-512 results in a 512 bit, i.e. 64 byte hash, i.e.:

    $hmac = substr($this->data, $ivlen, $sha2len = 32);
    

    must be replaced by:

    $hmac = substr($this->data, $ivlen, $sha2len = 64);   
    
  • When separating the data, start at the position $ivlen + $sha2len and consider everything to the end, i.e.:

    $decrypt_data = substr($this->data, $ivlen, $sha2len); 
    

    must be replaced by:

    $decrypt_data = substr($this->data, $ivlen + $sha2len);
    

With these changes everything works and an output looks e.g. like this:

Encrypted data: uTjcPmLK8jTktJ0oy5AqB40d5YFuAbgXMHfNEM6+JOH+DtyYAhckcv3mkLhdOvUqPlriKqYjHO6cpJI3ZdoTSS4lqDr0eH0MMiUpJMSXcan81irvobcdIV+rvaMPPRj7
Is this safe 

By the way, besides the ciphertext also the IV should be authenticated, see here. There are also authenticatable operation modes that provide confidentiality as well as authentication, e.g. GCM (e.g. aes-256-gcm), s. Peter's comment. You can check with openssl_get_cipher_methods() which algorithms/modes are available in your environment.

Related