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);
// 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 = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
// Split the keys
list($encKey, $authKey) = self::splitKeys($sharedSecretKey, $hkdfSalt, $config);
// We no longer need the original key after we split it
unset($key);
// Write the header:
$output->writeBytes(Halite::HALITE_VERSION_FILE, Halite::VERSION_TAG_LEN);
$output->writeBytes($ephPublic->getRawKeyMaterial(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
$output->writeBytes($hkdfSalt, $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);
return self::streamEncrypt($input, $output, new EncryptionKey(new HiddenString($encKey)), $nonce, $mac, $config);
}