public static function decrypt(string $ciphertext, EncryptionKey $secretKey, $encoding = Halite::ENCODE_BASE64URLSAFE) : HiddenString
{
$decoder = Halite::chooseEncoder($encoding, true);
if ($decoder) {
// We were given encoded data:
try {
$ciphertext = $decoder($ciphertext);
} catch (\RangeException $ex) {
throw new InvalidMessage('Invalid character encoding');
}
}
list($version, $config, $salt, $nonce, $encrypted, $auth) = self::unpackMessageForDecryption($ciphertext);
/* Split our key into two keys: One for encryption, the other for
authentication. By using separate keys, we can reasonably dismiss
likely cross-protocol attacks.
This uses salted HKDF to split the keys, which is why we need the
salt in the first place. */
list($encKey, $authKey) = self::splitKeys($secretKey, $salt, $config);
// Check the MAC first
if (!self::verifyMAC($auth, $version . $salt . $nonce . $encrypted, $authKey, $config)) {
throw new InvalidMessage('Invalid message authentication code');
}
\Sodium\memzero($salt);
\Sodium\memzero($authKey);
// crypto_stream_xor() can be used to encrypt and decrypt
$plaintext = \Sodium\crypto_stream_xor($encrypted, $nonce, $encKey);
if ($plaintext === false) {
throw new InvalidMessage('Invalid message authentication code');
}
\Sodium\memzero($encrypted);
\Sodium\memzero($nonce);
\Sodium\memzero($encKey);
return new HiddenString($plaintext);
}