I am trying to implement AES 256 bit encryption with string on php and JavaScript. For jasvascript I a musing CryptoJS and php I use openssl_decrypt/enecrypt.
Below is the code in JS for encryption and decryption.
JavaScript
function aes_encrypt(str_to_encrypt){
if(str_to_encrypt==null)
return "";
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
var encrypted = CryptoJS.AES.encrypt(str_to_encrypt,key, {'mode': CryptoJS.mode.CBC, iv: iv});
var encryptedString = encrypted.toString();
return encryptedString;
}
function aes_decrypt(str_to_decrypt){
if(str_to_decrypt==null)
return "";
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
var decrypted = CryptoJS.AES.decrypt(str_to_decrypt,key, {'mode': CryptoJS.mode.CBC, iv: iv });
var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedString;
}
And in php the code is
PHP
class Crypto_AES256
{
public $key = "0123456789abcdef0123456789abcdef";
public $iv = "abcdef9876543210abcdef9876543210";
public $encrypt_method = 'AES-256-CBC';
function __construct ()
{
$this->key = hex2bin($this->key);
$this->iv = hex2bin($this->iv);
}
public function encrypt ( $string )
{
if ( $encrypted = base64_encode( openssl_encrypt ( $string, $this->encrypt_method, $this->key, 0, $this->iv ) ) )
{
return $encrypted;
}
else
{
return false;
}
}
public function decrypt ($string)
{
if ( $decrypted = openssl_decrypt ( base64_decode ( $string ), $this->encrypt_method, $this->key, 0, $this->iv ) )
{
return $decrypted;
}
else
{
return false;
}
}
}
But the result of encryption at JavaScript side is not same as php, I need to produce same encrypted and encrypted result at both JavaScript and php. What could be the problem.
Both codes differ in two ways:
openssl_encrypt()
returns the ciphertext Base64 encoded by default, so the ciphertext is currently Base64 encoded twice. Therefore remove the explicit base64_encode()
or use OPENSSL_RAW_DATA
as the 4th parameter so that the raw data is returned. Similarly for openssl_decrypt()
.When these issues are fixed, both codes provide the same ciphertext on my machine. Note that a static IV is insecure (see also the comment), but you probably only do this for testing purposes.
Example: The following code uses your unmodified CryptoJS code, i.e. AES-128:
function aes_encrypt(str_to_encrypt){
if(str_to_encrypt==null)
return "";
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
var encrypted = CryptoJS.AES.encrypt(str_to_encrypt,key, {'mode': CryptoJS.mode.CBC, iv: iv});
var encryptedString = encrypted.toString();
return encryptedString;
}
function aes_decrypt(str_to_decrypt){
if(str_to_decrypt==null)
return "";
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
var decrypted = CryptoJS.AES.decrypt(str_to_decrypt,key, {'mode': CryptoJS.mode.CBC, iv: iv });
var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedString;
}
var ciphertext = aes_encrypt('The quick brown fox jumps over the lazy dog');
var decrypted = aes_decrypt(ciphertext);
console.log(ciphertext.replace(/(.{56})/g,'$1\n'));
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
The PHP code returns the same ciphertext if AES-128-CBC is applied and if the OPENSSL_RAW_DATA
flag is set as the 4th parameter in openssl_encrypt()
and openssl_decrypt()
.