Search code examples
phpcodeigniterencryptioncryptojs

AES encryption with CryptoJS and decryption with CodeIgniter


I'm trying to encrypt a username sent via POST request to my server (written in Codeigniter 3), so I'm encrypting on the client side with CryptoJS like so:

var user = $('.user').val();
var key = "<? echo($key);?>"; //$key is created on the server side
var encUser = CryptoJS.AES.encrypt(user, key, {
    mode: CryptoJS.mode.CBC
}).toString();

I get a fine looking 64 characters long string, which I send to my server.

On my server (running CodeIgniter 3) I am using the CI encryption library and I'm loading it as required, but when I try to decrypt the string like so:

$this->encryption->decrypt($this->input->post('encUser'), array(
    'cipher' => 'aes-128',
    'mode' => 'cbc',
    'hmac' => FALSE,
    'key' => $key
));

the function returns (bool)false, meaning something went wrong.

What am I doing wrong?

Note: not sure how much I need to encrypt with iv because the CI library just uses the first 16 chars from the string itself.

** EDIT **

I'm creating my $kay (passphrase) with the help of the random_int polyfill and this is my function:

private function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}

Which i am calling random_str(32);

Example generated key: 1xB8oBQgXGPhcKoD0QkP1Uj4CRZ7Sy1c

** UPDATE ** thanks to Artjom.B's answer(and chat :) ) we got it working, using his answer's client side code and fixing the server side code to be:

$user = $this->encryption->decrypt(base64_decode($this->input->post('encUser')), array(
        'cipher' => 'aes-256',
        'mode' => 'cbc',
        'hmac' => FALSE,
        'key' => $key
    ));

and now everything is working.


Solution

  • In CryptoJS, if key is a string, then it will assume that key is actually a password, generate a random salt and derive the actual key and IV from password+salt (this is done in an OpenSSL-compatible way through EVP_BytesToKey).

    CodeIgniter's Encryption library doesn't support this type of key derivation. You will either have to change your CryptoJS code to pass in a parsed WordArray:

    var key = CryptoJS.enc.Hex.parse("<? echo(bin2hex($key));?>");
    var iv = CryptoJS.lib.WordArray.random(128/8);
    var encUser = CryptoJS.AES.encrypt(user, key, {
        iv: iv
    }).ciphertext;
    return iv.concat(encUser).toString(CryptoJS.enc.Base64);
    

    Since the IV is written in front of the ciphertext, CodeIgniter should read it correctly and it doesn't have to be specified explicitly. Make sure that key is correctly encoded as Hex or Base64, because binary encoding doesn't work in JavaScript correctly. Also, at the PHP side, the ciphertext must be decoded from Base64.

    You could also implement EVP_BytesToKey in PHP as I've shown here.