/**
* Stream decryption - Do not call directly
*
* @param ReadOnlyFile $input
* @param MutableFile $output
* @param Key $encKey
* @param string $nonce
* @param resource $mac (hash context)
* @param Config $config
* @throws FileAlert\AccessDenied
*/
private static final function streamDecrypt(ReadOnlyFile $input, MutableFile $output, KeyInterface $encKey, $nonce, $mac, Config $config, array &$chunk_macs)
{
if (!$encKey instanceof EncryptionKey) {
throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 3: Expected an instance of EncryptionKey');
}
$start = $input->getPos();
$cipher_end = $input->getSize() - $config->MAC_SIZE;
// Begin the streaming decryption
$input->reset($start);
while ($input->remainingBytes() > $config->MAC_SIZE) {
if ($input->getPos() + $config->BUFFER > $cipher_end) {
$read = $input->readBytes($cipher_end - $input->getPos());
} else {
$read = $input->readBytes($config->BUFFER);
}
\hash_update($mac, $read);
$calcMAC = \hash_copy($mac);
if ($calcMAC === false) {
throw new CryptoException\CannotPerformOperation('An unknown error has occurred');
}
$calc = \hash_final($calcMAC, true);
if (empty($chunk_macs)) {
throw new CryptoException\InvalidMessage('Invalid message authentication code');
} else {
$chkmac = \array_shift($chunk_macs);
if (!\hash_equals($chkmac, $calc)) {
throw new CryptoException\InvalidMessage('Invalid message authentication code');
}
}
$decrypted = \Sodium\crypto_stream_xor($read, $nonce, $encKey->get());
$output->writeBytes($decrypted);
\Sodium\increment($nonce);
}
\Sodium\memzero($nonce);
return true;
}