|
<?php |
|
|
|
if (class_exists('ParagonIE_Sodium_File', false)) { |
|
return; |
|
} |
|
|
|
|
|
|
|
class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util |
|
{ |
|
|
|
const BUFFER_SIZE = 8192; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function box($inputFile, $outputFile, $nonce, $keyPair) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($nonce)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); |
|
} |
|
|
|
|
|
if (!is_string($keyPair)) { |
|
throw new TypeError('Argument 4 must be a string, ' . gettype($keyPair) . ' given.'); |
|
} |
|
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) { |
|
throw new TypeError('Argument 3 must be CRYPTO_BOX_NONCEBYTES bytes'); |
|
} |
|
if (self::strlen($keyPair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); |
|
} |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $keyPair); |
|
fclose($ifp); |
|
fclose($ofp); |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function box_open($inputFile, $outputFile, $nonce, $keypair) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($nonce)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); |
|
} |
|
if (!is_string($keypair)) { |
|
throw new TypeError('Argument 4 must be a string, ' . gettype($keypair) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_BOX_NONCEBYTES bytes'); |
|
} |
|
if (self::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); |
|
} |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $keypair); |
|
fclose($ifp); |
|
fclose($ofp); |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($nonce); |
|
ParagonIE_Sodium_Compat::memzero($ephKeypair); |
|
} catch (SodiumException $ex) { |
|
if (isset($ephKeypair)) { |
|
unset($ephKeypair); |
|
} |
|
} |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function box_seal($inputFile, $outputFile, $publicKey) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($publicKey)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { |
|
throw new TypeError('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES bytes'); |
|
} |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
|
|
$ephKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair(); |
|
|
|
|
|
$msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey( |
|
ParagonIE_Sodium_Compat::crypto_box_secretkey($ephKeypair), |
|
$publicKey |
|
); |
|
|
|
|
|
$ephemeralPK = ParagonIE_Sodium_Compat::crypto_box_publickey($ephKeypair); |
|
|
|
|
|
$nonce = ParagonIE_Sodium_Compat::crypto_generichash( |
|
$ephemeralPK . $publicKey, |
|
'', |
|
24 |
|
); |
|
|
|
|
|
$firstWrite = fwrite( |
|
$ofp, |
|
$ephemeralPK, |
|
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES |
|
); |
|
if (!is_int($firstWrite)) { |
|
fclose($ifp); |
|
fclose($ofp); |
|
ParagonIE_Sodium_Compat::memzero($ephKeypair); |
|
throw new SodiumException('Could not write to output file'); |
|
} |
|
if ($firstWrite !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { |
|
ParagonIE_Sodium_Compat::memzero($ephKeypair); |
|
fclose($ifp); |
|
fclose($ofp); |
|
throw new SodiumException('Error writing public key to output file'); |
|
} |
|
|
|
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $msgKeypair); |
|
fclose($ifp); |
|
fclose($ofp); |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($nonce); |
|
ParagonIE_Sodium_Compat::memzero($ephKeypair); |
|
} catch (SodiumException $ex) { |
|
|
|
unset($ephKeypair); |
|
} |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function box_seal_open($inputFile, $outputFile, $ecdhKeypair) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($ecdhKeypair)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($ecdhKeypair) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($ecdhKeypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { |
|
throw new TypeError('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); |
|
} |
|
|
|
$publicKey = ParagonIE_Sodium_Compat::crypto_box_publickey($ecdhKeypair); |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
$ephemeralPK = fread($ifp, ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES); |
|
if (!is_string($ephemeralPK)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
if (self::strlen($ephemeralPK) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { |
|
fclose($ifp); |
|
fclose($ofp); |
|
throw new SodiumException('Could not read public key from sealed file'); |
|
} |
|
|
|
$nonce = ParagonIE_Sodium_Compat::crypto_generichash( |
|
$ephemeralPK . $publicKey, |
|
'', |
|
24 |
|
); |
|
$msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey( |
|
ParagonIE_Sodium_Compat::crypto_box_secretkey($ecdhKeypair), |
|
$ephemeralPK |
|
); |
|
|
|
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $msgKeypair); |
|
fclose($ifp); |
|
fclose($ofp); |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($nonce); |
|
ParagonIE_Sodium_Compat::memzero($ephKeypair); |
|
} catch (SodiumException $ex) { |
|
if (isset($ephKeypair)) { |
|
unset($ephKeypair); |
|
} |
|
} |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function generichash($filePath, $key = '', $outputLength = 32) |
|
{ |
|
|
|
if (!is_string($filePath)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.'); |
|
} |
|
if (!is_string($key)) { |
|
if (is_null($key)) { |
|
$key = ''; |
|
} else { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.'); |
|
} |
|
} |
|
if (!is_int($outputLength)) { |
|
if (!is_numeric($outputLength)) { |
|
throw new TypeError('Argument 3 must be an integer, ' . gettype($outputLength) . ' given.'); |
|
} |
|
$outputLength = (int) $outputLength; |
|
} |
|
|
|
|
|
if (!empty($key)) { |
|
if (self::strlen($key) < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN) { |
|
throw new TypeError('Argument 2 must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes'); |
|
} |
|
if (self::strlen($key) > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) { |
|
throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes'); |
|
} |
|
} |
|
if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) { |
|
throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN'); |
|
} |
|
if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) { |
|
throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX'); |
|
} |
|
|
|
|
|
$size = filesize($filePath); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$fp = fopen($filePath, 'rb'); |
|
if (!is_resource($fp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
$ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength); |
|
while ($size > 0) { |
|
$blockSize = $size > 64 |
|
? 64 |
|
: $size; |
|
$read = fread($fp, $blockSize); |
|
if (!is_string($read)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $read); |
|
$size -= $blockSize; |
|
} |
|
|
|
fclose($fp); |
|
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function secretbox($inputFile, $outputFile, $nonce, $key) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given..'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($nonce)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { |
|
throw new TypeError('Argument 3 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); |
|
} |
|
if (!is_string($key)) { |
|
throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); |
|
} |
|
if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_KEYBYTES bytes'); |
|
} |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
$res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key); |
|
fclose($ifp); |
|
fclose($ofp); |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function secretbox_open($inputFile, $outputFile, $nonce, $key) |
|
{ |
|
|
|
if (!is_string($inputFile)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); |
|
} |
|
if (!is_string($outputFile)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); |
|
} |
|
if (!is_string($nonce)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); |
|
} |
|
if (!is_string($key)) { |
|
throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); |
|
} |
|
if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { |
|
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOXBOX_KEYBYTES bytes'); |
|
} |
|
|
|
|
|
$size = filesize($inputFile); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$ifp = fopen($inputFile, 'rb'); |
|
if (!is_resource($ifp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$ofp = fopen($outputFile, 'wb'); |
|
if (!is_resource($ofp)) { |
|
fclose($ifp); |
|
throw new SodiumException('Could not open output file for writing'); |
|
} |
|
|
|
$res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key); |
|
fclose($ifp); |
|
fclose($ofp); |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($key); |
|
} catch (SodiumException $ex) { |
|
|
|
unset($key); |
|
} |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function sign($filePath, $secretKey) |
|
{ |
|
|
|
if (!is_string($filePath)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.'); |
|
} |
|
if (!is_string($secretKey)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($secretKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) { |
|
throw new TypeError('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES bytes'); |
|
} |
|
if (PHP_INT_SIZE === 4) { |
|
return self::sign_core32($filePath, $secretKey); |
|
} |
|
|
|
|
|
$size = filesize($filePath); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$fp = fopen($filePath, 'rb'); |
|
if (!is_resource($fp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$az = hash('sha512', self::substr($secretKey, 0, 32), true); |
|
|
|
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248); |
|
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($az, 32, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
|
|
$nonceHash = hash_final($hs, true); |
|
|
|
|
|
$pk = self::substr($secretKey, 32, 32); |
|
|
|
|
|
$nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); |
|
|
|
|
|
$sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes( |
|
ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce) |
|
); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($sig, 0, 32)); |
|
self::hash_update($hs, self::substr($pk, 0, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
|
|
$hramHash = hash_final($hs, true); |
|
|
|
|
|
$hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash); |
|
|
|
|
|
$sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az, $nonce); |
|
|
|
|
|
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); |
|
|
|
try { |
|
ParagonIE_Sodium_Compat::memzero($az); |
|
} catch (SodiumException $ex) { |
|
$az = null; |
|
} |
|
fclose($fp); |
|
return $sig; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function verify($sig, $filePath, $publicKey) |
|
{ |
|
|
|
if (!is_string($sig)) { |
|
throw new TypeError('Argument 1 must be a string, ' . gettype($sig) . ' given.'); |
|
} |
|
if (!is_string($filePath)) { |
|
throw new TypeError('Argument 2 must be a string, ' . gettype($filePath) . ' given.'); |
|
} |
|
if (!is_string($publicKey)) { |
|
throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); |
|
} |
|
|
|
|
|
if (self::strlen($sig) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) { |
|
throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES bytes'); |
|
} |
|
if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) { |
|
throw new TypeError('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes'); |
|
} |
|
if (self::strlen($sig) < 64) { |
|
throw new SodiumException('Signature is too short'); |
|
} |
|
|
|
if (PHP_INT_SIZE === 4) { |
|
return self::verify_core32($sig, $filePath, $publicKey); |
|
} |
|
|
|
|
|
if ( |
|
(ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240) |
|
&& |
|
ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32)) |
|
) { |
|
throw new SodiumException('S < L - Invalid signature'); |
|
} |
|
if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) { |
|
throw new SodiumException('Signature is on too small of an order'); |
|
} |
|
if ((self::chrToInt($sig[63]) & 224) !== 0) { |
|
throw new SodiumException('Invalid signature'); |
|
} |
|
$d = 0; |
|
for ($i = 0; $i < 32; ++$i) { |
|
$d |= self::chrToInt($publicKey[$i]); |
|
} |
|
if ($d === 0) { |
|
throw new SodiumException('All zero public key'); |
|
} |
|
|
|
|
|
$size = filesize($filePath); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
$fp = fopen($filePath, 'rb'); |
|
if (!is_resource($fp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$orig = ParagonIE_Sodium_Compat::$fastMult; |
|
|
|
|
|
ParagonIE_Sodium_Compat::$fastMult = true; |
|
|
|
|
|
$A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($sig, 0, 32)); |
|
self::hash_update($hs, self::substr($publicKey, 0, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
$hDigest = hash_final($hs, true); |
|
|
|
|
|
$h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); |
|
|
|
|
|
$R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime( |
|
$h, |
|
$A, |
|
self::substr($sig, 32) |
|
); |
|
|
|
|
|
$rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R); |
|
|
|
|
|
fclose($fp); |
|
|
|
|
|
ParagonIE_Sodium_Compat::$fastMult = $orig; |
|
return self::verify_32($rcheck, self::substr($sig, 0, 32)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function box_encrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) |
|
{ |
|
if (PHP_INT_SIZE === 4) { |
|
return self::secretbox_encrypt( |
|
$ifp, |
|
$ofp, |
|
$mlen, |
|
$nonce, |
|
ParagonIE_Sodium_Crypto32::box_beforenm( |
|
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair), |
|
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair) |
|
) |
|
); |
|
} |
|
return self::secretbox_encrypt( |
|
$ifp, |
|
$ofp, |
|
$mlen, |
|
$nonce, |
|
ParagonIE_Sodium_Crypto::box_beforenm( |
|
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), |
|
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) |
|
) |
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function box_decrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) |
|
{ |
|
if (PHP_INT_SIZE === 4) { |
|
return self::secretbox_decrypt( |
|
$ifp, |
|
$ofp, |
|
$mlen, |
|
$nonce, |
|
ParagonIE_Sodium_Crypto32::box_beforenm( |
|
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair), |
|
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair) |
|
) |
|
); |
|
} |
|
return self::secretbox_decrypt( |
|
$ifp, |
|
$ofp, |
|
$mlen, |
|
$nonce, |
|
ParagonIE_Sodium_Crypto::box_beforenm( |
|
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), |
|
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) |
|
) |
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function secretbox_encrypt($ifp, $ofp, $mlen, $nonce, $key) |
|
{ |
|
if (PHP_INT_SIZE === 4) { |
|
return self::secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key); |
|
} |
|
|
|
$plaintext = fread($ifp, 32); |
|
if (!is_string($plaintext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$first32 = self::ftell($ifp); |
|
|
|
|
|
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); |
|
|
|
|
|
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); |
|
|
|
|
|
$block0 = str_repeat("\x00", 32); |
|
|
|
|
|
$mlen0 = $mlen; |
|
if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { |
|
$mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; |
|
} |
|
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); |
|
|
|
|
|
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( |
|
$block0, |
|
$realNonce, |
|
$subkey |
|
); |
|
|
|
$state = new ParagonIE_Sodium_Core_Poly1305_State( |
|
ParagonIE_Sodium_Core_Util::substr( |
|
$block0, |
|
0, |
|
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES |
|
) |
|
); |
|
|
|
|
|
$start = self::ftell($ofp); |
|
fwrite($ofp, str_repeat("\x00", 16)); |
|
|
|
|
|
$cBlock = ParagonIE_Sodium_Core_Util::substr( |
|
$block0, |
|
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES |
|
); |
|
$state->update($cBlock); |
|
fwrite($ofp, $cBlock); |
|
$mlen -= 32; |
|
|
|
|
|
$iter = 1; |
|
|
|
|
|
$incr = self::BUFFER_SIZE >> 6; |
|
|
|
|
|
|
|
|
|
|
|
fseek($ifp, $first32, SEEK_SET); |
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$plaintext = fread($ifp, $blockSize); |
|
if (!is_string($plaintext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( |
|
$plaintext, |
|
$realNonce, |
|
$iter, |
|
$subkey |
|
); |
|
fwrite($ofp, $cBlock, $blockSize); |
|
$state->update($cBlock); |
|
|
|
$mlen -= $blockSize; |
|
$iter += $incr; |
|
} |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($block0); |
|
ParagonIE_Sodium_Compat::memzero($subkey); |
|
} catch (SodiumException $ex) { |
|
$block0 = null; |
|
$subkey = null; |
|
} |
|
$end = self::ftell($ofp); |
|
|
|
|
|
|
|
|
|
|
|
fseek($ofp, $start, SEEK_SET); |
|
fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); |
|
fseek($ofp, $end, SEEK_SET); |
|
unset($state); |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function secretbox_decrypt($ifp, $ofp, $mlen, $nonce, $key) |
|
{ |
|
if (PHP_INT_SIZE === 4) { |
|
return self::secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key); |
|
} |
|
$tag = fread($ifp, 16); |
|
if (!is_string($tag)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
|
|
|
|
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); |
|
|
|
|
|
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); |
|
|
|
|
|
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( |
|
64, |
|
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), |
|
$subkey |
|
); |
|
|
|
|
|
$state = new ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32)); |
|
if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) { |
|
throw new SodiumException('Invalid MAC'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
$first32 = fread($ifp, 32); |
|
if (!is_string($first32)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$first32len = self::strlen($first32); |
|
fwrite( |
|
$ofp, |
|
self::xorStrings( |
|
self::substr($block0, 32, $first32len), |
|
self::substr($first32, 0, $first32len) |
|
) |
|
); |
|
$mlen -= 32; |
|
|
|
|
|
$iter = 1; |
|
|
|
|
|
$incr = self::BUFFER_SIZE >> 6; |
|
|
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$ciphertext = fread($ifp, $blockSize); |
|
if (!is_string($ciphertext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( |
|
$ciphertext, |
|
$realNonce, |
|
$iter, |
|
$subkey |
|
); |
|
fwrite($ofp, $pBlock, $blockSize); |
|
$mlen -= $blockSize; |
|
$iter += $incr; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function onetimeauth_verify( |
|
ParagonIE_Sodium_Core_Poly1305_State $state, |
|
$ifp, |
|
$tag = '', |
|
$mlen = 0 |
|
) { |
|
|
|
$pos = self::ftell($ifp); |
|
|
|
|
|
$iter = 1; |
|
|
|
|
|
$incr = self::BUFFER_SIZE >> 6; |
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$ciphertext = fread($ifp, $blockSize); |
|
if (!is_string($ciphertext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$state->update($ciphertext); |
|
$mlen -= $blockSize; |
|
$iter += $incr; |
|
} |
|
$res = ParagonIE_Sodium_Core_Util::verify_16($tag, $state->finish()); |
|
|
|
fseek($ifp, $pos, SEEK_SET); |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function updateHashWithFile($hash, $fp, $size = 0) |
|
{ |
|
|
|
if (PHP_VERSION_ID < 70200) { |
|
if (!is_resource($hash)) { |
|
throw new TypeError('Argument 1 must be a resource, ' . gettype($hash) . ' given.'); |
|
} |
|
} else { |
|
if (!is_object($hash)) { |
|
throw new TypeError('Argument 1 must be an object (PHP 7.2+), ' . gettype($hash) . ' given.'); |
|
} |
|
} |
|
|
|
if (!is_resource($fp)) { |
|
throw new TypeError('Argument 2 must be a resource, ' . gettype($fp) . ' given.'); |
|
} |
|
if (!is_int($size)) { |
|
throw new TypeError('Argument 3 must be an integer, ' . gettype($size) . ' given.'); |
|
} |
|
|
|
|
|
$originalPosition = self::ftell($fp); |
|
|
|
|
|
fseek($fp, 0, SEEK_SET); |
|
for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) { |
|
|
|
$message = fread( |
|
$fp, |
|
($size - $i) > self::BUFFER_SIZE |
|
? $size - $i |
|
: self::BUFFER_SIZE |
|
); |
|
if (!is_string($message)) { |
|
throw new SodiumException('Unexpected error reading from file.'); |
|
} |
|
|
|
|
|
self::hash_update($hash, $message); |
|
} |
|
|
|
fseek($fp, $originalPosition, SEEK_SET); |
|
return $hash; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function sign_core32($filePath, $secretKey) |
|
{ |
|
$size = filesize($filePath); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
$fp = fopen($filePath, 'rb'); |
|
if (!is_resource($fp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
$az = hash('sha512', self::substr($secretKey, 0, 32), true); |
|
|
|
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248); |
|
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($az, 32, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
$nonceHash = hash_final($hs, true); |
|
$pk = self::substr($secretKey, 32, 32); |
|
$nonce = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); |
|
$sig = ParagonIE_Sodium_Core32_Ed25519::ge_p3_tobytes( |
|
ParagonIE_Sodium_Core32_Ed25519::ge_scalarmult_base($nonce) |
|
); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($sig, 0, 32)); |
|
self::hash_update($hs, self::substr($pk, 0, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
$hramHash = hash_final($hs, true); |
|
|
|
$hram = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hramHash); |
|
|
|
$sigAfter = ParagonIE_Sodium_Core32_Ed25519::sc_muladd($hram, $az, $nonce); |
|
|
|
|
|
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); |
|
|
|
try { |
|
ParagonIE_Sodium_Compat::memzero($az); |
|
} catch (SodiumException $ex) { |
|
$az = null; |
|
} |
|
fclose($fp); |
|
return $sig; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function verify_core32($sig, $filePath, $publicKey) |
|
{ |
|
|
|
if (ParagonIE_Sodium_Core32_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) { |
|
throw new SodiumException('S < L - Invalid signature'); |
|
} |
|
if (ParagonIE_Sodium_Core32_Ed25519::small_order($sig)) { |
|
throw new SodiumException('Signature is on too small of an order'); |
|
} |
|
|
|
if ((self::chrToInt($sig[63]) & 224) !== 0) { |
|
throw new SodiumException('Invalid signature'); |
|
} |
|
$d = 0; |
|
for ($i = 0; $i < 32; ++$i) { |
|
$d |= self::chrToInt($publicKey[$i]); |
|
} |
|
if ($d === 0) { |
|
throw new SodiumException('All zero public key'); |
|
} |
|
|
|
|
|
$size = filesize($filePath); |
|
if (!is_int($size)) { |
|
throw new SodiumException('Could not obtain the file size'); |
|
} |
|
|
|
|
|
|
|
$fp = fopen($filePath, 'rb'); |
|
if (!is_resource($fp)) { |
|
throw new SodiumException('Could not open input file for reading'); |
|
} |
|
|
|
|
|
|
|
$orig = ParagonIE_Sodium_Compat::$fastMult; |
|
|
|
|
|
ParagonIE_Sodium_Compat::$fastMult = true; |
|
|
|
|
|
$A = ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey); |
|
|
|
$hs = hash_init('sha512'); |
|
self::hash_update($hs, self::substr($sig, 0, 32)); |
|
self::hash_update($hs, self::substr($publicKey, 0, 32)); |
|
|
|
$hs = self::updateHashWithFile($hs, $fp, $size); |
|
|
|
$hDigest = hash_final($hs, true); |
|
|
|
|
|
$h = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); |
|
|
|
|
|
$R = ParagonIE_Sodium_Core32_Ed25519::ge_double_scalarmult_vartime( |
|
$h, |
|
$A, |
|
self::substr($sig, 32) |
|
); |
|
|
|
|
|
$rcheck = ParagonIE_Sodium_Core32_Ed25519::ge_tobytes($R); |
|
|
|
|
|
fclose($fp); |
|
|
|
|
|
ParagonIE_Sodium_Compat::$fastMult = $orig; |
|
return self::verify_32($rcheck, self::substr($sig, 0, 32)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key) |
|
{ |
|
$plaintext = fread($ifp, 32); |
|
if (!is_string($plaintext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$first32 = self::ftell($ifp); |
|
|
|
|
|
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); |
|
|
|
|
|
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); |
|
|
|
|
|
$block0 = str_repeat("\x00", 32); |
|
|
|
|
|
$mlen0 = $mlen; |
|
if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { |
|
$mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; |
|
} |
|
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); |
|
|
|
|
|
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( |
|
$block0, |
|
$realNonce, |
|
$subkey |
|
); |
|
|
|
$state = new ParagonIE_Sodium_Core32_Poly1305_State( |
|
ParagonIE_Sodium_Core32_Util::substr( |
|
$block0, |
|
0, |
|
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES |
|
) |
|
); |
|
|
|
|
|
$start = self::ftell($ofp); |
|
fwrite($ofp, str_repeat("\x00", 16)); |
|
|
|
|
|
$cBlock = ParagonIE_Sodium_Core32_Util::substr( |
|
$block0, |
|
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES |
|
); |
|
$state->update($cBlock); |
|
fwrite($ofp, $cBlock); |
|
$mlen -= 32; |
|
|
|
|
|
$iter = 1; |
|
|
|
|
|
$incr = self::BUFFER_SIZE >> 6; |
|
|
|
|
|
|
|
|
|
|
|
fseek($ifp, $first32, SEEK_SET); |
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$plaintext = fread($ifp, $blockSize); |
|
if (!is_string($plaintext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$cBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( |
|
$plaintext, |
|
$realNonce, |
|
$iter, |
|
$subkey |
|
); |
|
fwrite($ofp, $cBlock, $blockSize); |
|
$state->update($cBlock); |
|
|
|
$mlen -= $blockSize; |
|
$iter += $incr; |
|
} |
|
try { |
|
ParagonIE_Sodium_Compat::memzero($block0); |
|
ParagonIE_Sodium_Compat::memzero($subkey); |
|
} catch (SodiumException $ex) { |
|
$block0 = null; |
|
$subkey = null; |
|
} |
|
$end = self::ftell($ofp); |
|
|
|
|
|
|
|
|
|
|
|
fseek($ofp, $start, SEEK_SET); |
|
fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); |
|
fseek($ofp, $end, SEEK_SET); |
|
unset($state); |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key) |
|
{ |
|
$tag = fread($ifp, 16); |
|
if (!is_string($tag)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
|
|
|
|
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); |
|
|
|
|
|
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); |
|
|
|
|
|
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( |
|
64, |
|
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
|
$subkey |
|
); |
|
|
|
|
|
$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'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
$first32 = fread($ifp, 32); |
|
if (!is_string($first32)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$first32len = self::strlen($first32); |
|
fwrite( |
|
$ofp, |
|
self::xorStrings( |
|
self::substr($block0, 32, $first32len), |
|
self::substr($first32, 0, $first32len) |
|
) |
|
); |
|
$mlen -= 32; |
|
|
|
|
|
$iter = 1; |
|
|
|
|
|
$incr = self::BUFFER_SIZE >> 6; |
|
|
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$ciphertext = fread($ifp, $blockSize); |
|
if (!is_string($ciphertext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$pBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( |
|
$ciphertext, |
|
$realNonce, |
|
$iter, |
|
$subkey |
|
); |
|
fwrite($ofp, $pBlock, $blockSize); |
|
$mlen -= $blockSize; |
|
$iter += $incr; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function onetimeauth_verify_core32( |
|
ParagonIE_Sodium_Core32_Poly1305_State $state, |
|
$ifp, |
|
$tag = '', |
|
$mlen = 0 |
|
) { |
|
|
|
$pos = self::ftell($ifp); |
|
|
|
while ($mlen > 0) { |
|
$blockSize = $mlen > self::BUFFER_SIZE |
|
? self::BUFFER_SIZE |
|
: $mlen; |
|
$ciphertext = fread($ifp, $blockSize); |
|
if (!is_string($ciphertext)) { |
|
throw new SodiumException('Could not read input file'); |
|
} |
|
$state->update($ciphertext); |
|
$mlen -= $blockSize; |
|
} |
|
$res = ParagonIE_Sodium_Core32_Util::verify_16($tag, $state->finish()); |
|
|
|
fseek($ifp, $pos, SEEK_SET); |
|
return $res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function ftell($resource) |
|
{ |
|
$return = ftell($resource); |
|
if (!is_int($return)) { |
|
throw new SodiumException('ftell() returned false'); |
|
} |
|
return (int) $return; |
|
} |
|
} |
|
|