final private static function streamVerify(
        ReadOnlyFile $input,
        $mac,
        Config $config
    ): array {
        /** @var int $start */
        $start = $input->getPos();

        // Grab the stored MAC:
        /** @var int $cipher_end */
        $cipher_end = $input->getSize() - (int) $config->MAC_SIZE;
        $input->reset($cipher_end);
        $stored_mac = $input->readBytes((int) $config->MAC_SIZE);
        $input->reset($start);

        $chunkMACs = [];

        $break = false;
        while (!$break && $input->getPos() < $cipher_end) {

            /**
             * Would a full BUFFER read put it past the end of the
             * ciphertext? If so, only return a portion of the file.
             */
            if (($input->getPos() + (int) $config->BUFFER) >= $cipher_end) {
                $break = true;
                $read = $input->readBytes($cipher_end - $input->getPos());
            } else {
                // @codeCoverageIgnoreStart
                $read = $input->readBytes((int) $config->BUFFER);
                // @codeCoverageIgnoreEnd
            }

            /**
             * We're updating our HMAC and nothing else
             */
            \sodium_crypto_generichash_update($mac, $read);
            $mac = (string) $mac;
            // Copy the hash state then store the MAC of this chunk
            /** @var string $chunkMAC */
            $chunkMAC = Util::safeStrcpy($mac);
            $chunkMACs []= \sodium_crypto_generichash_final(
                // @codeCoverageIgnoreStart
                $chunkMAC,
                // @codeCoverageIgnoreEnd
                (int) $config->MAC_SIZE
            );
        }

        /**
         * We should now have enough data to generate an identical MAC
         */
        $finalHMAC = \sodium_crypto_generichash_final(
            // @codeCoverageIgnoreStart
            $mac,
            // @codeCoverageIgnoreEnd
            (int) $config->MAC_SIZE
        );

        /**
         * Use hash_equals() to be timing-invariant
         */
        if (!\hash_equals($finalHMAC, $stored_mac)) {
            throw new InvalidMessage(
                'Invalid message authentication code'
            );
        }
        $input->reset($start);
        return $chunkMACs;
    }
final private static function streamVerify(
        ReadOnlyFile $input,
        $mac,
        Config $config
    ): array {
        /** @var int $start */
        $start = $input->getPos();

        // Grab the stored MAC:
        /** @var int $cipher_end */
        $cipher_end = $input->getSize() - (int) $config->MAC_SIZE;
        $input->reset($cipher_end);
        $stored_mac = $input->readBytes((int) $config->MAC_SIZE);
        $input->reset($start);

        $chunkMACs = [];

        $break = false;
        while (!$break && $input->getPos() < $cipher_end) {

            /**
             * Would a full BUFFER read put it past the end of the
             * ciphertext? If so, only return a portion of the file.
             */
            if (($input->getPos() + (int) $config->BUFFER) >= $cipher_end) {
                $break = true;
                $read = $input->readBytes($cipher_end - $input->getPos());
            } else {
                // @codeCoverageIgnoreStart
                $read = $input->readBytes((int) $config->BUFFER);
                // @codeCoverageIgnoreEnd
            }

            /**
             * We're updating our HMAC and nothing else
             */
            \sodium_crypto_generichash_update($mac, $read);
            $mac = (string) $mac;
            // Copy the hash state then store the MAC of this chunk
            /** @var string $chunkMAC */
            $chunkMAC = Util::safeStrcpy($mac);
            $chunkMACs []= \sodium_crypto_generichash_final(
                // @codeCoverageIgnoreStart
                $chunkMAC,
                // @codeCoverageIgnoreEnd
                (int) $config->MAC_SIZE
            );
        }

        /**
         * We should now have enough data to generate an identical MAC
         */
        $finalHMAC = \sodium_crypto_generichash_final(
            // @codeCoverageIgnoreStart
            $mac,
            // @codeCoverageIgnoreEnd
            (int) $config->MAC_SIZE
        );

        /**
         * Use hash_equals() to be timing-invariant
         */
        if (!\hash_equals($finalHMAC, $stored_mac)) {
            throw new InvalidMessage(
                'Invalid message authentication code'
            );
        }
        $input->reset($start);
        return $chunkMACs;
    }
final private static function streamVerify ( ReadOnlyFile $ input , $ mac , Config $ config ) : array { /** @var int $start */ $ start = $ input -> getPos ( ) ; // Grab the stored MAC: /** @var int $cipher_end */ $ cipher_end = $ input -> getSize ( ) - ( int ) $ config -> MAC_SIZE ; $ input -> reset ( $ cipher_end ) ; $ stored_mac = $ input -> readBytes ( ( int ) $ config -> MAC_SIZE ) ; $ input -> reset ( $ start ) ; $ chunkMACs = [ ] ; $ break = false ; while ( ! $ break && $ input -> getPos ( ) < $ cipher_end ) { /**
             * Would a full BUFFER read put it past the end of the
             * ciphertext? If so, only return a portion of the file.
             */ if ( ( $ input -> getPos ( ) + ( int ) $ config -> BUFFER ) >= $ cipher_end ) { $ break = true ; $ read = $ input -> readBytes ( $ cipher_end - $ input -> getPos ( ) ) ; } else { // @codeCoverageIgnoreStart $ read = $ input -> readBytes ( ( int ) $ config -> BUFFER ) ; // @codeCoverageIgnoreEnd } /**
             * We're updating our HMAC and nothing else
             */ \ sodium_crypto_generichash_update ( $ mac , $ read ) ; $ mac = ( string ) $ mac ; // Copy the hash state then store the MAC of this chunk /** @var string $chunkMAC */ $ chunkMAC = Util :: safeStrcpy ( $ mac ) ; $ chunkMACs [ ] = \ sodium_crypto_generichash_final ( // @codeCoverageIgnoreStart $ chunkMAC , // @codeCoverageIgnoreEnd ( int ) $ config -> MAC_SIZE ) ; } /**
         * We should now have enough data to generate an identical MAC
         */ $ finalHMAC = \ sodium_crypto_generichash_final ( // @codeCoverageIgnoreStart $ mac , // @codeCoverageIgnoreEnd ( int ) $ config -> MAC_SIZE ) ; /**
         * Use hash_equals() to be timing-invariant
         */ if ( ! \ hash_equals ( $ finalHMAC , $ stored_mac ) ) { throw new InvalidMessage ( 'Invalid message authentication code' ) ; } $ input -> reset ( $ start ) ; return $ chunkMACs ; }
Recalculate and verify the HMAC of the input file

@param ReadOnlyFile $input  The file we are verifying
@param string $mac (hash context)
@param Config $config       Version-specific settings

@return array               Hashes of various chunks

@throws CannotPerformOperation
@throws FileAccessDenied
@throws FileModified
@throws InvalidMessage
@throws \TypeError
@throws \SodiumException
Recalculate and verify the HMAC of the input file