Friday, May 17, 2024
 Popular · Latest · Hot · Upcoming
116
rated 0 times [  122] [ 6]  / answers: 1 / hits: 27244  / 10 Years ago, sun, december 28, 2014, 12:00:00

I'm encrypting my user password in JavaScript like this:



 var encryptedPassword = CryptoJS.AES.encrypt(password, Secret Passphrase);


It works fine but now I'm trying to decrypt in PHP on the server side like this:



 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
$decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, Secret Passphrase, base64_decode($password), MCRYPT_MODE_CBC, $iv);


it doesn't works at all, the decrypted password string looks very strange:



 string(64) >�OX2MS��댗v�<$�ʕ��i�̄��_��P����կ=�_6(�m����,4WT7��a


Here is the current state of my code in JavaScript after the helpful comments:



    var encryptedPassword = CryptoJS.AES.encrypt(password, Secret Passphrase);
var ivHex = encryptedPassword.iv.toString();
var ivSize = encryptedPassword.algorithm.ivSize; // same as blockSize
var keySize = encryptedPassword.algorithm.keySize;
var keyHex = encryptedPassword.key.toString();
var saltHex = encryptedPassword.salt.toString(); // must be sent
var openSslFormattedCipherTextString = encryptedPassword.toString(); // not used
var cipherTextHex = encryptedPassword.ciphertext.toString(); // must be sent


I am sending saltHex and CipherTextHex to the PHP server and I'm using mcrypt_decrypt() like this:



 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), $saltHex);
$decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, Secret Passphrase, base64_decode($cipherTextHex), MCRYPT_MODE_CBC, $iv);


It still does't work with this updated code.



Can someone help me to decrypt properly with mcrypt_decrypt() PHP function for a simple AES encryption method ? I'm sure I am doing something wrong with the cipher, mcrypt mode and the IV parameters inside my mcrypt_decrypt() method. Thanks if you know.


More From » php

 Answers
10

The problem is that in the CryptoJS code a password is used to derive the key and the IV to be used for AES encryption, but mcrypt only uses the key to encrypt/decrypt. This information needs to be passed to php. Since you don't want to transmit the password, you have to derive the key and IV in the same way in php.



The following code derives the key and IV from a password and salt. It is modeled after the code in my answer here (for more information).



function evpKDF($password, $salt, $keySize = 8, $ivSize = 4, $iterations = 1, $hashAlgorithm = md5) {
$targetKeySize = $keySize + $ivSize;
$derivedBytes = ;
$numberOfDerivedWords = 0;
$block = NULL;
$hasher = hash_init($hashAlgorithm);
while ($numberOfDerivedWords < $targetKeySize) {
if ($block != NULL) {
hash_update($hasher, $block);
}
hash_update($hasher, $password);
hash_update($hasher, $salt);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);

// Iterations
for ($i = 1; $i < $iterations; $i++) {
hash_update($hasher, $block);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);
}

$derivedBytes .= substr($block, 0, min(strlen($block), ($targetKeySize - $numberOfDerivedWords) * 4));

$numberOfDerivedWords += strlen($block)/4;
}

return array(
key => substr($derivedBytes, 0, $keySize * 4),
iv => substr($derivedBytes, $keySize * 4, $ivSize * 4)
);
}


The salt is generated during encryption in CryptoJS and needs to be sent to php with the ciphertext. Before invoking evpKDF the salt has to be converted to a binary string from hex.



$keyAndIV = evpKDF(Secret Passphrase, hex2bin($saltHex));
$decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$keyAndIV[key],
hex2bin($cipherTextHex),
MCRYPT_MODE_CBC,
$keyAndIV[iv]);





If only encryptedPassword.toString() was sent to the server, then it is necessary to split the salt and actual ciphertext before use. The format is a proprietary OpenSSL-compatible format with the first 8 bytes being Salted__, the next 8 bytes being the random salt and the rest is the actual ciphertext. Everything together is Base64-encoded.



function decrypt($ciphertext, $password) {
$ciphertext = base64_decode($ciphertext);
if (substr($ciphertext, 0, 8) != Salted__) {
return false;
}
$salt = substr($ciphertext, 8, 8);
$keyAndIV = evpKDF($password, $salt);
$decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$keyAndIV[key],
substr($ciphertext, 16),
MCRYPT_MODE_CBC,
$keyAndIV[iv]);

// unpad (PKCS#7)
return substr($decryptPassword, 0, strlen($decryptPassword) - ord($decryptPassword[strlen($decryptPassword)-1]));
}


The same can be achieved with the OpenSSL extension instead of Mcrypt:



function decrypt($ciphertext, $password) {
$ciphertext = base64_decode($ciphertext);
if (substr($ciphertext, 0, 8) != Salted__) {
return false;
}
$salt = substr($ciphertext, 8, 8);
$keyAndIV = evpKDF($password, $salt);
$decryptPassword = openssl_decrypt(
substr($ciphertext, 16),
aes-256-cbc,
$keyAndIV[key],
OPENSSL_RAW_DATA, // base64 was already decoded
$keyAndIV[iv]);

return $decryptPassword;
}

[#68369] Wednesday, December 24, 2014, 10 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
mustafaericho

Total Points: 322
Total Questions: 103
Total Answers: 110

Location: Montenegro
Member since Thu, Jun 16, 2022
2 Years ago
mustafaericho questions
Mon, May 31, 21, 00:00, 3 Years ago
Sun, May 23, 21, 00:00, 3 Years ago
Sat, Feb 13, 21, 00:00, 3 Years ago
Sat, Jan 2, 21, 00:00, 3 Years ago
Thu, Nov 12, 20, 00:00, 4 Years ago
;