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;
    }
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;
    }
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 ; }
Unseal the contents of a file.

@param ReadOnlyFile $input
@param MutableFile $output
@param EncryptionSecretKey $secretKey
@return bool

@throws CannotPerformOperation
@throws FileAccessDenied
@throws FileError
@throws FileModified
@throws InvalidDigestLength
@throws InvalidKey
@throws InvalidMessage
@throws InvalidType
@throws \TypeError
Unseal the contents of a file .