$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
/* Verify the Poly1305 MAC -before- attempting to decrypt! */
$state = new ParagonIE_Sodium_Core32_Poly1305_State(self::substr($block0, 0, 32));
if (!self::onetimeauth_verify_core32($state, $ifp, $tag, $mlen)) {
throw new SodiumException('Invalid MAC');
* Set the cursor to the end of the first half-block. All future bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
$first32 = fread($ifp, 32);
if (!is_string($first32)) {
throw new SodiumException('Could not read input file');
$first32len = self::strlen($first32);
self::substr($block0, 32, $first32len),
self::substr($first32, 0, $first32len)
$incr = self::BUFFER_SIZE >> 6;
/* Decrypts ciphertext, writes to output file. */
$blockSize = $mlen > self::BUFFER_SIZE
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
$pBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
fwrite($ofp, $pBlock, $blockSize);
* One-time message authentication for 32-bit systems
* @param ParagonIE_Sodium_Core32_Poly1305_State $state
* @throws SodiumException
protected static function onetimeauth_verify_core32(
ParagonIE_Sodium_Core32_Poly1305_State $state,
$pos = self::ftell($ifp);
$blockSize = $mlen > self::BUFFER_SIZE
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
$state->update($ciphertext);
$res = ParagonIE_Sodium_Core32_Util::verify_16($tag, $state->finish());
fseek($ifp, $pos, SEEK_SET);
* @param resource $resource
* @throws SodiumException
private static function ftell($resource)
$return = ftell($resource);
throw new SodiumException('ftell() returned false');