I am trying to convert below encryption function created in PHP using CryptoJS but it is not returning same encrypted text. Can anyone help me doing this?
PHP function:
function encrypt($data, $key)
{
$algo = 'AES-128-CBC';
$iv = substr($key, 0, 16);
$cipherText = openssl_encrypt(
$data,
$algo,
$key,
OPENSSL_RAW_DATA,
$iv
);
$cipherText = base64_encode($cipherText);
return $cipherText;
}
CryptoJS Function
var key = "abcdefghijklmnopqrstuvwx123456";
var IV = key.substr(0, 16);
var encrypted = CryptoJS.AES.encrypt("ABC", key, { mode: CryptoJS.mode.CBC, iv: IV });
Related
I succeeded in encrypting the plaintext using PHP openssl, but with openssl_decrypt, I get this error.
�RC(�ɸ�gQ���삭
What is the reason for alien language to float? I think this is the problem:
openssl_random_pseudo_bytes (16).
openssl_random_pseudo_bytes(opensl_cipher_iv_length ("AES-128-CBC")); is the same situation.
function aes_encode($text, $s_key){
$iv = openssl_random_pseudo_bytes(16);
return base64_encode(openssl_encrypt($text, "AES-128-CBC", $s_key, 0, $iv));
}
$encrypt_text = aes_encode($plaintext, $s_key);
echo $encrypt_text;
function aes_decode($encrypt_text, $s_key){
$iv = openssl_random_pseudo_bytes(16);
return openssl_decrypt(base64_decode($encrypt_text), "AES-128-CBC", $s_key, 0, $iv);
}
$decrypt_text = aes_decode($encrypt_text, $s_key);
echo $decrypt_text;
<result>
QUxwTUxiSTkwWFc2WE0zcmtSOXNHR0cyKzU1RWIvNkxnaGJTZmdnVlB4VT0=
�RC(�ɸ�gQ���삭
You need to use the same IV you encrypted with when decrypting:
function aes_encode($text, $s_key, $iv){
return base64_encode(openssl_encrypt($text, "AES-128-CBC", $s_key, 0, $iv));
}
function aes_decode($encrypt_text, $s_key, $iv){
return openssl_decrypt(base64_decode($encrypt_text), "AES-128-CBC", $s_key, 0, $iv);
}
$plaintext = 'testtest';
$s_key = 'secret';
$iv = openssl_random_pseudo_bytes(16);
$encrypt_text = aes_encode($plaintext, $s_key, $iv);
echo $encrypt_text;
echo "\n";
$decrypt_text = aes_decode($encrypt_text, $s_key, $iv);
echo $decrypt_text;
Output
SVg2Y0FtV1h6RFZac2t5UjhxNDhpdz09
testtest
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.
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';
// derrive 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);
}
I have been trying to find out how to make this:
function encrypt_decrypt($action, $string) {
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = 'HqFdkh2FX126fH1r';
$secret_iv = 'iS2dk82dXd26f61K';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if( $action == 'decrypt' ) {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
In Node.js
The reason is that the encryption will be handled by PHP and the decryption by Node.
EDIT:
I managed to get this far:
var crypto = require('crypto')
, key = 'cI8Jd96NDoasd09jcI8Jd96NDoasd09j'
, iv = 'cI8Jd96NDoasd09j'
, plaintext = '2';
hashedKey = crypto.createHash('sha256').update(key, 'utf-8').digest('hex');
console.log('hashed key=', hashedKey);
// corresponds to the hashed key in PHP
hashedIv = crypto.createHash('sha256').update(iv, 'utf-8').digest('hex').substring(0,16);
console.log('hashed iv=', hashedIv);
// corresponds to the hashed iv in PHP
var buf = Buffer.from(teamId, 'base64');
console.log("buffer: " + buf);
and the variable buf actually is the same as base64_decode($string in the PHP code.
However, when I do this:
var decipher = crypto.createDecipheriv("aes-256-cbc",key, iv);
var decrypted = decipher.update(buf, 'base64', 'utf8');
console.log("decrypted.toString(): " + decrypted.toString());
I'm getting Z���ߋd�M:�� in the console rather than the desired 2.
The main problem was an embarrasing one. We are mainly two devs on this project and I thought the php-file I was editing for the encryption and decryption was the only thing I had to care about.
It was later realized that the actual call for the encoding was made from another php-file. Thus, what I changed in the encoding in the file I was working on was all in vain.
The end result looks like this, for anyone who's interested:
function encrypt_decrypt($action, $string) {
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = '32 byte key';
$secret_iv = '16 byte iv';
// hash
$key = substr(hash('sha256', $secret_key), 0, 32);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
//$output = base64_encode($output);
} else if( $action == 'decrypt' ) { // this below is now handled in Node
$output = openssl_decrypt($string, $encrypt_method, $key, 0, $iv);
//$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
And Node:
function getDecryptedTeamId(encryptedId) {
var hashedKey;
var hashedIv;
var crypto = require('crypto')
, key = 'same 32 byte key as above in php'
, iv = 'same 16 byte ivas above in php'
, plaintext = '2';
hashedKey = crypto.createHash('sha256').update(key, 'utf-8').digest('hex').substring(0,32);
key = hashedKey;
hashedIv = crypto.createHash('sha256').update(iv, 'utf-8').digest('hex').substring(0,16);
iv = hashedIv;
var buf = Buffer.from(encryptedId, 'base64');
var crypt = buf.toString('base64');
var decryptor = crypto.createDecipheriv("aes-256-cbc", hashedKey, hashedIv);
var teamIdDec = decryptor.update(buf);
teamIdDec += decryptor.final();
return teamIdDec;
}
I have old PHP project where used mcrypt_encrypt
But this function doesn't work in new PHP.
I try to convert it to php7+, use openssl_encrypt, but I got no same result, what I do wrong?
Maybe do you know other way to get same result?
mcrypt_encrypt function:
public static function cryptToCode($data)
{
$iv_size = #mcrypt_get_iv_size(MCRYPT_CAST_128, MCRYPT_MODE_ECB);
$iv = #mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM );
$code = #mcrypt_encrypt(MCRYPT_CAST_128, self::KEY_TRANSLATE_ID, $data, MCRYPT_MODE_ECB, $iv);
$code = bin2hex($code);
return $code;
}
openssl_encrypt function:
public static function cryptToCodeSSL($data, $key = self::KEY_TRANSLATE_ID, $method = "cast-128-ecb") //"cast-128-ecb"
{
$iv_size = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_size);
$code = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$code = bin2hex($code);
return $code;
}
Done:
I found library http://www.gilfether.com/phpcrypt/
I got same result.
Here are my encrypt and decrypt functions
public function encrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
$result = base64_encode(mcrypt_encrypt(MCRYPT_TWOFISH, $key, $text, MCRYPT_MODE_CBC, $iv));
return $result;
}
public function decrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
$result = trim(mcrypt_decrypt(MCRYPT_TWOFISH, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
return $result;
}
When encryption is run on a JSON string to be stored as a text file and then retrieved and decrypted the front section of the resulting string has replacement and/or incorrect characters:
Expected:
{"players":[{"label":"...
Actual:
�Ӹ�!G#${�W�Rՙ�bel":"...
If it makes any difference the actual placement/incorrect chars are different each time I refresh the page on the same file.
In case anyone comes across this...
The IV needs to be prepended to the file before encoding, like so:
public function encrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
$result = base64_encode($iv.mcrypt_encrypt(MCRYPT_TWOFISH, $key, $text, MCRYPT_MODE_CBC, $iv));
return $result;
}
Then when decrypting take the IV from the decoded string and use it to decrypt, like so:
public function decrypt($text){
$key = hash("md5", KEY);
$decode = base64_decode($text);
$iv = substr($decode, 0, 16);
$decrypt = substr($decode, 16);
$result = mcrypt_decrypt(MCRYPT_TWOFISH, $key, $decrypt, MCRYPT_MODE_CBC, $iv);
return $result;
}