private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
{
RuntimeTests::runtimeTest();
if (!$raw_binary) {
try {
$ciphertext = Encoding::hexToBin($ciphertext);
} catch (Ex\BadFormatException $ex) {
throw new Ex\WrongKeyOrModifiedCiphertextException('Ciphertext has invalid hex encoding.');
}
}
if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
throw new Ex\WrongKeyOrModifiedCiphertextException('Ciphertext is too short.');
}
// Get and check the version header.
$header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
if ($header !== Core::CURRENT_VERSION) {
throw new Ex\WrongKeyOrModifiedCiphertextException('Bad version header.');
}
// Get the salt.
$salt = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE, Core::SALT_BYTE_SIZE);
if ($salt === false) {
throw new Ex\EnvironmentIsBrokenException();
}
// Get the IV.
$iv = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, Core::BLOCK_BYTE_SIZE);
if ($iv === false) {
throw new Ex\EnvironmentIsBrokenException();
}
// Get the HMAC.
$hmac = Core::ourSubstr($ciphertext, Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, Core::MAC_BYTE_SIZE);
if ($hmac === false) {
throw new Ex\EnvironmentIsBrokenException();
}
// Get the actual encrypted ciphertext.
$encrypted = Core::ourSubstr($ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE, Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE - Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE);
if ($encrypted === false) {
throw new Ex\EnvironmentIsBrokenException();
}
// Derive the separate encryption and authentication keys from the key
// or password, whichever it is.
$keys = $secret->deriveKeys($salt);
if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
$plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
return $plaintext;
} else {
throw new Ex\WrongKeyOrModifiedCiphertextException('Integrity check failed.');
}
}