views:

159

answers:

3

When I decrypt something encrypted with this function, the decrypted version doesn't equal the original.

 class AES256encryption {

    var $secret = '';
    var $cipher_key = '';

    function AES256encryption($secret='') {
        if (empty($secret)) {
            global $secret;         
            if (empty($secret)) {
                $secret = "some random secret string";
            }
        }
        $this->secret = $secret;
    }

    function gen_cipher() {
        if (empty($this->cipher_key)) {
            $this->cipher_key = substr(sha1($this->secret),0,20);
        }
    }
    function mciv() {
        return mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
    }
    function encrypt($text) {
        $this->gen_cipher();
        return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, $text, MCRYPT_MODE_CBC, $this->mciv()))); 
    }
    function decrypt($text) {
        $this->gen_cipher();
        return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, base64_decode($text), MCRYPT_MODE_CBC, $this->mciv())); 
    }
}
+3  A: 

Hi,

Don't create a new IV each time you want to encrypt/decrypt something. You need the same IV at encryption and decryption times. In CBC mode, there is no need to get IV secret as long as it is random at its creation. So your code should be something like:

class AES256encryption {

    var $secret = '';
    var $cipher_key = '';
    var $mciv = NULL;

    function AES256encryption($secret='') {
        if (empty($secret)) {
            global $secret;⋅⋅⋅⋅⋅⋅⋅⋅⋅
            if (empty($secret)) {
                $secret = "some random secret string";
            }
        }
        $this->secret = $secret;
        $this->gen_mciv();
    }   

    function gen_cipher() {
        if (empty($this->cipher_key)) {
            $this->cipher_key = substr(sha1($this->secret),0,20);
        }   
    }   

    function gen_mciv() {
        if(NULL === $this->mciv)
        {
            $this->mciv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
        }   
    }   

    function encrypt($text) {
        $this->gen_cipher();
        return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, $text, MCRYPT_MODE_CBC, $this->mciv)));
    }   
    function decrypt($text) {
        $this->gen_cipher();
        return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, base64_decode($text), MCRYPT_MODE_CBC, $this->mciv));
    }   
}   



$ac = new AES256encryption('my secret pass');
$z = $ac->encrypt('test');
var_dump($z);
$u = $ac->decrypt($z);
var_dump($u);

And that seems to work:

mycroft:~ $ php test_aes.php 
string(44) "+KRlfrPp37FfwB4gJXQ67X+8bjbjxEFHjOn55YOgU5o="
string(4) "test"

Please check block cipher modes of operation which resumes how this work.

Patrick MARIE
Thanks, Patrick, for the help!
tru10000
+1  A: 

The IV needs to be sent to the recipient, along with the encrypted data. This means your encrypt function will need to base64 encode it and send it, and your decrypt function will need to expect to receive it as part of the input.

caf
Thanks, caf, this was helpful!
tru10000
A: 

Based on help from Patrick and caf, I've revised my class. I discovered that both the secret and IV must be the same in decryption as was used in encryption otherwise the decryption won't work. IV must be 32 characters. Here is my revised class in case it is of use to anyone.

class AES256 {

    var $secret = 'some string of any length'; // some random string of any length
    var $iv = '0v6bJhPYe2TElCUrT{TD-drLH(5y4pQj'; // must be 32 chars
    var $cipher_key = '';

    function AES256($secret='', $iv='') {
        if (!empty($secret)) {
            $this->secret = $secret;
        }
        $this->cipher_key = substr(sha1($this->secret),0,20);
        if (!empty($iv) && (strlen($iv) == 32)) {
            $this->iv = $iv;
        }
     }
    function encrypt($plaintext) {
         return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, $plaintext, MCRYPT_MODE_CBC, $this->iv))); 
    }
    function decrypt($ciphertext) {
         return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->cipher_key, base64_decode($ciphertext), MCRYPT_MODE_CBC, $this->iv)); 
    }
}

$r = array();

$ac = new AES256('some string of any length');
$r['ciphertext'] = $ac->encrypt(',23ln1gQ6-3ZY[JI');
$r['plaintext'] = $ac->decrypt("wdkUJRR1qxXLkeseVfiLhKnXsAiVzx4H2ytj+2BFRlo=");
print_r($r);
tru10000
You shouldn't be using a fixed IV - you should be using a freshly generated IV for each message, and simply including it alongside the encrypted data.
caf
oh, okay good to know. Thanks for the help!
tru10000