View source
<?php
if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
return;
}
abstract class ParagonIE_Sodium_Crypto32 {
const aead_chacha20poly1305_KEYBYTES = 32;
const aead_chacha20poly1305_NSECBYTES = 0;
const aead_chacha20poly1305_NPUBBYTES = 8;
const aead_chacha20poly1305_ABYTES = 16;
const aead_chacha20poly1305_IETF_KEYBYTES = 32;
const aead_chacha20poly1305_IETF_NSECBYTES = 0;
const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
const aead_chacha20poly1305_IETF_ABYTES = 16;
const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
const aead_xchacha20poly1305_IETF_ABYTES = 16;
const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
const box_curve25519xsalsa20poly1305_MACBYTES = 16;
const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
const onetimeauth_poly1305_BYTES = 16;
const onetimeauth_poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
const secretbox_xsalsa20poly1305_MACBYTES = 16;
const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
const secretbox_xchacha20poly1305_KEYBYTES = 32;
const secretbox_xchacha20poly1305_NONCEBYTES = 24;
const secretbox_xchacha20poly1305_MACBYTES = 16;
const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
const secretbox_xchacha20poly1305_ZEROBYTES = 32;
const stream_salsa20_KEYBYTES = 32;
public static function aead_chacha20poly1305_decrypt($message = '', $ad = '', $nonce = '', $key = '') {
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
$clen = $len - self::aead_chacha20poly1305_ABYTES;
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
$mac = ParagonIE_Sodium_Core32_Util::substr($message, $clen, self::aead_chacha20poly1305_ABYTES);
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen);
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(32, $nonce, $key);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state
->update($ad);
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state
->update($ciphertext);
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state
->finish();
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc($ciphertext, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1));
}
public static function aead_chacha20poly1305_encrypt($message = '', $ad = '', $nonce = '', $key = '') {
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(32, $nonce, $key);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc($message, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1));
$state
->update($ad);
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state
->update($ciphertext);
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state
->finish();
}
public static function aead_chacha20poly1305_ietf_decrypt($message = '', $ad = '', $nonce = '', $key = '') {
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
$clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $nonce, $key);
$mac = ParagonIE_Sodium_Core32_Util::substr($message, $len - self::aead_chacha20poly1305_IETF_ABYTES, self::aead_chacha20poly1305_IETF_ABYTES);
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $len - self::aead_chacha20poly1305_IETF_ABYTES);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state
->update($ad);
$state
->update(str_repeat("\0", 0x10 - $adlen & 0xf));
$state
->update($ciphertext);
$state
->update(str_repeat("\0", 0x10 - $clen & 0xf));
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state
->finish();
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc($ciphertext, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1));
}
public static function aead_chacha20poly1305_ietf_encrypt($message = '', $ad = '', $nonce = '', $key = '') {
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $nonce, $key);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc($message, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1));
$state
->update($ad);
$state
->update(str_repeat("\0", 0x10 - $adlen & 0xf));
$state
->update($ciphertext);
$state
->update(str_repeat("\0", 0x10 - $len & 0xf));
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state
->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state
->finish();
}
public static function aead_xchacha20poly1305_ietf_decrypt($message = '', $ad = '', $nonce = '', $key = '') {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key);
$nonceLast = "\0\0\0\0" . ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
}
public static function aead_xchacha20poly1305_ietf_encrypt($message = '', $ad = '', $nonce = '', $key = '') {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key);
$nonceLast = "\0\0\0\0" . ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
}
public static function auth($message, $key) {
return ParagonIE_Sodium_Core32_Util::substr(hash_hmac('sha512', $message, $key, true), 0, 32);
}
public static function auth_verify($mac, $message, $key) {
return ParagonIE_Sodium_Core32_Util::hashEquals($mac, self::auth($message, $key));
}
public static function box($plaintext, $nonce, $keypair) {
return self::secretbox($plaintext, $nonce, self::box_beforenm(self::box_secretkey($keypair), self::box_publickey($keypair)));
}
public static function box_seal($message, $publicKey) {
$ephemeralKeypair = self::box_keypair();
$ephemeralSK = self::box_secretkey($ephemeralKeypair);
$ephemeralPK = self::box_publickey($ephemeralKeypair);
$nonce = self::generichash($ephemeralPK . $publicKey, '', 24);
$keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
$ciphertext = self::box($message, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
ParagonIE_Sodium_Compat::memzero($ephemeralSK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$ephemeralKeypair = null;
$ephemeralSK = null;
$nonce = null;
}
return $ephemeralPK . $ciphertext;
}
public static function box_seal_open($message, $keypair) {
$ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32);
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
$secretKey = self::box_secretkey($keypair);
$publicKey = self::box_publickey($keypair);
$nonce = self::generichash($ephemeralPK . $publicKey, '', 24);
$keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
$m = self::box_open($ciphertext, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($secretKey);
ParagonIE_Sodium_Compat::memzero($ephemeralPK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$secretKey = null;
$ephemeralPK = null;
$nonce = null;
}
return $m;
}
public static function box_beforenm($sk, $pk) {
return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(str_repeat("\0", 16), self::scalarmult($sk, $pk));
}
public static function box_keypair() {
$sKey = random_bytes(32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
public static function box_seed_keypair($seed) {
$sKey = ParagonIE_Sodium_Core32_Util::substr(hash('sha512', $seed, true), 0, 32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) {
return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) . ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32);
}
public static function box_secretkey($keypair) {
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) {
throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.');
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32);
}
public static function box_publickey($keypair) {
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.');
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32);
}
public static function box_publickey_from_secretkey($sKey) {
if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.');
}
return self::scalarmult_base($sKey);
}
public static function box_open($ciphertext, $nonce, $keypair) {
return self::secretbox_open($ciphertext, $nonce, self::box_beforenm(self::box_secretkey($keypair), self::box_publickey($keypair)));
}
public static function generichash($message, $key = '', $outlen = 32) {
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k
->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
$in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in
->count());
$out = new SplFixedArray($outlen);
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
$outArray = $out
->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
public static function generichash_final($ctx, $outlen = 32) {
if (!is_string($ctx)) {
throw new TypeError('Context must be a string');
}
$out = new SplFixedArray($outlen);
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
$outArray = $out
->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
public static function generichash_init($key = '', $outputLength = 32) {
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k
->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
public static function generichash_init_salt_personal($key = '', $outputLength = 32, $salt = '', $personal = '') {
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k
->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
if (!empty($salt)) {
$s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
}
else {
$s = null;
}
if (!empty($salt)) {
$p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
}
else {
$p = null;
}
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
public static function generichash_update($ctx, $message) {
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
$in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in
->count());
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
}
public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) {
return self::generichash(self::scalarmult($my_sk, $their_pk) . $client_pk . $server_pk);
}
public static function scalarmult($sKey, $pKey) {
$q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
self::scalarmult_throw_if_zero($q);
return $q;
}
public static function scalarmult_base($secret) {
$q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
self::scalarmult_throw_if_zero($q);
return $q;
}
protected static function scalarmult_throw_if_zero($q) {
$d = 0;
for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
$d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]);
}
if (-(1 & $d - 1 >> 8)) {
throw new SodiumException('Zero public key is not allowed');
}
}
public static function secretbox($plaintext, $nonce, $key) {
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
$block0 = str_repeat("\0", 32);
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor($block0, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey);
$c = ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(ParagonIE_Sodium_Core32_Util::substr($plaintext, self::secretbox_xsalsa20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1, $subkey);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(ParagonIE_Sodium_Core32_Util::substr($block0, 0, self::onetimeauth_poly1305_KEYBYTES));
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state
->update($c);
$c = $state
->finish() . $c;
unset($state);
return $c;
}
public static function secretbox_open($ciphertext, $nonce, $key) {
$mac = ParagonIE_Sodium_Core32_Util::substr($ciphertext, 0, self::secretbox_xsalsa20poly1305_MACBYTES);
$c = ParagonIE_Sodium_Core32_Util::substr($ciphertext, self::secretbox_xsalsa20poly1305_MACBYTES);
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(64, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify($mac, $c, ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32));
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
$m = ParagonIE_Sodium_Core32_Util::xorStrings(ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES));
if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(ParagonIE_Sodium_Core32_Util::substr($c, self::secretbox_xsalsa20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1, (string) $subkey);
}
return $m;
}
public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key);
$nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
$block0 = str_repeat("\0", 32);
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
$block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc($block0, $nonceLast, $subkey);
$c = ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(ParagonIE_Sodium_Core32_Util::substr($plaintext, self::secretbox_xchacha20poly1305_ZEROBYTES), $nonceLast, $subkey, ParagonIE_Sodium_Core32_Util::store64_le(1));
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(ParagonIE_Sodium_Core32_Util::substr($block0, 0, self::onetimeauth_poly1305_KEYBYTES));
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state
->update($c);
$c = $state
->finish() . $c;
unset($state);
return $c;
}
public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) {
$mac = ParagonIE_Sodium_Core32_Util::substr($ciphertext, 0, self::secretbox_xchacha20poly1305_MACBYTES);
$c = ParagonIE_Sodium_Core32_Util::substr($ciphertext, self::secretbox_xchacha20poly1305_MACBYTES);
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key);
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(64, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify($mac, $c, ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32));
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
$m = ParagonIE_Sodium_Core32_Util::xorStrings(ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES));
if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
$m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(ParagonIE_Sodium_Core32_Util::substr($c, self::secretbox_xchacha20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), (string) $subkey, ParagonIE_Sodium_Core32_Util::store64_le(1));
}
return $m;
}
public static function secretstream_xchacha20poly1305_init_push($key) {
$out = random_bytes(24);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
$state = new ParagonIE_Sodium_Core32_SecretStream_State($subkey, ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4));
$state
->counterReset();
return array(
$state
->toString(),
$out,
);
}
public static function secretstream_xchacha20poly1305_init_pull($key, $header) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(ParagonIE_Sodium_Core32_Util::substr($header, 0, 16), $key);
$state = new ParagonIE_Sodium_Core32_SecretStream_State($subkey, ParagonIE_Sodium_Core32_Util::substr($header, 16));
$state
->counterReset();
return $state
->toString();
}
public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) {
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
$msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
if ($msglen + 63 >> 6 > 0xfffffffe) {
throw new SodiumException('message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes');
}
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st
->getCombinedNonce(), $st
->getKey()));
$auth
->update($aad);
$auth
->update(str_repeat("\0", 0x10 - $aadlen & 0xf));
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63), $st
->getCombinedNonce(), $st
->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(1));
$auth
->update($block);
$out = $block[0];
$cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc($msg, $st
->getCombinedNonce(), $st
->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(2));
$auth
->update($cipher);
$out .= $cipher;
unset($cipher);
$auth
->update(str_repeat("\0", 0x10 - 64 + $msglen & 0xf));
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
$auth
->update($slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
$auth
->update($slen);
$mac = $auth
->finish();
$out .= $mac;
unset($auth);
$st
->xorNonce($mac);
$st
->incrementCounter();
$state = $st
->toString();
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
if ($rekey || $st
->needsRekey()) {
self::secretstream_xchacha20poly1305_rekey($state);
}
return $out;
}
public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') {
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
$cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
$msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
if ($msglen + 63 >> 6 > 0xfffffffe) {
throw new SodiumException('message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes');
}
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st
->getCombinedNonce(), $st
->getKey()));
$auth
->update($aad);
$auth
->update(str_repeat("\0", 0x10 - $aadlen & 0xf));
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc($cipher[0] . str_repeat("\0", 63), $st
->getCombinedNonce(), $st
->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(1));
$tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
$block[0] = $cipher[0];
$auth
->update($block);
$auth
->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen));
$auth
->update(str_repeat("\0", 0x10 - 64 + $msglen & 0xf));
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
$auth
->update($slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
$auth
->update($slen);
$mac = $auth
->finish();
$stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16);
if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
return false;
}
$out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen), $st
->getCombinedNonce(), $st
->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(2));
$st
->xorNonce($mac);
$st
->incrementCounter();
$state = $st
->toString();
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
if ($rekey || $st
->needsRekey()) {
self::secretstream_xchacha20poly1305_rekey($state);
}
return array(
$out,
$tag,
);
}
public static function secretstream_xchacha20poly1305_rekey(&$state) {
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
$new_key_and_inonce = $st
->getKey();
$new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st
->getNonce(), 0, 8);
$st
->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc($new_key_and_inonce, $st
->getCombinedNonce(), $st
->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(0)));
$st
->counterReset();
$state = $st
->toString();
}
public static function sign_detached($message, $sk) {
return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk);
}
public static function sign($message, $sk) {
return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
}
public static function sign_open($signedMessage, $pk) {
return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk);
}
public static function sign_verify_detached($signature, $message, $pk) {
return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk);
}
}