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($config->PUBLICKEY_BYTES);
$hkdfSalt = $input->readBytes($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);
unset($ephemeral);
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);
$oldMACs = self::streamVerify($input, Util::safeStrcpy($mac), $config);
// We no longer need this:
\Sodium\memzero($hkdfSalt);
$ret = self::streamDecrypt($input, $output, new EncryptionKey(new HiddenString($encKey)), $nonce, $mac, $config, $oldMACs);
unset($encKey);
unset($authKey);
unset($nonce);
unset($mac);
unset($config);
unset($oldMACs);
return $ret;
}