Reputation: 360
I use the following functions to encrypt/decrypt with NodeJS, they work fine. But I was unable to decrypt the data with PHP to use in some part of the same project.
NodeJS:
function encrypt(text){
var cipher = crypto.createCipher('aes-256-cbc','strong-key')
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
function decrypt(text){
var decipher = crypto.createDecipher('aes-256-cbc','strong-key')
var dec = decipher.update(text,'hex','utf8')
dec += decipher.final('utf8');
return dec;
}
What I tried with PHP is:
openssl_decrypt('fdf32748aa4ce37fc600bbe7be14bfc7', 'AES-256-CBC', "strong-key");
But it keeps returning false/empty. I appreciate healping me to know what I am doing wrong.
Edit:
For example, decrypting 28e1dfdedac467a015a9c8720d0a6451
with PHP should return "Hello World", using the same key as above.
Upvotes: 1
Views: 809
Reputation: 2365
Make sure that your incoming data is the correct format (ie doesn't have any extra layers of encoding). It looks like hex but it's not what openssl_decrypt necessarily expects.
Here's a back and forth PHP example (using an IV which you should too):
$data = 'hello this is some data';
$key = 'this is a cool and secret password';
$iv = random_bytes(16);
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
echo 'iv (as hex): ', bin2hex($iv), PHP_EOL;
echo 'encrypted: ', $encrypted, PHP_EOL; // note this is not hex
$decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL;
$ php test.php
iv (as hex): 02c00788438518f241cb86dc90237102
encrypted: oRZAXMjNle6hkJ9rTHTeUl5VoHQol+020Q/iFnbgbeU=
decrypted: hello this is some data
Edit, even more specific example, highlighting the importance of knowing your encodings:
// test.js
const crypto = require('crypto');
let data = 'hello this is some data';
const key = crypto.scryptSync('Password used to generate key', '', 32); // 256 / 8 = 32
const iv = crypto.randomBytes(16); // Initialization vector.
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let crypted = cipher.update(data,'utf8','hex')
crypted += cipher.final('hex');
console.log('data: ', data);
console.log('key: ', key.toString('hex')); // key: 9266bc531befd01b6a55c232fa0efeb35625079e7024758b2e65d0dd72fe59df
console.log('crypted (as hex): ', crypted); // crypted (as hex): b571d864da0680d77e4880d0071b49e456a1eead4b1cbfa42a9337965a466362
console.log('iv (as hex): ', iv.toString('hex')); // iv (as hex): 788ac1dcee25824b713b5201d07cc133
Here we know all our outputs are hex, so we can re-format them to binary data on the PHP side:
// test.php
$iv = hex2bin( '788ac1dcee25824b713b5201d07cc133' );
$encrypted = hex2bin( 'b571d864da0680d77e4880d0071b49e456a1eead4b1cbfa42a9337965a466362' );
$key = hex2bin('9266bc531befd01b6a55c232fa0efeb35625079e7024758b2e65d0dd72fe59df');
$decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL; // hello this is some data
Final Edit: Now with working key derivation implementation. This successfully decrypts your 'Hello world':
$password = 'strong-key';
// derive key and IV using function from SO, which implements same method node uses
$ar = deriveKeyAndIV($password, 1, 'aes-256-cbc', 'md5');
$key = $ar['key'];
$iv = $ar['iv'];
$decrypted = openssl_decrypt(hex2bin('28e1dfdedac467a015a9c8720d0a6451'), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL; // Hello world
function deriveKeyAndIV($data,$count,$cipher,$digest) {
$ivlen = openssl_cipher_iv_length($cipher);
$keylen = 32;
$hash = "";
$hdata = "";
while(strlen($hash) < $keylen+$ivlen) {
$hdata .= $data;
$md_buf = openssl_digest($hdata, $digest);
//
for ($i = 1; $i < $count; $i++) {
$md_buf = openssl_digest ( hex2bin($md_buf),$digest);
}
$hdata = hex2bin($md_buf);
$hash .= $hdata;
}
//
$key = substr($hash,0,$keylen);
$iv = substr($hash,$keylen,$ivlen);
//
return array('key' => $key, 'iv' => $iv);
}
Upvotes: 2