I need to encrypt a short string using Javascript (pidCrypt AES CBC) then decrypt it using PHP (phpseclib Crypt_AES CBC).
There are so many incompatibilities between various libraries (tried many of them, some I couldn't even start to use because of lack of documentation) that I am way over my head trying to understand and overcome them (the current "standards" just don't cover debugging, and gibberish or simply a false
will be returned with incorrect usage).
pidCrypt AES CBC says it is using OpenSSL compatible encoding.
So far, I can't understand why the output from pidCrypt won't be decrypted in phpseclib:
pidCrypt
var aes=new pidCrypt.AES.CBC();
aes.encryptText("abcdefg", "secret", {nBits: 128});
console.log(aes.pidcrypt.getParams());
/**
A0_PAD: true
UTF8: true
blockSize: 16
clear: true
dataIn: "abcdefg"
dataOut: "U2FsdGVkX19p8dJctoZSgamat+UBHMWM/Zx64fBDYJY="
decryptIn: ""
decryptOut: ""
encryptIn: Array[16]
encryptOut: "©·åÅýzáðC`"
iv: "e314f8ebbcc5a1e0ae6c27033dd6725f"
key: "49f9bd99b7952b68b3bfa47404455fa7"
nBits: 128
salt: "69f1d25cb6865281"
*/
phpseclib
function hex2raw($strHexString)
{
$strRawBytes="";
$arrChunks=str_split($strHexString, 2);
for($i=0; $i<count($arrChunks); $i++)
$strRawBytes.=chr(hexdec($arrChunks[$i]));
return $strRawBytes;
}
require_once("Crypt/AES.php");
$aes=new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setPassword("secret");
$aes->setIV(hex2raw("e314f8ebbcc5a1e0ae6c27033dd6725f"));
var_export($aes->decrypt(base64_decode("U2FsdGVkX19p8dJctoZSgamat+UBHMWM/Zx64fBDYJY=")));
/**
false
*/
I have also tried the phpseclib AES CBC mode "Key Derivation: None" example (setKey and setIV instead of setPassword), with the same results.
How can I get phpseclib to decode the above pidCrypt AES CBC output?
or
Are there alternatives to phpseclib which can decrypt the above pidCrypt output (which have a code API; OpenSSL usage examples not allowed)?
Please, no lectures on Javascript security and network security. This is not meant to protect against internet/network sniffing.
Found a solution in a comment on php.net for decrypting using OpenSSL, removed the OpenSSL part and replaced it with phpseclib (which in turn uses php's mcrypt, or its own software only implementation).
require_once("Crypt/AES.php");
//https://www.pidder.com/pidcrypt/?page=demo_aes-cbc
//"U2FsdGVkX18KqDRV4bSqJCauxP7004rQmPu3HD1FUrgbXEGpjJAKAfgYvxtWJ6iJ"
//Used the password: "password".
var_export(pidCryptAESCBCDecrypt("U2FsdGVkX18KqDRV4bSqJCauxP7004rQmPu3HD1FUrgbXEGpjJAKAfgYvxtWJ6iJ", "password"));
//Outputs: "Some text to encrypt..."
function pidCryptAESCBCDecrypt($strBase64OpenSSLCompatibleCipher, $strPassword)
{
$data=base64_decode($strBase64OpenSSLCompatibleCipher);
$salt=substr($data, 8, 8);
$ct=substr($data, 16);
/**
* From https://github.com/mdp/gibberish-aes
*
* Number of rounds depends on the size of the AES in use
* 3 rounds for 256
* 2 rounds for the key, 1 for the IV
* 2 rounds for 128
* 1 round for the key, 1 round for the IV
* 3 rounds for 192 since it's not evenly divided by 128 bits
*/
$rounds = 3;
$data00 = $strPassword.$salt;
$md5_hash = array();
$md5_hash[0] = md5($data00, true);
$result = $md5_hash[0];
for ($i = 1; $i < $rounds; $i++) {
$md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true);
$result .= $md5_hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
$aes=new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey($key);
$aes->setIV($iv);
echo $aes->decrypt($ct);
}
Update: Even simpler (can't believe I didn't see it), send to phpseclib pidCryptUtil.encodeBase64(aes.pidcrypt.getParams().encryptOut)
, aes.pidcrypt.getParams().iv
and aes.pidcrypt.getParams().key
.