/** * Stream encryption - Do not call directly * * @param ReadOnlyFile $input * @param MutableFile $output * @param EncryptionKey $encKey * @param string $nonce * @param resource $mac (hash context) * @param Config $config * @return int * @throws CryptoException\AccessDenied * @throws CryptoException\FileModified * @throws CryptoException\InvalidKey */ private static final function streamEncrypt(ReadOnlyFile $input, MutableFile $output, EncryptionKey $encKey, string $nonce, $mac, Config $config) : int { $initHash = $input->getHash(); // Begin the streaming decryption $size = $input->getSize(); while ($input->remainingBytes() > 0) { $read = $input->readBytes($input->getPos() + $config->BUFFER > $size ? $size - $input->getPos() : $config->BUFFER); $encrypted = \Sodium\crypto_stream_xor($read, $nonce, $encKey->getRawKeyMaterial()); if ($config->USE_BLAKE2B) { \Sodium\crypto_generichash_update($mac, $encrypted); } else { \hash_update($mac, $encrypted); } $output->writeBytes($encrypted); \Sodium\increment($nonce); } \Sodium\memzero($nonce); // Check that our input file was not modified before we MAC it if (!\hash_equals($input->gethash(), $initHash)) { throw new CryptoException\FileModified('Read-only file has been modified since it was opened for reading'); } if ($config->USE_BLAKE2B) { return $output->writeBytes(\Sodium\crypto_generichash_final($mac, $config->MAC_SIZE), $config->MAC_SIZE); } return $output->writeBytes(\hash_final($mac, true)); }