protected static function sealData(
        ReadOnlyFile $input,
        MutableFile $output,
        EncryptionPublicKey $publicKey
    ): int {
        // Generate a new keypair for this encryption
        $ephemeralKeyPair = KeyFactory::generateEncryptionKeyPair();
        $ephSecret = $ephemeralKeyPair->getSecretKey();
        $ephPublic = $ephemeralKeyPair->getPublicKey();
        unset($ephemeralKeyPair);

        // Calculate the shared secret key
        $sharedSecretKey = AsymmetricCrypto::getSharedSecret($ephSecret, $publicKey, true);
        // @codeCoverageIgnoreStart
        if (!($sharedSecretKey instanceof EncryptionKey)) {
            throw new \TypeError('Shared secret is the wrong key type.');
        }
        // @codeCoverageIgnoreEnd

        // Destroy the secret key after we have the shared secret
        unset($ephSecret);

        // Load the configuration
        $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'seal');

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

        // Generate a random HKDF salt
        $hkdfSalt = \random_bytes((int) $config->HKDF_SALT_LEN);

        // Split the keys
        /**
         * @var string $encKey
         * @var string $authKey
         */
        list ($encKey, $authKey) = self::splitKeys($sharedSecretKey, $hkdfSalt, $config);

        // Write the header:
        $output->writeBytes(
            Halite::HALITE_VERSION_FILE,
            Halite::VERSION_TAG_LEN
        );
        $output->writeBytes(
            $ephPublic->getRawKeyMaterial(),
            \SODIUM_CRYPTO_BOX_PUBLICKEYBYTES
        );
        $output->writeBytes(
            $hkdfSalt,
            (int) $config->HKDF_SALT_LEN
        );

        // VERSION 2+
        $mac = \sodium_crypto_generichash_init($authKey);

        // We no longer need $authKey after we set up the hash context
        \sodium_memzero($authKey);

        \sodium_crypto_generichash_update($mac, Halite::HALITE_VERSION_FILE);
        \sodium_crypto_generichash_update($mac, $ephPublic->getRawKeyMaterial());
        \sodium_crypto_generichash_update($mac, $hkdfSalt);

        unset($ephPublic);
        \sodium_memzero($hkdfSalt);

        $ret = self::streamEncrypt(
            $input,
            $output,
            new EncryptionKey(
                new HiddenString($encKey)
            ),
            (string) $nonce,
            (string) $mac,
            $config
        );
        \sodium_memzero($encKey);
        unset($encKey);
        unset($nonce);
        return $ret;
    }