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);
}
}
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);
}