protected static function unsealData(
        ReadOnlyFile $input,
        MutableFile $output,
        EncryptionSecretKey $secretKey
    ): bool {
        $publicKey = $secretKey
            ->derivePublicKey();

        // Is the file at least as long as a header?
        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, 'seal');

        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 public key and salt
        $ephPublic = $input->readBytes((int) $config->PUBLICKEY_BYTES);
        $hkdfSalt = $input->readBytes((int) $config->HKDF_SALT_LEN);

        // Generate the same nonce, as per sealData()
        $nonce = \sodium_crypto_generichash(
            $ephPublic . $publicKey->getRawKeyMaterial(),
            '',
            \SODIUM_CRYPTO_STREAM_NONCEBYTES
        );

        // Create a key object out of the public key:
        $ephemeral = new EncryptionPublicKey(
            new HiddenString($ephPublic)
        );

        $key = AsymmetricCrypto::getSharedSecret(
            $secretKey,
            $ephemeral,
            true
        );
        // @codeCoverageIgnoreStart
        if (!($key instanceof EncryptionKey)) {
            throw new \TypeError();
        }
        // @codeCoverageIgnoreEnd
        unset($ephemeral);

        /**
         * @var string $encKey
         * @var string $authKey
         */
        list ($encKey, $authKey) = self::splitKeys($key, $hkdfSalt, $config);
        // We no longer need the original key after we split it
        unset($key);

        $mac = \sodium_crypto_generichash_init($authKey);

        \sodium_crypto_generichash_update($mac, $header);
        \sodium_crypto_generichash_update($mac, $ephPublic);
        \sodium_crypto_generichash_update($mac, $hkdfSalt);

        /** @var string $mac */
        $oldMACs = self::streamVerify($input, Util::safeStrcpy($mac), $config);

        // We no longer need these:
        \sodium_memzero($authKey);
        \sodium_memzero($hkdfSalt);

        $ret = self::streamDecrypt(
            $input,
            $output,
            new EncryptionKey(
                new HiddenString($encKey)
            ),
            $nonce,
            $mac,
            $config,
            $oldMACs
        );

        \sodium_memzero($encKey);
        unset($encKey);
        unset($nonce);
        unset($mac);
        unset($config);
        unset($oldMACs);
        return $ret;
    }