2

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

3
  • 2
    Welcome to Stackoverflow. Your secured_encryption gives an output of 3 elements ($this->iv.$final_encryption.$encrypted_data) but on decrypt_data you don't split the data and feed the complete (Base64-decoded) data to openssl_decrypt and hash_hmac so you HAVE to get an error when decrypting. Commented Sep 17, 2020 at 22:12
  • 1
    Don't invent your own crypto scheme. There are well-established modes for authenticated encryption, such as GCM. Commented Sep 18, 2020 at 8:30
  • 1
    @Peter - I would not say that this is their encryption scheme, see encrypt-then-MAC. But I agree, that nowadays modes like GCM are more convenient (and modern), as long as they are supported in the respective environment. Commented Sep 18, 2020 at 8:45

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I am grateful for your support everyone. But still having some issues @Topaco, after doing the changes you asked me to do.... I am still getting an error:- Error in decrypting data
@Incrediblecoder - I' ve shared the executable code here. Please check if there is a difference to your code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.