2awm366 2awm366 - 2 months ago 12
PHP Question

PHP MCrypt decryption fails unless using AES-256

I have written a class to encrypt and decrypt strings, but I can't use any cipher except

MCRYPT_RIJNDAEL_256
. The program always report that the message is corrupted. How can I fix it?

The ciphers I have tested which fails are
MCRYPT_RIJNDAEL_128
MCRYPT_RIJNDAEL_192
MCRYPT_BLOWFISH
MCRYPT_SERPENT
and
MCRYPT_TWOFISH
.

Here's my code:

class Crypt {
private $masterKey;
private $subKey;
private $cipher = MCRYPT_RIJNDAEL_256 ;
private $cipherMode = MCRYPT_MODE_CFB;
//private $hashAlog = 'sha256';

public function __construct($masterKey) {
$this->masterKey = $masterKey;
}

public function setKey($masterKey) {
$this->__construct($masterKey);
}

public function encrypt($message) {
$iv = mcrypt_create_iv($this->getIVSize());
$hmac = $this->signMsg($message);
$this->genSubKey($iv);
$cipherText = mcrypt_encrypt($this->cipher, $this->subKey, $message, $this->cipherMode, $iv);
$cipherText = $iv . $hmac . $cipherText;
return base64_encode($cipherText);
}

public function decrypt($enc_message) {
$mixedMsg = base64_decode($enc_message);
$iv = substr($mixedMsg, 0, $this->getIVSize());
$this->genSubKey($iv);
$hmac = substr($mixedMsg, $this->getIVSize(), strlen($this->signMsg(null)));
$cipherText = substr($mixedMsg, $this->getIVSize() + strlen($this->signMsg(null)));
$message = mcrypt_decrypt($this->cipher, $this->subKey, $cipherText, $this->cipherMode, $iv);
if(!$message)
die("Decrypt Error!");
if($hmac != $this->signMsg($message))
die("Message Corrupted");
return $message;
}

private function genSubKey($iv) {
$this->subKey = hash_pbkdf2("sha256", $this->masterKey, $iv, 50000, $this->getKeySize());
}

private function getKeySize() {
return mcrypt_get_key_size($this->cipher, $this->cipherMode);
}

private function getIVSize() {
return mcrypt_get_iv_size($this->cipher, $this->cipherMode);
}

private function signMsg($message) {
return hash_hmac("sha512", $message, $this->masterKey, true);
}
}

Answer

The problem is caused by the hash_pbkdf2 function in the genSubKey function. Since hash_pbkdf2 will output hex encoded strings, it will be twice as long as the key size. To solve this, we need to pass true as an additional parameter to it, let it output raw bytes and fit the key size.

Here's the corrected code:

private function genSubKey($iv) {
    $this->subKey = hash_pbkdf2("sha256", $this->masterKey, $iv, 50000, $this->getKeySize(), true);
}
Comments