protected static function decryptData(ReadOnlyFile $input, MutableFile $output, EncryptionKey $key) : bool
{
// Rewind
$input->reset(0);
// Make sure it's large enough to even read a version tag
if ($input->getSize() < Halite::VERSION_TAG_LEN) {
throw new InvalidMessage("Input file is too small to have been encrypted by Halite.");
}
// Parse the header, ensuring we get 4 bytes
$header = $input->readBytes(Halite::VERSION_TAG_LEN);
// Load the config
$config = self::getConfig($header, 'encrypt');
// Is this shorter than an encrypted empty string?
if ($input->getSize() < $config->SHORTEST_CIPHERTEXT_LENGTH) {
throw new InvalidMessage("Input file is too small to have been encrypted by Halite.");
}
// Let's grab the first nonce and salt
$firstNonce = $input->readBytes($config->NONCE_BYTES);
$hkdfSalt = $input->readBytes($config->HKDF_SALT_LEN);
// Split our keys, begin the HMAC instance
list($encKey, $authKey) = self::splitKeys($key, $hkdfSalt, $config);
// VERSION 2+
$mac = \Sodium\crypto_generichash_init($authKey);
\Sodium\crypto_generichash_update($mac, $header);
\Sodium\crypto_generichash_update($mac, $firstNonce);
\Sodium\crypto_generichash_update($mac, $hkdfSalt);
$old_macs = self::streamVerify($input, Util::safeStrcpy($mac), $config);
\Sodium\memzero($authKey);
\Sodium\memzero($hkdfSalt);
$ret = self::streamDecrypt($input, $output, new EncryptionKey(new HiddenString($encKey)), $firstNonce, $mac, $config, $old_macs);
unset($encKey);
unset($authKey);
unset($firstNonce);
unset($mac);
unset($config);
unset($old_macs);
return $ret;
}