D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
mybf1
/
www
/
mentol.bf1.my
/
Filename :
src.tar
back
Copy
Compat.php 0000644 00000440246 15120356514 0006514 0 ustar 00 <?php /** * Libsodium compatibility layer * * This is the only class you should be interfacing with, as a user of * sodium_compat. * * If the PHP extension for libsodium is installed, it will always use that * instead of our implementations. You get better performance and stronger * guarantees against side-channels that way. * * However, if your users don't have the PHP extension installed, we offer a * compatible interface here. It will give you the correct results as if the * PHP extension was installed. It won't be as fast, of course. * * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * * * * Until audited, this is probably not safe to use! DANGER WILL ROBINSON * * * * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * */ if (class_exists('ParagonIE_Sodium_Compat', false)) { return; } class ParagonIE_Sodium_Compat { /** * This parameter prevents the use of the PECL extension. * It should only be used for unit testing. * * @var bool */ public static $disableFallbackForUnitTests = false; /** * Use fast multiplication rather than our constant-time multiplication * implementation. Can be enabled at runtime. Only enable this if you * are absolutely certain that there is no timing leak on your platform. * * @var bool */ public static $fastMult = false; const LIBRARY_MAJOR_VERSION = 9; const LIBRARY_MINOR_VERSION = 1; const LIBRARY_VERSION_MAJOR = 9; const LIBRARY_VERSION_MINOR = 1; const VERSION_STRING = 'polyfill-1.0.8'; // From libsodium const BASE64_VARIANT_ORIGINAL = 1; const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3; const BASE64_VARIANT_URLSAFE = 5; const BASE64_VARIANT_URLSAFE_NO_PADDING = 7; const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32; const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0; const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12; const CRYPTO_AEAD_AES256GCM_ABYTES = 16; const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32; const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0; const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8; const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16; const CRYPTO_AUTH_BYTES = 32; const CRYPTO_AUTH_KEYBYTES = 32; const CRYPTO_BOX_SEALBYTES = 16; const CRYPTO_BOX_SECRETKEYBYTES = 32; const CRYPTO_BOX_PUBLICKEYBYTES = 32; const CRYPTO_BOX_KEYPAIRBYTES = 64; const CRYPTO_BOX_MACBYTES = 16; const CRYPTO_BOX_NONCEBYTES = 24; const CRYPTO_BOX_SEEDBYTES = 32; const CRYPTO_CORE_RISTRETTO255_BYTES = 32; const CRYPTO_CORE_RISTRETTO255_SCALARBYTES = 32; const CRYPTO_CORE_RISTRETTO255_HASHBYTES = 64; const CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES = 64; const CRYPTO_KDF_BYTES_MIN = 16; const CRYPTO_KDF_BYTES_MAX = 64; const CRYPTO_KDF_CONTEXTBYTES = 8; const CRYPTO_KDF_KEYBYTES = 32; const CRYPTO_KX_BYTES = 32; const CRYPTO_KX_PRIMITIVE = 'x25519blake2b'; const CRYPTO_KX_SEEDBYTES = 32; const CRYPTO_KX_KEYPAIRBYTES = 64; const CRYPTO_KX_PUBLICKEYBYTES = 32; const CRYPTO_KX_SECRETKEYBYTES = 32; const CRYPTO_KX_SESSIONKEYBYTES = 32; const CRYPTO_GENERICHASH_BYTES = 32; const CRYPTO_GENERICHASH_BYTES_MIN = 16; const CRYPTO_GENERICHASH_BYTES_MAX = 64; const CRYPTO_GENERICHASH_KEYBYTES = 32; const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16; const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64; const CRYPTO_PWHASH_SALTBYTES = 16; const CRYPTO_PWHASH_STRPREFIX = '$argon2id$'; const CRYPTO_PWHASH_ALG_ARGON2I13 = 1; const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2; const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432; const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4; const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728; const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6; const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912; const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$'; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824; const CRYPTO_SCALARMULT_BYTES = 32; const CRYPTO_SCALARMULT_SCALARBYTES = 32; const CRYPTO_SCALARMULT_RISTRETTO255_BYTES = 32; const CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES = 32; const CRYPTO_SHORTHASH_BYTES = 8; const CRYPTO_SHORTHASH_KEYBYTES = 16; const CRYPTO_SECRETBOX_KEYBYTES = 32; const CRYPTO_SECRETBOX_MACBYTES = 16; const CRYPTO_SECRETBOX_NONCEBYTES = 24; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80; const CRYPTO_SIGN_BYTES = 64; const CRYPTO_SIGN_SEEDBYTES = 32; const CRYPTO_SIGN_PUBLICKEYBYTES = 32; const CRYPTO_SIGN_SECRETKEYBYTES = 64; const CRYPTO_SIGN_KEYPAIRBYTES = 96; const CRYPTO_STREAM_KEYBYTES = 32; const CRYPTO_STREAM_NONCEBYTES = 24; const CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32; const CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24; /** * Add two numbers (little-endian unsigned), storing the value in the first * parameter. * * This mutates $val. * * @param string $val * @param string $addv * @return void * @throws SodiumException */ public static function add(&$val, $addv) { $val_len = ParagonIE_Sodium_Core_Util::strlen($val); $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); if ($val_len !== $addv_len) { throw new SodiumException('values must have the same length'); } $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); $c = 0; for ($i = 0; $i < $val_len; $i++) { $c += ($A[$i] + $B[$i]); $A[$i] = ($c & 0xff); $c >>= 8; } $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); } /** * @param string $encoded * @param int $variant * @param string $ignore * @return string * @throws SodiumException */ public static function base642bin($encoded, $variant, $ignore = '') { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1); /** @var string $encoded */ $encoded = (string) $encoded; if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) { return ''; } // Just strip before decoding if (!empty($ignore)) { $encoded = str_replace($ignore, '', $encoded); } try { switch ($variant) { case self::BASE64_VARIANT_ORIGINAL: return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true); case self::BASE64_VARIANT_ORIGINAL_NO_PADDING: return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false); case self::BASE64_VARIANT_URLSAFE: return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true); case self::BASE64_VARIANT_URLSAFE_NO_PADDING: return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false); default: throw new SodiumException('invalid base64 variant identifier'); } } catch (Exception $ex) { if ($ex instanceof SodiumException) { throw $ex; } throw new SodiumException('invalid base64 string'); } } /** * @param string $decoded * @param int $variant * @return string * @throws SodiumException */ public static function bin2base64($decoded, $variant) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1); /** @var string $decoded */ $decoded = (string) $decoded; if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) { return ''; } switch ($variant) { case self::BASE64_VARIANT_ORIGINAL: return ParagonIE_Sodium_Core_Base64_Original::encode($decoded); case self::BASE64_VARIANT_ORIGINAL_NO_PADDING: return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded); case self::BASE64_VARIANT_URLSAFE: return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded); case self::BASE64_VARIANT_URLSAFE_NO_PADDING: return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded); default: throw new SodiumException('invalid base64 variant identifier'); } } /** * Cache-timing-safe implementation of bin2hex(). * * @param string $string A string (probably raw binary) * @return string A hexadecimal-encoded string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function bin2hex($string) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); if (self::useNewSodiumAPI()) { return (string) sodium_bin2hex($string); } if (self::use_fallback('bin2hex')) { return (string) call_user_func('\\Sodium\\bin2hex', $string); } return ParagonIE_Sodium_Core_Util::bin2hex($string); } /** * Compare two strings, in constant-time. * Compared to memcmp(), compare() is more useful for sorting. * * @param string $left The left operand; must be a string * @param string $right The right operand; must be a string * @return int If < 0 if the left operand is less than the right * If = 0 if both strings are equal * If > 0 if the right operand is less than the left * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function compare($left, $right) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); if (self::useNewSodiumAPI()) { return (int) sodium_compare($left, $right); } if (self::use_fallback('compare')) { return (int) call_user_func('\\Sodium\\compare', $left, $right); } return ParagonIE_Sodium_Core_Util::compare($left, $right); } /** * Is AES-256-GCM even available to use? * * @return bool * @psalm-suppress UndefinedFunction * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aes256gcm_is_available() { if (self::useNewSodiumAPI()) { return sodium_crypto_aead_aes256gcm_is_available(); } if (self::use_fallback('crypto_aead_aes256gcm_is_available')) { return call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available'); } if (PHP_VERSION_ID < 70100) { // OpenSSL doesn't support AEAD before 7.1.0 return false; } if (!is_callable('openssl_encrypt') || !is_callable('openssl_decrypt')) { // OpenSSL isn't installed return false; } return (bool) in_array('aes-256-gcm', openssl_get_cipher_methods()); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * AES-256-GCM * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string|bool The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aes256gcm_decrypt( $ciphertext = '', $assocData = '', $nonce = '', $key = '' ) { if (!self::crypto_aead_aes256gcm_is_available()) { throw new SodiumException('AES-256-GCM is not available'); } ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_AES256GCM_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_AES256GCM_ABYTES long'); } if (!is_callable('openssl_decrypt')) { throw new SodiumException('The OpenSSL extension is not installed, or openssl_decrypt() is not available'); } /** @var string $ctext */ $ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0, -self::CRYPTO_AEAD_AES256GCM_ABYTES); /** @var string $authTag */ $authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext, -self::CRYPTO_AEAD_AES256GCM_ABYTES, 16); return openssl_decrypt( $ctext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $authTag, $assocData ); } /** * Authenticated Encryption with Associated Data: Encryption * * Algorithm: * AES-256-GCM * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte GCM message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_aes256gcm_encrypt( $plaintext = '', $assocData = '', $nonce = '', $key = '' ) { if (!self::crypto_aead_aes256gcm_is_available()) { throw new SodiumException('AES-256-GCM is not available'); } ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); } if (!is_callable('openssl_encrypt')) { throw new SodiumException('The OpenSSL extension is not installed, or openssl_encrypt() is not available'); } $authTag = ''; $ciphertext = openssl_encrypt( $plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $authTag, $assocData ); return $ciphertext . $authTag; } /** * Return a secure random key for use with the AES-256-GCM * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_aes256gcm_keygen() { return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * ChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_chacha20poly1305_decrypt( $ciphertext = '', $assocData = '', $nonce = '', $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) { return call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_decrypt', $ciphertext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data * * Algorithm: * ChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_chacha20poly1305_encrypt( $plaintext = '', $assocData = '', $nonce = '', $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) { return (string) call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_encrypt', $plaintext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * ChaCha20-Poly1305 * * IETF mode uses a 96-bit random nonce with a 32-bit counter. * Regular mode uses a 64-bit random nonce with a 64-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 12 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_chacha20poly1305_ietf_decrypt( $ciphertext = '', $assocData = '', $nonce = '', $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) { return call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt', $ciphertext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the ChaCha20-Poly1305 * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_chacha20poly1305_keygen() { return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES); } /** * Authenticated Encryption with Associated Data * * Algorithm: * ChaCha20-Poly1305 * * IETF mode uses a 96-bit random nonce with a 32-bit counter. * Regular mode uses a 64-bit random nonce with a 64-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_chacha20poly1305_ietf_encrypt( $plaintext = '', $assocData = '', $nonce = '', $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) { return (string) call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt', $plaintext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the ChaCha20-Poly1305 * symmetric AEAD interface. (IETF version) * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_chacha20poly1305_ietf_keygen() { return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * XChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * @param bool $dontFallback Don't fallback to ext/sodium * * @return string|bool The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_xchacha20poly1305_ietf_decrypt( $ciphertext = '', $assocData = '', $nonce = '', $key = '', $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } else { $assocData = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) { return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data * * Algorithm: * XChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * @param bool $dontFallback Don't fallback to ext/sodium * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_xchacha20poly1305_ietf_encrypt( $plaintext = '', $assocData = '', $nonce = '', $key = '', $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } else { $assocData = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) { return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the XChaCha20-Poly1305 * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_xchacha20poly1305_ietf_keygen() { return random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES); } /** * Authenticate a message. Uses symmetric-key cryptography. * * Algorithm: * HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits. * Not to be confused with HMAC-SHA-512/256 which would use the * SHA-512/256 hash function (uses different initial parameters * but still truncates to 256 bits to sidestep length-extension * attacks). * * @param string $message Message to be authenticated * @param string $key Symmetric authentication key * @return string Message authentication code * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_auth($message, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_auth($message, $key); } if (self::use_fallback('crypto_auth')) { return (string) call_user_func('\\Sodium\\crypto_auth', $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::auth($message, $key); } return ParagonIE_Sodium_Crypto::auth($message, $key); } /** * @return string * @throws Exception * @throws Error */ public static function crypto_auth_keygen() { return random_bytes(self::CRYPTO_AUTH_KEYBYTES); } /** * Verify the MAC of a message previously authenticated with crypto_auth. * * @param string $mac Message authentication code * @param string $message Message whose authenticity you are attempting to * verify (with a given MAC and key) * @param string $key Symmetric authentication key * @return bool TRUE if authenticated, FALSE otherwise * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_auth_verify($mac, $message, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) { throw new SodiumException('Argument 1 must be CRYPTO_AUTH_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_auth_verify($mac, $message, $key); } if (self::use_fallback('crypto_auth_verify')) { return (bool) call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key); } return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key); } /** * Authenticated asymmetric-key encryption. Both the sender and recipient * may decrypt messages. * * Algorithm: X25519-XSalsa20-Poly1305. * X25519: Elliptic-Curve Diffie Hellman over Curve25519. * XSalsa20: Extended-nonce variant of salsa20. * Poyl1305: Polynomial MAC for one-time message authentication. * * @param string $plaintext The message to be encrypted * @param string $nonce A Number to only be used Once; must be 24 bytes * @param string $keypair Your secret key and your recipient's public key * @return string Ciphertext with 16-byte Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box($plaintext, $nonce, $keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box($plaintext, $nonce, $keypair); } if (self::use_fallback('crypto_box')) { return (string) call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair); } return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair); } /** * Anonymous public-key encryption. Only the recipient may decrypt messages. * * Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box. * The sender's X25519 keypair is ephemeral. * Nonce is generated from the BLAKE2b hash of both public keys. * * This provides ciphertext integrity. * * @param string $plaintext Message to be sealed * @param string $publicKey Your recipient's public key * @return string Sealed message that only your recipient can * decrypt * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_seal($plaintext, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_seal($plaintext, $publicKey); } if (self::use_fallback('crypto_box_seal')) { return (string) call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey); } return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey); } /** * Opens a message encrypted with crypto_box_seal(). Requires * the recipient's keypair (sk || pk) to decrypt successfully. * * This validates ciphertext integrity. * * @param string $ciphertext Sealed message to be opened * @param string $keypair Your crypto_box keypair * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_box_seal_open($ciphertext, $keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_box_seal_open($ciphertext, $keypair); } if (self::use_fallback('crypto_box_seal_open')) { return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair); } return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair); } /** * Generate a new random X25519 keypair. * * @return string A 64-byte string; the first 32 are your secret key, while * the last 32 are your public key. crypto_box_secretkey() * and crypto_box_publickey() exist to separate them so you * don't accidentally get them mixed up! * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_keypair() { if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_keypair(); } if (self::use_fallback('crypto_box_keypair')) { return (string) call_user_func('\\Sodium\\crypto_box_keypair'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_keypair(); } return ParagonIE_Sodium_Crypto::box_keypair(); } /** * Combine two keys into a keypair for use in library methods that expect * a keypair. This doesn't necessarily have to be the same person's keys. * * @param string $secretKey Secret key * @param string $publicKey Public key * @return string Keypair * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) { return (string) call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } /** * Decrypt a message previously encrypted with crypto_box(). * * @param string $ciphertext Encrypted message * @param string $nonce Number to only be used Once; must be 24 bytes * @param string $keypair Your secret key and the sender's public key * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_box_open($ciphertext, $nonce, $keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_box_open($ciphertext, $nonce, $keypair); } if (self::use_fallback('crypto_box_open')) { return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair); } return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair); } /** * Extract the public key from a crypto_box keypair. * * @param string $keypair Keypair containing secret and public key * @return string Your crypto_box public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_publickey($keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_publickey($keypair); } if (self::use_fallback('crypto_box_publickey')) { return (string) call_user_func('\\Sodium\\crypto_box_publickey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_publickey($keypair); } return ParagonIE_Sodium_Crypto::box_publickey($keypair); } /** * Calculate the X25519 public key from a given X25519 secret key. * * @param string $secretKey Any X25519 secret key * @return string The corresponding X25519 public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_publickey_from_secretkey($secretKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_publickey_from_secretkey($secretKey); } if (self::use_fallback('crypto_box_publickey_from_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey); } return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey); } /** * Extract the secret key from a crypto_box keypair. * * @param string $keypair * @return string Your crypto_box secret key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_secretkey($keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_secretkey($keypair); } if (self::use_fallback('crypto_box_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_box_secretkey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_secretkey($keypair); } return ParagonIE_Sodium_Crypto::box_secretkey($keypair); } /** * Generate an X25519 keypair from a seed. * * @param string $seed * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress UndefinedFunction */ public static function crypto_box_seed_keypair($seed) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_seed_keypair($seed); } if (self::use_fallback('crypto_box_seed_keypair')) { return (string) call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seed_keypair($seed); } return ParagonIE_Sodium_Crypto::box_seed_keypair($seed); } /** * Calculates a BLAKE2b hash, with an optional key. * * @param string $message The message to be hashed * @param string|null $key If specified, must be a string between 16 * and 64 bytes long * @param int $length Output length in bytes; must be between 16 * and 64 (default = 32) * @return string Raw binary * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash($message, $key = '', $length = self::CRYPTO_GENERICHASH_BYTES) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3); /* Input validation: */ if (!empty($key)) { if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_generichash($message, $key, $length); } if (self::use_fallback('crypto_generichash')) { return (string) call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length); } return ParagonIE_Sodium_Crypto::generichash($message, $key, $length); } /** * Get the final BLAKE2b hash output for a given context. * * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). * @param int $length Hash output size. * @return string Final BLAKE2b hash. * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress ReferenceConstraintViolation * @psalm-suppress ConflictingReferenceConstraint */ public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); if (self::useNewSodiumAPI()) { return sodium_crypto_generichash_final($ctx, $length); } if (self::use_fallback('crypto_generichash_final')) { $func = '\\Sodium\\crypto_generichash_final'; return (string) $func($ctx, $length); } if ($length < 1) { try { self::memzero($ctx); } catch (SodiumException $ex) { unset($ctx); } return ''; } if (PHP_INT_SIZE === 4) { $result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length); } else { $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length); } try { self::memzero($ctx); } catch (SodiumException $ex) { unset($ctx); } return $result; } /** * Initialize a BLAKE2b hashing context, for use in a streaming interface. * * @param string|null $key If specified must be a string between 16 and 64 bytes * @param int $length The size of the desired hash output * @return string A BLAKE2 hashing context, encoded as a string * (To be 100% compatible with ext/libsodium) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash_init($key = '', $length = self::CRYPTO_GENERICHASH_BYTES) { /* Type checks: */ if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); /* Input validation: */ if (!empty($key)) { if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (self::useNewSodiumAPI()) { return sodium_crypto_generichash_init($key, $length); } if (self::use_fallback('crypto_generichash_init')) { return (string) call_user_func('\\Sodium\\crypto_generichash_init', $key, $length); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash_init($key, $length); } return ParagonIE_Sodium_Crypto::generichash_init($key, $length); } /** * Initialize a BLAKE2b hashing context, for use in a streaming interface. * * @param string|null $key If specified must be a string between 16 and 64 bytes * @param int $length The size of the desired hash output * @param string $salt Salt (up to 16 bytes) * @param string $personal Personalization string (up to 16 bytes) * @return string A BLAKE2 hashing context, encoded as a string * (To be 100% compatible with ext/libsodium) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash_init_salt_personal( $key = '', $length = self::CRYPTO_GENERICHASH_BYTES, $salt = '', $personal = '' ) { /* Type checks: */ if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4); $salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT); $personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT); /* Input validation: */ if (!empty($key)) { /* if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } */ if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal); } return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal); } /** * Update a BLAKE2b hashing context with additional data. * * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). * $ctx is passed by reference and gets updated in-place. * @param-out string $ctx * @param string $message The message to append to the existing hash state. * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress ReferenceConstraintViolation */ public static function crypto_generichash_update(&$ctx, $message) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); if (self::useNewSodiumAPI()) { sodium_crypto_generichash_update($ctx, $message); return; } if (self::use_fallback('crypto_generichash_update')) { $func = '\\Sodium\\crypto_generichash_update'; $func($ctx, $message); return; } if (PHP_INT_SIZE === 4) { $ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message); } else { $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message); } } /** * @return string * @throws Exception * @throws Error */ public static function crypto_generichash_keygen() { return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES); } /** * @param int $subkey_len * @param int $subkey_id * @param string $context * @param string $key * @return string * @throws SodiumException */ public static function crypto_kdf_derive_from_key( $subkey_len, $subkey_id, $context, $key ) { ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); $subkey_id = (int) $subkey_id; $subkey_len = (int) $subkey_len; $context = (string) $context; $key = (string) $key; if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) { throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN'); } if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) { throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX'); } if ($subkey_id < 0) { throw new SodiumException('subkey_id cannot be negative'); } if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) { throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) { throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes'); } $salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id); $state = self::crypto_generichash_init_salt_personal( $key, $subkey_len, $salt, $context ); return self::crypto_generichash_final($state, $subkey_len); } /** * @return string * @throws Exception * @throws Error */ public static function crypto_kdf_keygen() { return random_bytes(self::CRYPTO_KDF_KEYBYTES); } /** * Perform a key exchange, between a designated client and a server. * * Typically, you would designate one machine to be the client and the * other to be the server. The first two keys are what you'd expect for * scalarmult() below, but the latter two public keys don't swap places. * * | ALICE | BOB | * | Client | Server | * |--------------------------------|-------------------------------------| * | shared = crypto_kx( | shared = crypto_kx( | * | alice_sk, | bob_sk, | <- contextual * | bob_pk, | alice_pk, | <- contextual * | alice_pk, | alice_pk, | <----- static * | bob_pk | bob_pk | <----- static * | ) | ) | * * They are used along with the scalarmult product to generate a 256-bit * BLAKE2b hash unique to the client and server keys. * * @param string $my_secret * @param string $their_public * @param string $client_public * @param string $server_public * @param bool $dontFallback * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_kx($my_secret, $their_public, $client_public, $server_public, $dontFallback = false) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_kx')) { return (string) sodium_crypto_kx( $my_secret, $their_public, $client_public, $server_public ); } } if (self::use_fallback('crypto_kx')) { return (string) call_user_func( '\\Sodium\\crypto_kx', $my_secret, $their_public, $client_public, $server_public ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::keyExchange( $my_secret, $their_public, $client_public, $server_public ); } return ParagonIE_Sodium_Crypto::keyExchange( $my_secret, $their_public, $client_public, $server_public ); } /** * @param string $seed * @return string * @throws SodiumException */ public static function crypto_kx_seed_keypair($seed) { ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); $seed = (string) $seed; if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) { throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes'); } $sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES); $pk = self::crypto_scalarmult_base($sk); return $sk . $pk; } /** * @return string * @throws Exception */ public static function crypto_kx_keypair() { $sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES); $pk = self::crypto_scalarmult_base($sk); return $sk . $pk; } /** * @param string $keypair * @param string $serverPublicKey * @return array{0: string, 1: string} * @throws SodiumException */ public static function crypto_kx_client_session_keys($keypair, $serverPublicKey) { ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2); $keypair = (string) $keypair; $serverPublicKey = (string) $serverPublicKey; if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); } $sk = self::crypto_kx_secretkey($keypair); $pk = self::crypto_kx_publickey($keypair); $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey)); self::crypto_generichash_update($h, $pk); self::crypto_generichash_update($h, $serverPublicKey); $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); return array( ParagonIE_Sodium_Core_Util::substr( $sessionKeys, 0, self::CRYPTO_KX_SESSIONKEYBYTES ), ParagonIE_Sodium_Core_Util::substr( $sessionKeys, self::CRYPTO_KX_SESSIONKEYBYTES, self::CRYPTO_KX_SESSIONKEYBYTES ) ); } /** * @param string $keypair * @param string $clientPublicKey * @return array{0: string, 1: string} * @throws SodiumException */ public static function crypto_kx_server_session_keys($keypair, $clientPublicKey) { ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2); $keypair = (string) $keypair; $clientPublicKey = (string) $clientPublicKey; if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); } $sk = self::crypto_kx_secretkey($keypair); $pk = self::crypto_kx_publickey($keypair); $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey)); self::crypto_generichash_update($h, $clientPublicKey); self::crypto_generichash_update($h, $pk); $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); return array( ParagonIE_Sodium_Core_Util::substr( $sessionKeys, self::CRYPTO_KX_SESSIONKEYBYTES, self::CRYPTO_KX_SESSIONKEYBYTES ), ParagonIE_Sodium_Core_Util::substr( $sessionKeys, 0, self::CRYPTO_KX_SESSIONKEYBYTES ) ); } /** * @param string $kp * @return string * @throws SodiumException */ public static function crypto_kx_secretkey($kp) { return ParagonIE_Sodium_Core_Util::substr( $kp, 0, self::CRYPTO_KX_SECRETKEYBYTES ); } /** * @param string $kp * @return string * @throws SodiumException */ public static function crypto_kx_publickey($kp) { return ParagonIE_Sodium_Core_Util::substr( $kp, self::CRYPTO_KX_SECRETKEYBYTES, self::CRYPTO_KX_PUBLICKEYBYTES ); } /** * @param int $outlen * @param string $passwd * @param string $salt * @param int $opslimit * @param int $memlimit * @param int|null $alg * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg = null) { ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); if (self::useNewSodiumAPI()) { if (!is_null($alg)) { ParagonIE_Sodium_Core_Util::declareScalarType($alg, 'int', 6); return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg); } return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit); } if (self::use_fallback('crypto_pwhash')) { return (string) call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * !Exclusive to sodium_compat! * * This returns TRUE if the native crypto_pwhash API is available by libsodium. * This returns FALSE if only sodium_compat is available. * * @return bool */ public static function crypto_pwhash_is_available() { if (self::useNewSodiumAPI()) { return true; } if (self::use_fallback('crypto_pwhash')) { return true; } return false; } /** * @param string $passwd * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash_str($passwd, $opslimit, $memlimit) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); if (self::useNewSodiumAPI()) { return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit); } if (self::use_fallback('crypto_pwhash_str')) { return (string) call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * Do we need to rehash this password? * * @param string $hash * @param int $opslimit * @param int $memlimit * @return bool * @throws SodiumException */ public static function crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit) { ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); // Just grab the first 4 pieces. $pieces = explode('$', (string) $hash); $prefix = implode('$', array_slice($pieces, 0, 4)); // Rebuild the expected header. /** @var int $ops */ $ops = (int) $opslimit; /** @var int $mem */ $mem = (int) $memlimit >> 10; $encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1'; // Do they match? If so, we don't need to rehash, so return false. return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix); } /** * @param string $passwd * @param string $hash * @return bool * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash_str_verify($passwd, $hash) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash); } if (self::use_fallback('crypto_pwhash_str_verify')) { return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * @param int $outlen * @param string $passwd * @param string $salt * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit) { ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_pwhash_scryptsalsa208sha256( (int) $outlen, (string) $passwd, (string) $salt, (int) $opslimit, (int) $memlimit ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { return (string) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256', (int) $outlen, (string) $passwd, (string) $salt, (int) $opslimit, (int) $memlimit ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * !Exclusive to sodium_compat! * * This returns TRUE if the native crypto_pwhash API is available by libsodium. * This returns FALSE if only sodium_compat is available. * * @return bool */ public static function crypto_pwhash_scryptsalsa208sha256_is_available() { if (self::useNewSodiumAPI()) { return true; } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { return true; } return false; } /** * @param string $passwd * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str( (string) $passwd, (int) $opslimit, (int) $memlimit ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) { return (string) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str', (string) $passwd, (int) $opslimit, (int) $memlimit ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * @param string $passwd * @param string $hash * @return bool * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_pwhash_scryptsalsa208sha256_str_verify( (string) $passwd, (string) $hash ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) { return (bool) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify', (string) $passwd, (string) $hash ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * Calculate the shared secret between your secret key and your * recipient's public key. * * Algorithm: X25519 (ECDH over Curve25519) * * @param string $secretKey * @param string $publicKey * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_scalarmult($secretKey, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_scalarmult($secretKey, $publicKey); } if (self::use_fallback('crypto_scalarmult')) { return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey); } /* Output validation: Forbid all-zero keys */ if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { throw new SodiumException('Zero secret key is not allowed'); } if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) { throw new SodiumException('Zero public key is not allowed'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey); } return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey); } /** * Calculate an X25519 public key from an X25519 secret key. * * @param string $secretKey * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress TooFewArguments * @psalm-suppress MixedArgument */ public static function crypto_scalarmult_base($secretKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_scalarmult_base($secretKey); } if (self::use_fallback('crypto_scalarmult_base')) { return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey); } if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { throw new SodiumException('Zero secret key is not allowed'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey); } return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey); } /** * Authenticated symmetric-key encryption. * * Algorithm: XSalsa20-Poly1305 * * @param string $plaintext The message you're encrypting * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Ciphertext with Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox($plaintext, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_secretbox($plaintext, $nonce, $key); } if (self::use_fallback('crypto_secretbox')) { return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key); } /** * Decrypts a message previously encrypted with crypto_secretbox(). * * @param string $ciphertext Ciphertext with Poly1305 MAC * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_secretbox_open($ciphertext, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_secretbox_open($ciphertext, $nonce, $key); } if (self::use_fallback('crypto_secretbox_open')) { return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key); } /** * Return a secure random key for use with crypto_secretbox * * @return string * @throws Exception * @throws Error */ public static function crypto_secretbox_keygen() { return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES); } /** * Authenticated symmetric-key encryption. * * Algorithm: XChaCha20-Poly1305 * * @param string $plaintext The message you're encrypting * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Ciphertext with Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key); } /** * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305(). * * @param string $ciphertext Ciphertext with Poly1305 MAC * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); } /** * @param string $key * @return array<int, string> Returns a state and a header. * @throws Exception * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_init_push($key) { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key); } /** * @param string $header * @param string $key * @return string Returns a state. * @throws Exception */ public static function crypto_secretstream_xchacha20poly1305_init_pull($header, $key) { if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) { throw new SodiumException( 'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes' ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header); } /** * @param string $state * @param string $msg * @param string $aad * @param int $tag * @return string * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push( $state, $msg, $aad, $tag ); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push( $state, $msg, $aad, $tag ); } /** * @param string $state * @param string $msg * @param string $aad * @return bool|array{0: string, 1: int} * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad = '') { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull( $state, $msg, $aad ); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull( $state, $msg, $aad ); } /** * @return string * @throws Exception */ public static function crypto_secretstream_xchacha20poly1305_keygen() { return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES); } /** * @param string $state * @return void * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_rekey(&$state) { if (PHP_INT_SIZE === 4) { ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state); } else { ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state); } } /** * Calculates a SipHash-2-4 hash of a message for a given key. * * @param string $message Input message * @param string $key SipHash-2-4 key * @return string Hash * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_shorthash($message, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_shorthash($message, $key); } if (self::use_fallback('crypto_shorthash')) { return (string) call_user_func('\\Sodium\\crypto_shorthash', $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key); } return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key); } /** * Return a secure random key for use with crypto_shorthash * * @return string * @throws Exception * @throws Error */ public static function crypto_shorthash_keygen() { return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES); } /** * Returns a signed message. You probably want crypto_sign_detached() * instead, which only returns the signature. * * Algorithm: Ed25519 (EdDSA over Curve25519) * * @param string $message Message to be signed. * @param string $secretKey Secret signing key. * @return string Signed message (signature is prefixed). * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_sign($message, $secretKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign($message, $secretKey); } if (self::use_fallback('crypto_sign')) { return (string) call_user_func('\\Sodium\\crypto_sign', $message, $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign($message, $secretKey); } return ParagonIE_Sodium_Crypto::sign($message, $secretKey); } /** * Validates a signed message then returns the message. * * @param string $signedMessage A signed message * @param string $publicKey A public key * @return string The original message (if the signature is * valid for this public key) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_sign_open($signedMessage, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_sign_open($signedMessage, $publicKey); } if (self::use_fallback('crypto_sign_open')) { return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey); } return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey); } /** * Generate a new random Ed25519 keypair. * * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_sign_keypair() { if (self::useNewSodiumAPI()) { return sodium_crypto_sign_keypair(); } if (self::use_fallback('crypto_sign_keypair')) { return (string) call_user_func('\\Sodium\\crypto_sign_keypair'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::keypair(); } return ParagonIE_Sodium_Core_Ed25519::keypair(); } /** * @param string $sk * @param string $pk * @return string * @throws SodiumException */ public static function crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk) { ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1); $sk = (string) $sk; $pk = (string) $pk; if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk); } return $sk . $pk; } /** * Generate an Ed25519 keypair from a seed. * * @param string $seed Input seed * @return string Keypair * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_seed_keypair($seed) { ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); if (self::useNewSodiumAPI()) { return sodium_crypto_sign_seed_keypair($seed); } if (self::use_fallback('crypto_sign_keypair')) { return (string) call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed); } $publicKey = ''; $secretKey = ''; if (PHP_INT_SIZE === 4) { ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed); } else { ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed); } return $secretKey . $publicKey; } /** * Extract an Ed25519 public key from an Ed25519 keypair. * * @param string $keypair Keypair * @return string Public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_publickey($keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_publickey($keypair); } if (self::use_fallback('crypto_sign_publickey')) { return (string) call_user_func('\\Sodium\\crypto_sign_publickey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair); } return ParagonIE_Sodium_Core_Ed25519::publickey($keypair); } /** * Calculate an Ed25519 public key from an Ed25519 secret key. * * @param string $secretKey Your Ed25519 secret key * @return string The corresponding Ed25519 public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_publickey_from_secretkey($secretKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_publickey_from_secretkey($secretKey); } if (self::use_fallback('crypto_sign_publickey_from_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey); } return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey); } /** * Extract an Ed25519 secret key from an Ed25519 keypair. * * @param string $keypair Keypair * @return string Secret key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_secretkey($keypair) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_secretkey($keypair); } if (self::use_fallback('crypto_sign_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair); } return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair); } /** * Calculate the Ed25519 signature of a message and return ONLY the signature. * * Algorithm: Ed25519 (EdDSA over Curve25519) * * @param string $message Message to be signed * @param string $secretKey Secret signing key * @return string Digital signature * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_detached($message, $secretKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_detached($message, $secretKey); } if (self::use_fallback('crypto_sign_detached')) { return (string) call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey); } return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey); } /** * Verify the Ed25519 signature of a message. * * @param string $signature Digital sginature * @param string $message Message to be verified * @param string $publicKey Public key * @return bool TRUE if this signature is good for this public key; * FALSE otherwise * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_verify_detached($signature, $message, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_verify_detached($signature, $message, $publicKey); } if (self::use_fallback('crypto_sign_verify_detached')) { return (bool) call_user_func( '\\Sodium\\crypto_sign_verify_detached', $signature, $message, $publicKey ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey); } return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey); } /** * Convert an Ed25519 public key to a Curve25519 public key * * @param string $pk * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_ed25519_pk_to_curve25519($pk) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($pk) < self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { if (is_callable('crypto_sign_ed25519_pk_to_curve25519')) { return (string) sodium_crypto_sign_ed25519_pk_to_curve25519($pk); } } if (self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) { return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519', $pk); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::pk_to_curve25519($pk); } return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk); } /** * Convert an Ed25519 secret key to a Curve25519 secret key * * @param string $sk * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_ed25519_sk_to_curve25519($sk) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.'); } if (self::useNewSodiumAPI()) { if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) { return sodium_crypto_sign_ed25519_sk_to_curve25519($sk); } } if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) { return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk); } $h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true); $h[0] = ParagonIE_Sodium_Core_Util::intToChr( ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248 ); $h[31] = ParagonIE_Sodium_Core_Util::intToChr( (ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64 ); return ParagonIE_Sodium_Core_Util::substr($h, 0, 32); } /** * Expand a key and nonce into a keystream of pseudorandom bytes. * * @param int $len Number of bytes desired * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key XSalsa20 key * @return string Pseudorandom stream that can be XORed with messages * to provide encryption (but not authentication; see * Poly1305 or crypto_auth() for that, which is not * optional for security) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream($len, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_stream($len, $nonce, $key); } if (self::use_fallback('crypto_stream')) { return (string) call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key); } return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key); } /** * DANGER! UNAUTHENTICATED ENCRYPTION! * * Unless you are following expert advice, do not used this feature. * * Algorithm: XSalsa20 * * This DOES NOT provide ciphertext integrity. * * @param string $message Plaintext message * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key Encryption key * @return string Encrypted text which is vulnerable to chosen- * ciphertext attacks unless you implement some * other mitigation to the ciphertext (i.e. * Encrypt then MAC) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xor($message, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_stream_xor($message, $nonce, $key); } if (self::use_fallback('crypto_stream_xor')) { return (string) call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key); } return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key); } /** * Return a secure random key for use with crypto_stream * * @return string * @throws Exception * @throws Error */ public static function crypto_stream_keygen() { return random_bytes(self::CRYPTO_STREAM_KEYBYTES); } /** * Expand a key and nonce into a keystream of pseudorandom bytes. * * @param int $len Number of bytes desired * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key XChaCha20 key * @param bool $dontFallback * @return string Pseudorandom stream that can be XORed with messages * to provide encryption (but not authentication; see * Poly1305 or crypto_auth() for that, which is not * optional for security) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xchacha20($len, $nonce, $key, $dontFallback = false) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_STREAM_XCHACHA20_KEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_stream_xchacha20($len, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XChaCha20::stream($len, $nonce, $key); } return ParagonIE_Sodium_Core_XChaCha20::stream($len, $nonce, $key); } /** * DANGER! UNAUTHENTICATED ENCRYPTION! * * Unless you are following expert advice, do not used this feature. * * Algorithm: XChaCha20 * * This DOES NOT provide ciphertext integrity. * * @param string $message Plaintext message * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key Encryption key * @return string Encrypted text which is vulnerable to chosen- * ciphertext attacks unless you implement some * other mitigation to the ciphertext (i.e. * Encrypt then MAC) * @param bool $dontFallback * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xchacha20_xor($message, $nonce, $key, $dontFallback = false) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_stream_xchacha20_xor($message, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key); } return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key); } /** * Return a secure random key for use with crypto_stream_xchacha20 * * @return string * @throws Exception * @throws Error */ public static function crypto_stream_xchacha20_keygen() { return random_bytes(self::CRYPTO_STREAM_XCHACHA20_KEYBYTES); } /** * Cache-timing-safe implementation of hex2bin(). * * @param string $string Hexadecimal string * @return string Raw binary string * @throws SodiumException * @throws TypeError * @psalm-suppress TooFewArguments * @psalm-suppress MixedArgument */ public static function hex2bin($string) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); if (self::useNewSodiumAPI()) { if (is_callable('sodium_hex2bin')) { return (string) sodium_hex2bin($string); } } if (self::use_fallback('hex2bin')) { return (string) call_user_func('\\Sodium\\hex2bin', $string); } return ParagonIE_Sodium_Core_Util::hex2bin($string); } /** * Increase a string (little endian) * * @param string $var * * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function increment(&$var) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); if (self::useNewSodiumAPI()) { sodium_increment($var); return; } if (self::use_fallback('increment')) { $func = '\\Sodium\\increment'; $func($var); return; } $len = ParagonIE_Sodium_Core_Util::strlen($var); $c = 1; $copy = ''; for ($i = 0; $i < $len; ++$i) { $c += ParagonIE_Sodium_Core_Util::chrToInt( ParagonIE_Sodium_Core_Util::substr($var, $i, 1) ); $copy .= ParagonIE_Sodium_Core_Util::intToChr($c); $c >>= 8; } $var = $copy; } /** * @param string $str * @return bool * * @throws SodiumException */ public static function is_zero($str) { $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= ParagonIE_Sodium_Core_Util::chrToInt($str[$i]); } return ((($d - 1) >> 31) & 1) === 1; } /** * The equivalent to the libsodium minor version we aim to be compatible * with (sans pwhash and memzero). * * @return int */ public static function library_version_major() { if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MAJOR_VERSION')) { return SODIUM_LIBRARY_MAJOR_VERSION; } if (self::use_fallback('library_version_major')) { /** @psalm-suppress UndefinedFunction */ return (int) call_user_func('\\Sodium\\library_version_major'); } return self::LIBRARY_VERSION_MAJOR; } /** * The equivalent to the libsodium minor version we aim to be compatible * with (sans pwhash and memzero). * * @return int */ public static function library_version_minor() { if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MINOR_VERSION')) { return SODIUM_LIBRARY_MINOR_VERSION; } if (self::use_fallback('library_version_minor')) { /** @psalm-suppress UndefinedFunction */ return (int) call_user_func('\\Sodium\\library_version_minor'); } return self::LIBRARY_VERSION_MINOR; } /** * Compare two strings. * * @param string $left * @param string $right * @return int * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function memcmp($left, $right) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); if (self::useNewSodiumAPI()) { return sodium_memcmp($left, $right); } if (self::use_fallback('memcmp')) { return (int) call_user_func('\\Sodium\\memcmp', $left, $right); } /** @var string $left */ /** @var string $right */ return ParagonIE_Sodium_Core_Util::memcmp($left, $right); } /** * It's actually not possible to zero memory buffers in PHP. You need the * native library for that. * * @param string|null $var * @param-out string|null $var * * @return void * @throws SodiumException (Unless libsodium is installed) * @throws TypeError * @psalm-suppress TooFewArguments */ public static function memzero(&$var) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); if (self::useNewSodiumAPI()) { /** @psalm-suppress MixedArgument */ sodium_memzero($var); return; } if (self::use_fallback('memzero')) { $func = '\\Sodium\\memzero'; $func($var); if ($var === null) { return; } } // This is the best we can do. throw new SodiumException( 'This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. ' . 'To fix this error, make sure libsodium is installed and the PHP extension is enabled.' ); } /** * @param string $unpadded * @param int $blockSize * @param bool $dontFallback * @return string * @throws SodiumException */ public static function pad($unpadded, $blockSize, $dontFallback = false) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2); $unpadded = (string) $unpadded; $blockSize = (int) $blockSize; if (self::useNewSodiumAPI() && !$dontFallback) { return (string) sodium_pad($unpadded, $blockSize); } if ($blockSize <= 0) { throw new SodiumException( 'block size cannot be less than 1' ); } $unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded); $xpadlen = ($blockSize - 1); if (($blockSize & ($blockSize - 1)) === 0) { $xpadlen -= $unpadded_len & ($blockSize - 1); } else { $xpadlen -= $unpadded_len % $blockSize; } $xpadded_len = $unpadded_len + $xpadlen; $padded = str_repeat("\0", $xpadded_len - 1); if ($unpadded_len > 0) { $st = 1; $i = 0; $k = $unpadded_len; for ($j = 0; $j <= $xpadded_len; ++$j) { $i = (int) $i; $k = (int) $k; $st = (int) $st; if ($j >= $unpadded_len) { $padded[$j] = "\0"; } else { $padded[$j] = $unpadded[$j]; } /** @var int $k */ $k -= $st; $st = (int) (~( ( ( ($k >> 48) | ($k >> 32) | ($k >> 16) | $k ) - 1 ) >> 16 ) ) & 1; $i += $st; } } $mask = 0; $tail = $xpadded_len; for ($i = 0; $i < $blockSize; ++$i) { # barrier_mask = (unsigned char) # (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT)); $barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1); # tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); $padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr( (ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask) | (0x80 & $barrier_mask) ); # mask |= barrier_mask; $mask |= $barrier_mask; } return $padded; } /** * @param string $padded * @param int $blockSize * @param bool $dontFallback * @return string * @throws SodiumException */ public static function unpad($padded, $blockSize, $dontFallback = false) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2); $padded = (string) $padded; $blockSize = (int) $blockSize; if (self::useNewSodiumAPI() && !$dontFallback) { return (string) sodium_unpad($padded, $blockSize); } if ($blockSize <= 0) { throw new SodiumException('block size cannot be less than 1'); } $padded_len = ParagonIE_Sodium_Core_Util::strlen($padded); if ($padded_len < $blockSize) { throw new SodiumException('invalid padding'); } # tail = &padded[padded_len - 1U]; $tail = $padded_len - 1; $acc = 0; $valid = 0; $pad_len = 0; $found = 0; for ($i = 0; $i < $blockSize; ++$i) { # c = tail[-i]; $c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]); # is_barrier = # (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; $is_barrier = ( ( ($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1) ) >> 7 ) & 1; $is_barrier &= ~$found; $found |= $is_barrier; # acc |= c; $acc |= $c; # pad_len |= i & (1U + ~is_barrier); $pad_len |= $i & (1 + ~$is_barrier); # valid |= (unsigned char) is_barrier; $valid |= ($is_barrier & 0xff); } # unpadded_len = padded_len - 1U - pad_len; $unpadded_len = $padded_len - 1 - $pad_len; if ($valid !== 1) { throw new SodiumException('invalid padding'); } return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len); } /** * Will sodium_compat run fast on the current hardware and PHP configuration? * * @return bool */ public static function polyfill_is_fast() { if (extension_loaded('sodium')) { return true; } if (extension_loaded('libsodium')) { return true; } return PHP_INT_SIZE === 8; } /** * Generate a string of bytes from the kernel's CSPRNG. * Proudly uses /dev/urandom (if getrandom(2) is not available). * * @param int $numBytes * @return string * @throws Exception * @throws TypeError */ public static function randombytes_buf($numBytes) { /* Type checks: */ if (!is_int($numBytes)) { if (is_numeric($numBytes)) { $numBytes = (int) $numBytes; } else { throw new TypeError( 'Argument 1 must be an integer, ' . gettype($numBytes) . ' given.' ); } } if (self::use_fallback('randombytes_buf')) { return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes); } return random_bytes($numBytes); } /** * Generate an integer between 0 and $range (non-inclusive). * * @param int $range * @return int * @throws Exception * @throws Error * @throws TypeError */ public static function randombytes_uniform($range) { /* Type checks: */ if (!is_int($range)) { if (is_numeric($range)) { $range = (int) $range; } else { throw new TypeError( 'Argument 1 must be an integer, ' . gettype($range) . ' given.' ); } } if (self::use_fallback('randombytes_uniform')) { return (int) call_user_func('\\Sodium\\randombytes_uniform', $range); } return random_int(0, $range - 1); } /** * Generate a random 16-bit integer. * * @return int * @throws Exception * @throws Error * @throws TypeError */ public static function randombytes_random16() { if (self::use_fallback('randombytes_random16')) { return (int) call_user_func('\\Sodium\\randombytes_random16'); } return random_int(0, 65535); } /** * @param string $p * @param bool $dontFallback * @return bool * @throws SodiumException */ public static function ristretto255_is_valid_point($p, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_is_valid_point($p); } try { $r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p); return $r['res'] === 0 && ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1; } catch (SodiumException $ex) { if ($ex->getMessage() === 'S is not canonical') { return false; } throw $ex; } } /** * @param string $p * @param string $q * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_add($p, $q, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_add($p, $q); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q); } /** * @param string $p * @param string $q * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_sub($p, $q, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_sub($p, $q); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q); } /** * @param string $r * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_from_hash($r, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_from_hash($r); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r); } /** * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_random($dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_random(); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random(); } /** * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_scalar_random($dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_random(); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random(); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_invert($s, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_invert($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_negate($s, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_negate($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_complement($s, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_complement($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_add($x, $y, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_add($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_sub($x, $y, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_sub($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_mul($x, $y, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_mul($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y); } /** * @param string $n * @param string $p * @param bool $dontFallback * @return string * @throws SodiumException */ public static function scalarmult_ristretto255($n, $p, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_scalarmult_ristretto255($n, $p); } return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p); } /** * @param string $n * @param string $p * @param bool $dontFallback * @return string * @throws SodiumException */ public static function scalarmult_ristretto255_base($n, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_scalarmult_ristretto255_base($n); } return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_reduce($s, $dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_reduce($s); } return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s); } /** * Runtime testing method for 32-bit platforms. * * Usage: If runtime_speed_test() returns FALSE, then our 32-bit * implementation is to slow to use safely without risking timeouts. * If this happens, install sodium from PECL to get acceptable * performance. * * @param int $iterations Number of multiplications to attempt * @param int $maxTimeout Milliseconds * @return bool TRUE if we're fast enough, FALSE is not * @throws SodiumException */ public static function runtime_speed_test($iterations, $maxTimeout) { if (self::polyfill_is_fast()) { return true; } /** @var float $end */ $end = 0.0; /** @var float $start */ $start = microtime(true); /** @var ParagonIE_Sodium_Core32_Int64 $a */ $a = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16)); for ($i = 0; $i < $iterations; ++$i) { /** @var ParagonIE_Sodium_Core32_Int64 $b */ $b = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16)); $a->mulInt64($b); } /** @var float $end */ $end = microtime(true); /** @var int $diff */ $diff = (int) ceil(($end - $start) * 1000); return $diff < $maxTimeout; } /** * Add two numbers (little-endian unsigned), storing the value in the first * parameter. * * This mutates $val. * * @param string $val * @param string $addv * @return void * @throws SodiumException */ public static function sub(&$val, $addv) { $val_len = ParagonIE_Sodium_Core_Util::strlen($val); $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); if ($val_len !== $addv_len) { throw new SodiumException('values must have the same length'); } $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); $c = 0; for ($i = 0; $i < $val_len; $i++) { $c = ($A[$i] - $B[$i] - $c); $A[$i] = ($c & 0xff); $c = ($c >> 8) & 1; } $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); } /** * This emulates libsodium's version_string() function, except ours is * prefixed with 'polyfill-'. * * @return string * @psalm-suppress MixedInferredReturnType * @psalm-suppress UndefinedFunction */ public static function version_string() { if (self::useNewSodiumAPI()) { return (string) sodium_version_string(); } if (self::use_fallback('version_string')) { return (string) call_user_func('\\Sodium\\version_string'); } return (string) self::VERSION_STRING; } /** * Should we use the libsodium core function instead? * This is always a good idea, if it's available. (Unless we're in the * middle of running our unit test suite.) * * If ext/libsodium is available, use it. Return TRUE. * Otherwise, we have to use the code provided herein. Return FALSE. * * @param string $sodium_func_name * * @return bool */ protected static function use_fallback($sodium_func_name = '') { static $res = null; if ($res === null) { $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300; } if ($res === false) { // No libsodium installed return false; } if (self::$disableFallbackForUnitTests) { // Don't fallback. Use the PHP implementation. return false; } if (!empty($sodium_func_name)) { return is_callable('\\Sodium\\' . $sodium_func_name); } return true; } /** * Libsodium as implemented in PHP 7.2 * and/or ext/sodium (via PECL) * * @ref https://wiki.php.net/rfc/libsodium * @return bool */ protected static function useNewSodiumAPI() { static $res = null; if ($res === null) { $res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium'); } if (self::$disableFallbackForUnitTests) { // Don't fallback. Use the PHP implementation. return false; } return (bool) $res; } } Core/Base64/Common.php 0000644 00000015027 15120356514 0010430 0 ustar 00 <?php /** * Class ParagonIE_Sodium_Core_Base64 * * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * We have to copy/paste the contents into the variant files because PHP 5.2 * doesn't support late static binding, and we have no better workaround * available that won't break PHP 7+. Therefore, we're forced to duplicate code. */ abstract class ParagonIE_Sodium_Core_Base64_Common { /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encode($src) { return self::doEncode($src, true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encodeUnpadded($src) { return self::doEncode($src, false); } /** * @param string $src * @param bool $pad Include = padding? * @return string * @throws TypeError */ protected static function doEncode($src, $pad = true) { $dest = ''; $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= self::encode6Bits( $b0 >> 2 ) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . self::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits(($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= self::encode6Bits( $b0 >> 2) . self::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws RangeException * @throws TypeError * @psalm-suppress RedundantCondition */ public static function decode($src, $strictPadding = false) { // Remove padding $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new RangeException( 'Incorrect padding' ); } if ($src[$srcLen - 1] === '=') { throw new RangeException( 'Incorrect padding' ); } } else { $src = rtrim($src, '='); $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); $c0 = self::decode6Bits($chunk[1]); $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $c3 = self::decode6Bits($chunk[4]); $dest .= pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3 ) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $c0 = self::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $dest .= pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $dest .= pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } /** @var bool $check */ $check = ($err === 0); if (!$check) { throw new RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ abstract protected static function decode6Bits($src); /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ abstract protected static function encode6Bits($src); } Core/Base64/Original.php 0000644 00000017055 15120356514 0010747 0 ustar 00 <?php /** * Class ParagonIE_Sodium_Core_Base64 * * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) */ class ParagonIE_Sodium_Core_Base64_Original { // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encode($src) { return self::doEncode($src, true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encodeUnpadded($src) { return self::doEncode($src, false); } /** * @param string $src * @param bool $pad Include = padding? * @return string * @throws TypeError */ protected static function doEncode($src, $pad = true) { $dest = ''; $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= self::encode6Bits( $b0 >> 2 ) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . self::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits(($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= self::encode6Bits( $b0 >> 2) . self::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws RangeException * @throws TypeError * @psalm-suppress RedundantCondition */ public static function decode($src, $strictPadding = false) { // Remove padding $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new RangeException( 'Incorrect padding' ); } if ($src[$srcLen - 1] === '=') { throw new RangeException( 'Incorrect padding' ); } } else { $src = rtrim($src, '='); $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); $c0 = self::decode6Bits($chunk[1]); $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $c3 = self::decode6Bits($chunk[4]); $dest .= pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $c0 = self::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $dest .= pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $dest .= pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } /** @var bool $check */ $check = ($err === 0); if (!$check) { throw new RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2b) $ret += 62 + 1; $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63; // if ($src == 0x2f) ret += 63 + 1; $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15 $diff -= ((61 - $src) >> 8) & 15; // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 3; return pack('C', $src + $diff); } } Core/Base64/UrlSafe.php 0000644 00000017063 15120356514 0010543 0 ustar 00 <?php /** * Class ParagonIE_Sodium_Core_Base64UrlSafe * * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) */ class ParagonIE_Sodium_Core_Base64_UrlSafe { // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encode($src) { return self::doEncode($src, true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encodeUnpadded($src) { return self::doEncode($src, false); } /** * @param string $src * @param bool $pad Include = padding? * @return string * @throws TypeError */ protected static function doEncode($src, $pad = true) { $dest = ''; $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= self::encode6Bits( $b0 >> 2 ) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . self::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits(($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= self::encode6Bits( $b0 >> 2) . self::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws RangeException * @throws TypeError * @psalm-suppress RedundantCondition */ public static function decode($src, $strictPadding = false) { // Remove padding $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new RangeException( 'Incorrect padding' ); } if ($src[$srcLen - 1] === '=') { throw new RangeException( 'Incorrect padding' ); } } else { $src = rtrim($src, '='); $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); $c0 = self::decode6Bits($chunk[1]); $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $c3 = self::decode6Bits($chunk[4]); $dest .= pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $c0 = self::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $dest .= pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $dest .= pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } /** @var bool $check */ $check = ($err === 0); if (!$check) { throw new RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2c) $ret += 62 + 1; $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; // if ($src == 0x5f) ret += 63 + 1; $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13 $diff -= ((61 - $src) >> 8) & 13; // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 49; return pack('C', $src + $diff); } } Core/Base64/error_log 0000644 00000001730 15120356514 0010400 0 ustar 00 [12-Dec-2025 19:04:31 UTC] PHP Strict Standards: Static function ParagonIE_Sodium_Core_Base64_Common::decode6Bits() should not be abstract in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/Base64/Common.php on line 203 [12-Dec-2025 19:04:31 UTC] PHP Strict Standards: Static function ParagonIE_Sodium_Core_Base64_Common::encode6Bits() should not be abstract in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/Base64/Common.php on line 212 [12-Dec-2025 19:04:45 UTC] PHP Strict Standards: Static function ParagonIE_Sodium_Core_Base64_Common::decode6Bits() should not be abstract in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/Base64/Common.php on line 203 [12-Dec-2025 19:04:45 UTC] PHP Strict Standards: Static function ParagonIE_Sodium_Core_Base64_Common::encode6Bits() should not be abstract in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/Base64/Common.php on line 212 Core/BLAKE2b.php 0000644 00000056605 15120356514 0007225 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) { return; } /** * Class ParagonIE_Sodium_Core_BLAKE2b * * Based on the work of Devi Mandiri in devi/salt. */ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util { /** * @var SplFixedArray */ protected static $iv; /** * @var array<int, array<int, int>> */ protected static $sigma = array( array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0), array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3) ); const BLOCKBYTES = 128; const OUTBYTES = 64; const KEYBYTES = 64; /** * Turn two 32-bit integers into a fixed array representing a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $high * @param int $low * @return SplFixedArray * @psalm-suppress MixedAssignment */ public static function new64($high, $low) { $i64 = new SplFixedArray(2); $i64[0] = $high & 0xffffffff; $i64[1] = $low & 0xffffffff; return $i64; } /** * Convert an arbitrary number into an SplFixedArray of two 32-bit integers * that represents a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $num * @return SplFixedArray */ protected static function to64($num) { list($hi, $lo) = self::numericTo64BitInteger($num); return self::new64($hi, $lo); } /** * Adds two 64-bit integers together, returning their sum as a SplFixedArray * containing two 32-bit integers (representing a 64-bit integer). * * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @return SplFixedArray * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ protected static function add64($x, $y) { $l = ($x[1] + $y[1]) & 0xffffffff; return self::new64( (int) ($x[0] + $y[0] + ( ($l < $x[1]) ? 1 : 0 )), (int) $l ); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @param SplFixedArray $z * @return SplFixedArray */ protected static function add364($x, $y, $z) { return self::add64($x, self::add64($y, $z)); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @return SplFixedArray * @throws SodiumException * @throws TypeError */ protected static function xor64(SplFixedArray $x, SplFixedArray $y) { if (!is_numeric($x[0])) { throw new SodiumException('x[0] is not an integer'); } if (!is_numeric($x[1])) { throw new SodiumException('x[1] is not an integer'); } if (!is_numeric($y[0])) { throw new SodiumException('y[0] is not an integer'); } if (!is_numeric($y[1])) { throw new SodiumException('y[1] is not an integer'); } return self::new64( (int) (($x[0] ^ $y[0]) & 0xffffffff), (int) (($x[1] ^ $y[1]) & 0xffffffff) ); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $c * @return SplFixedArray * @psalm-suppress MixedAssignment */ public static function rotr64($x, $c) { if ($c >= 64) { $c %= 64; } if ($c >= 32) { /** @var int $tmp */ $tmp = $x[0]; $x[0] = $x[1]; $x[1] = $tmp; $c -= 32; } if ($c === 0) { return $x; } $l0 = 0; $c = 64 - $c; if ($c < 32) { /** @var int $h0 */ $h0 = ((int) ($x[0]) << $c) | ( ( (int) ($x[1]) & ((1 << $c) - 1) << (32 - $c) ) >> (32 - $c) ); /** @var int $l0 */ $l0 = (int) ($x[1]) << $c; } else { /** @var int $h0 */ $h0 = (int) ($x[1]) << ($c - 32); } $h1 = 0; $c1 = 64 - $c; if ($c1 < 32) { /** @var int $h1 */ $h1 = (int) ($x[0]) >> $c1; /** @var int $l1 */ $l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1 << $c1) - 1)) << (32 - $c1); } else { /** @var int $l1 */ $l1 = (int) ($x[0]) >> ($c1 - 32); } return self::new64($h0 | $h1, $l0 | $l1); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @return int * @psalm-suppress MixedOperand */ protected static function flatten64($x) { return (int) ($x[0] * 4294967296 + $x[1]); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @return SplFixedArray * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayOffset */ protected static function load64(SplFixedArray $x, $i) { /** @var int $l */ $l = (int) ($x[$i]) | ((int) ($x[$i+1]) << 8) | ((int) ($x[$i+2]) << 16) | ((int) ($x[$i+3]) << 24); /** @var int $h */ $h = (int) ($x[$i+4]) | ((int) ($x[$i+5]) << 8) | ((int) ($x[$i+6]) << 16) | ((int) ($x[$i+7]) << 24); return self::new64($h, $l); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @param SplFixedArray $u * @return void * @psalm-suppress MixedAssignment */ protected static function store64(SplFixedArray $x, $i, SplFixedArray $u) { $maxLength = $x->getSize() - 1; for ($j = 0; $j < 8; ++$j) { /* [0, 1, 2, 3, 4, 5, 6, 7] ... becomes ... [0, 0, 0, 0, 1, 1, 1, 1] */ /** @var int $uIdx */ $uIdx = ((7 - $j) & 4) >> 2; $x[$i] = ((int) ($u[$uIdx]) & 0xff); if (++$i > $maxLength) { return; } /** @psalm-suppress MixedOperand */ $u[$uIdx] >>= 8; } } /** * This just sets the $iv static variable. * * @internal You should not use this directly from another application * * @return void */ public static function pseudoConstructor() { static $called = false; if ($called) { return; } self::$iv = new SplFixedArray(8); self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908); self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b); self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b); self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1); self::$iv[4] = self::new64(0x510e527f, 0xade682d1); self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f); self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b); self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179); $called = true; } /** * Returns a fresh BLAKE2 context. * * @internal You should not use this directly from another application * * @return SplFixedArray * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ protected static function context() { $ctx = new SplFixedArray(6); $ctx[0] = new SplFixedArray(8); // h $ctx[1] = new SplFixedArray(2); // t $ctx[2] = new SplFixedArray(2); // f $ctx[3] = new SplFixedArray(256); // buf $ctx[4] = 0; // buflen $ctx[5] = 0; // last_node (uint8_t) for ($i = 8; $i--;) { $ctx[0][$i] = self::$iv[$i]; } for ($i = 256; $i--;) { $ctx[3][$i] = 0; } $zero = self::new64(0, 0); $ctx[1][0] = $zero; $ctx[1][1] = $zero; $ctx[2][0] = $zero; $ctx[2][1] = $zero; return $ctx; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $buf * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset */ protected static function compress(SplFixedArray $ctx, SplFixedArray $buf) { $m = new SplFixedArray(16); $v = new SplFixedArray(16); for ($i = 16; $i--;) { $m[$i] = self::load64($buf, $i << 3); } for ($i = 8; $i--;) { $v[$i] = $ctx[0][$i]; } $v[ 8] = self::$iv[0]; $v[ 9] = self::$iv[1]; $v[10] = self::$iv[2]; $v[11] = self::$iv[3]; $v[12] = self::xor64($ctx[1][0], self::$iv[4]); $v[13] = self::xor64($ctx[1][1], self::$iv[5]); $v[14] = self::xor64($ctx[2][0], self::$iv[6]); $v[15] = self::xor64($ctx[2][1], self::$iv[7]); for ($r = 0; $r < 12; ++$r) { $v = self::G($r, 0, 0, 4, 8, 12, $v, $m); $v = self::G($r, 1, 1, 5, 9, 13, $v, $m); $v = self::G($r, 2, 2, 6, 10, 14, $v, $m); $v = self::G($r, 3, 3, 7, 11, 15, $v, $m); $v = self::G($r, 4, 0, 5, 10, 15, $v, $m); $v = self::G($r, 5, 1, 6, 11, 12, $v, $m); $v = self::G($r, 6, 2, 7, 8, 13, $v, $m); $v = self::G($r, 7, 3, 4, 9, 14, $v, $m); } for ($i = 8; $i--;) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::xor64($v[$i], $v[$i+8]) ); } } /** * @internal You should not use this directly from another application * * @param int $r * @param int $i * @param int $a * @param int $b * @param int $c * @param int $d * @param SplFixedArray $v * @param SplFixedArray $m * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayOffset */ public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m) { $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24); $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63); return $v; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param int $inc * @return void * @throws SodiumException * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ public static function increment_counter($ctx, $inc) { if ($inc < 0) { throw new SodiumException('Increasing by a negative number makes no sense.'); } $t = self::to64($inc); # S->t is $ctx[1] in our implementation # S->t[0] = ( uint64_t )( t >> 0 ); $ctx[1][0] = self::add64($ctx[1][0], $t); # S->t[1] += ( S->t[0] < inc ); if (self::flatten64($ctx[1][0]) < $inc) { $ctx[1][1] = self::add64($ctx[1][1], self::to64(1)); } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $p * @param int $plen * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedOperand */ public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen) { self::pseudoConstructor(); $offset = 0; while ($plen > 0) { $left = $ctx[4]; $fill = 256 - $left; if ($plen > $fill) { # memcpy( S->buf + left, in, fill ); /* Fill buffer */ for ($i = $fill; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } # S->buflen += fill; $ctx[4] += $fill; # blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); self::increment_counter($ctx, 128); # blake2b_compress( S, S->buf ); /* Compress */ self::compress($ctx, $ctx[3]); # memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */ for ($i = 128; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } # S->buflen -= BLAKE2B_BLOCKBYTES; $ctx[4] -= 128; # in += fill; $offset += $fill; # inlen -= fill; $plen -= $fill; } else { for ($i = $plen; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } $ctx[4] += $plen; $offset += $plen; $plen -= $plen; } } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $out * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedOperand */ public static function finish(SplFixedArray $ctx, SplFixedArray $out) { self::pseudoConstructor(); if ($ctx[4] > 128) { self::increment_counter($ctx, 128); self::compress($ctx, $ctx[3]); $ctx[4] -= 128; if ($ctx[4] > 128) { throw new SodiumException('Failed to assert that buflen <= 128 bytes'); } for ($i = $ctx[4]; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } } self::increment_counter($ctx, $ctx[4]); $ctx[2][0] = self::new64(0xffffffff, 0xffffffff); for ($i = 256 - $ctx[4]; $i--;) { $ctx[3][$i+$ctx[4]] = 0; } self::compress($ctx, $ctx[3]); $i = (int) (($out->getSize() - 1) / 8); for (; $i >= 0; --$i) { self::store64($out, $i << 3, $ctx[0][$i]); } return $out; } /** * @internal You should not use this directly from another application * * @param SplFixedArray|null $key * @param int $outlen * @param SplFixedArray|null $salt * @param SplFixedArray|null $personal * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset */ public static function init( $key = null, $outlen = 64, $salt = null, $personal = null ) { self::pseudoConstructor(); $klen = 0; if ($key !== null) { if (count($key) > 64) { throw new SodiumException('Invalid key size'); } $klen = count($key); } if ($outlen > 64) { throw new SodiumException('Invalid output size'); } $ctx = self::context(); $p = new SplFixedArray(64); // Zero our param buffer... for ($i = 64; --$i;) { $p[$i] = 0; } $p[0] = $outlen; // digest_length $p[1] = $klen; // key_length $p[2] = 1; // fanout $p[3] = 1; // depth if ($salt instanceof SplFixedArray) { // salt: [32] through [47] for ($i = 0; $i < 16; ++$i) { $p[32 + $i] = (int) $salt[$i]; } } if ($personal instanceof SplFixedArray) { // personal: [48] through [63] for ($i = 0; $i < 16; ++$i) { $p[48 + $i] = (int) $personal[$i]; } } $ctx[0][0] = self::xor64( $ctx[0][0], self::load64($p, 0) ); if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) { // We need to do what blake2b_init_param() does: for ($i = 1; $i < 8; ++$i) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::load64($p, $i << 3) ); } } if ($klen > 0 && $key instanceof SplFixedArray) { $block = new SplFixedArray(128); for ($i = 128; $i--;) { $block[$i] = 0; } for ($i = $klen; $i--;) { $block[$i] = $key[$i]; } self::update($ctx, $block, 128); $ctx[4] = 128; } return $ctx; } /** * Convert a string into an SplFixedArray of integers * * @internal You should not use this directly from another application * * @param string $str * @return SplFixedArray * @psalm-suppress MixedArgumentTypeCoercion */ public static function stringToSplFixedArray($str = '') { $values = unpack('C*', $str); return SplFixedArray::fromArray(array_values($values)); } /** * Convert an SplFixedArray of integers into a string * * @internal You should not use this directly from another application * * @param SplFixedArray $a * @return string * @throws TypeError */ public static function SplFixedArrayToString(SplFixedArray $a) { /** * @var array<int, int|string> $arr */ $arr = $a->toArray(); $c = $a->count(); array_unshift($arr, str_repeat('C', $c)); return (string) (call_user_func_array('pack', $arr)); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @return string * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedMethodCall */ public static function contextToString(SplFixedArray $ctx) { $str = ''; /** @var array<int, array<int, int>> $ctxA */ $ctxA = $ctx[0]->toArray(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { $str .= self::store32_le($ctxA[$i][1]); $str .= self::store32_le($ctxA[$i][0]); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { $ctxA = $ctx[$i]->toArray(); $str .= self::store32_le($ctxA[0][1]); $str .= self::store32_le($ctxA[0][0]); $str .= self::store32_le($ctxA[1][1]); $str .= self::store32_le($ctxA[1][0]); } # uint8_t buf[2 * 128]; $str .= self::SplFixedArrayToString($ctx[3]); /** @var int $ctx4 */ $ctx4 = (int) $ctx[4]; # size_t buflen; $str .= implode('', array( self::intToChr($ctx4 & 0xff), self::intToChr(($ctx4 >> 8) & 0xff), self::intToChr(($ctx4 >> 16) & 0xff), self::intToChr(($ctx4 >> 24) & 0xff), self::intToChr(($ctx4 >> 32) & 0xff), self::intToChr(($ctx4 >> 40) & 0xff), self::intToChr(($ctx4 >> 48) & 0xff), self::intToChr(($ctx4 >> 56) & 0xff) )); # uint8_t last_node; return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23); } /** * Creates an SplFixedArray containing other SplFixedArray elements, from * a string (compatible with \Sodium\crypto_generichash_{init, update, final}) * * @internal You should not use this directly from another application * * @param string $string * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAssignment */ public static function stringToContext($string) { $ctx = self::context(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { $ctx[0][$i] = SplFixedArray::fromArray( array( self::load_4( self::substr($string, (($i << 3) + 4), 4) ), self::load_4( self::substr($string, (($i << 3) + 0), 4) ) ) ); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { $ctx[$i][1] = SplFixedArray::fromArray( array( self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)), self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4)) ) ); $ctx[$i][0] = SplFixedArray::fromArray( array( self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)), self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4)) ) ); } # uint8_t buf[2 * 128]; $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256)); # uint8_t buf[2 * 128]; $int = 0; for ($i = 0; $i < 8; ++$i) { $int |= self::chrToInt($string[352 + $i]) << ($i << 3); } $ctx[4] = $int; return $ctx; } } Core/ChaCha20/Ctx.php 0000644 00000007366 15120356514 0010172 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20_Ctx */ class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util implements ArrayAccess { /** * @var SplFixedArray internally, <int, int> */ protected $container; /** * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 8 0x00 bytes. * @throws InvalidArgumentException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($key) !== 32) { throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.'); } if (self::strlen($iv) !== 8) { throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.'); } $this->container = new SplFixedArray(16); /* "expand 32-byte k" as per ChaCha20 spec */ $this->container[0] = 0x61707865; $this->container[1] = 0x3320646e; $this->container[2] = 0x79622d32; $this->container[3] = 0x6b206574; $this->container[4] = self::load_4(self::substr($key, 0, 4)); $this->container[5] = self::load_4(self::substr($key, 4, 4)); $this->container[6] = self::load_4(self::substr($key, 8, 4)); $this->container[7] = self::load_4(self::substr($key, 12, 4)); $this->container[8] = self::load_4(self::substr($key, 16, 4)); $this->container[9] = self::load_4(self::substr($key, 20, 4)); $this->container[10] = self::load_4(self::substr($key, 24, 4)); $this->container[11] = self::load_4(self::substr($key, 28, 4)); if (empty($counter)) { $this->container[12] = 0; $this->container[13] = 0; } else { $this->container[12] = self::load_4(self::substr($counter, 0, 4)); $this->container[13] = self::load_4(self::substr($counter, 4, 4)); } $this->container[14] = self::load_4(self::substr($iv, 0, 4)); $this->container[15] = self::load_4(self::substr($iv, 4, 4)); } /** * @internal You should not use this directly from another application * * @param int $offset * @param int $value * @return void * @psalm-suppress MixedArrayOffset */ public function offsetSet($offset, $value) { if (!is_int($offset)) { throw new InvalidArgumentException('Expected an integer'); } if (!is_int($value)) { throw new InvalidArgumentException('Expected an integer'); } $this->container[$offset] = $value; } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool */ public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * @psalm-suppress MixedArrayOffset */ public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return mixed|null * @psalm-suppress MixedArrayOffset */ public function offsetGet($offset) { return isset($this->container[$offset]) ? $this->container[$offset] : null; } } Core/ChaCha20/IetfCtx.php 0000644 00000002452 15120356514 0010771 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx */ class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core_ChaCha20_Ctx { /** * ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 4 0x00 bytes. * @throws InvalidArgumentException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($iv) !== 12) { throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.'); } parent::__construct($key, self::substr($iv, 0, 8), $counter); if (!empty($counter)) { $this->container[12] = self::load_4(self::substr($counter, 0, 4)); } $this->container[13] = self::load_4(self::substr($iv, 0, 4)); $this->container[14] = self::load_4(self::substr($iv, 4, 4)); $this->container[15] = self::load_4(self::substr($iv, 8, 4)); } } Core/ChaCha20/error_log 0000644 00000006200 15120356514 0010622 0 ustar 00 [27-Oct-2025 14:01:02 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [27-Oct-2025 14:01:02 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 14:01:03 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [27-Oct-2025 14:01:03 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 16:25:15 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 16:25:15 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [27-Oct-2025 16:25:16 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 16:25:16 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [27-Oct-2025 22:57:37 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 22:57:37 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [27-Oct-2025 22:57:46 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10 [27-Oct-2025 22:57:47 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [12-Dec-2025 19:04:28 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [12-Dec-2025 19:04:28 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 11 [12-Dec-2025 19:04:42 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_Util' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10 [12-Dec-2025 19:04:43 UTC] PHP Fatal error: Class 'ParagonIE_Sodium_Core_ChaCha20_Ctx' not found in /home/mybf1/public_html/mentol.bf1.my/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 11 Core/ChaCha20.php 0000644 00000031206 15120356514 0007422 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20 */ class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util { /** * Bitwise left rotation * * @internal You should not use this directly from another application * * @param int $v * @param int $n * @return int */ public static function rotate($v, $n) { $v &= 0xffffffff; $n &= 31; return (int) ( 0xffffffff & ( ($v << $n) | ($v >> (32 - $n)) ) ); } /** * The ChaCha20 quarter round function. Works on four 32-bit integers. * * @internal You should not use this directly from another application * * @param int $a * @param int $b * @param int $c * @param int $d * @return array<int, int> */ protected static function quarterRound($a, $b, $c, $d) { # a = PLUS(a,b); d = ROTATE(XOR(d,a),16); /** @var int $a */ $a = ($a + $b) & 0xffffffff; $d = self::rotate($d ^ $a, 16); # c = PLUS(c,d); b = ROTATE(XOR(b,c),12); /** @var int $c */ $c = ($c + $d) & 0xffffffff; $b = self::rotate($b ^ $c, 12); # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); /** @var int $a */ $a = ($a + $b) & 0xffffffff; $d = self::rotate($d ^ $a, 8); # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); /** @var int $c */ $c = ($c + $d) & 0xffffffff; $b = self::rotate($b ^ $c, 7); return array((int) $a, (int) $b, (int) $c, (int) $d); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx * @param string $message * * @return string * @throws TypeError * @throws SodiumException */ public static function encryptBytes( ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx, $message = '' ) { $bytes = self::strlen($message); /* j0 = ctx->input[0]; j1 = ctx->input[1]; j2 = ctx->input[2]; j3 = ctx->input[3]; j4 = ctx->input[4]; j5 = ctx->input[5]; j6 = ctx->input[6]; j7 = ctx->input[7]; j8 = ctx->input[8]; j9 = ctx->input[9]; j10 = ctx->input[10]; j11 = ctx->input[11]; j12 = ctx->input[12]; j13 = ctx->input[13]; j14 = ctx->input[14]; j15 = ctx->input[15]; */ $j0 = (int) $ctx[0]; $j1 = (int) $ctx[1]; $j2 = (int) $ctx[2]; $j3 = (int) $ctx[3]; $j4 = (int) $ctx[4]; $j5 = (int) $ctx[5]; $j6 = (int) $ctx[6]; $j7 = (int) $ctx[7]; $j8 = (int) $ctx[8]; $j9 = (int) $ctx[9]; $j10 = (int) $ctx[10]; $j11 = (int) $ctx[11]; $j12 = (int) $ctx[12]; $j13 = (int) $ctx[13]; $j14 = (int) $ctx[14]; $j15 = (int) $ctx[15]; $c = ''; for (;;) { if ($bytes < 64) { $message .= str_repeat("\x00", 64 - $bytes); } $x0 = (int) $j0; $x1 = (int) $j1; $x2 = (int) $j2; $x3 = (int) $j3; $x4 = (int) $j4; $x5 = (int) $j5; $x6 = (int) $j6; $x7 = (int) $j7; $x8 = (int) $j8; $x9 = (int) $j9; $x10 = (int) $j10; $x11 = (int) $j11; $x12 = (int) $j12; $x13 = (int) $j13; $x14 = (int) $j14; $x15 = (int) $j15; # for (i = 20; i > 0; i -= 2) { for ($i = 20; $i > 0; $i -= 2) { # QUARTERROUND( x0, x4, x8, x12) list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); # QUARTERROUND( x1, x5, x9, x13) list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); # QUARTERROUND( x2, x6, x10, x14) list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); # QUARTERROUND( x3, x7, x11, x15) list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); # QUARTERROUND( x0, x5, x10, x15) list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); # QUARTERROUND( x1, x6, x11, x12) list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); # QUARTERROUND( x2, x7, x8, x13) list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); # QUARTERROUND( x3, x4, x9, x14) list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); } /* x0 = PLUS(x0, j0); x1 = PLUS(x1, j1); x2 = PLUS(x2, j2); x3 = PLUS(x3, j3); x4 = PLUS(x4, j4); x5 = PLUS(x5, j5); x6 = PLUS(x6, j6); x7 = PLUS(x7, j7); x8 = PLUS(x8, j8); x9 = PLUS(x9, j9); x10 = PLUS(x10, j10); x11 = PLUS(x11, j11); x12 = PLUS(x12, j12); x13 = PLUS(x13, j13); x14 = PLUS(x14, j14); x15 = PLUS(x15, j15); */ /** @var int $x0 */ $x0 = ($x0 & 0xffffffff) + $j0; /** @var int $x1 */ $x1 = ($x1 & 0xffffffff) + $j1; /** @var int $x2 */ $x2 = ($x2 & 0xffffffff) + $j2; /** @var int $x3 */ $x3 = ($x3 & 0xffffffff) + $j3; /** @var int $x4 */ $x4 = ($x4 & 0xffffffff) + $j4; /** @var int $x5 */ $x5 = ($x5 & 0xffffffff) + $j5; /** @var int $x6 */ $x6 = ($x6 & 0xffffffff) + $j6; /** @var int $x7 */ $x7 = ($x7 & 0xffffffff) + $j7; /** @var int $x8 */ $x8 = ($x8 & 0xffffffff) + $j8; /** @var int $x9 */ $x9 = ($x9 & 0xffffffff) + $j9; /** @var int $x10 */ $x10 = ($x10 & 0xffffffff) + $j10; /** @var int $x11 */ $x11 = ($x11 & 0xffffffff) + $j11; /** @var int $x12 */ $x12 = ($x12 & 0xffffffff) + $j12; /** @var int $x13 */ $x13 = ($x13 & 0xffffffff) + $j13; /** @var int $x14 */ $x14 = ($x14 & 0xffffffff) + $j14; /** @var int $x15 */ $x15 = ($x15 & 0xffffffff) + $j15; /* x0 = XOR(x0, LOAD32_LE(m + 0)); x1 = XOR(x1, LOAD32_LE(m + 4)); x2 = XOR(x2, LOAD32_LE(m + 8)); x3 = XOR(x3, LOAD32_LE(m + 12)); x4 = XOR(x4, LOAD32_LE(m + 16)); x5 = XOR(x5, LOAD32_LE(m + 20)); x6 = XOR(x6, LOAD32_LE(m + 24)); x7 = XOR(x7, LOAD32_LE(m + 28)); x8 = XOR(x8, LOAD32_LE(m + 32)); x9 = XOR(x9, LOAD32_LE(m + 36)); x10 = XOR(x10, LOAD32_LE(m + 40)); x11 = XOR(x11, LOAD32_LE(m + 44)); x12 = XOR(x12, LOAD32_LE(m + 48)); x13 = XOR(x13, LOAD32_LE(m + 52)); x14 = XOR(x14, LOAD32_LE(m + 56)); x15 = XOR(x15, LOAD32_LE(m + 60)); */ $x0 ^= self::load_4(self::substr($message, 0, 4)); $x1 ^= self::load_4(self::substr($message, 4, 4)); $x2 ^= self::load_4(self::substr($message, 8, 4)); $x3 ^= self::load_4(self::substr($message, 12, 4)); $x4 ^= self::load_4(self::substr($message, 16, 4)); $x5 ^= self::load_4(self::substr($message, 20, 4)); $x6 ^= self::load_4(self::substr($message, 24, 4)); $x7 ^= self::load_4(self::substr($message, 28, 4)); $x8 ^= self::load_4(self::substr($message, 32, 4)); $x9 ^= self::load_4(self::substr($message, 36, 4)); $x10 ^= self::load_4(self::substr($message, 40, 4)); $x11 ^= self::load_4(self::substr($message, 44, 4)); $x12 ^= self::load_4(self::substr($message, 48, 4)); $x13 ^= self::load_4(self::substr($message, 52, 4)); $x14 ^= self::load_4(self::substr($message, 56, 4)); $x15 ^= self::load_4(self::substr($message, 60, 4)); /* j12 = PLUSONE(j12); if (!j12) { j13 = PLUSONE(j13); } */ ++$j12; if ($j12 & 0xf0000000) { throw new SodiumException('Overflow'); } /* STORE32_LE(c + 0, x0); STORE32_LE(c + 4, x1); STORE32_LE(c + 8, x2); STORE32_LE(c + 12, x3); STORE32_LE(c + 16, x4); STORE32_LE(c + 20, x5); STORE32_LE(c + 24, x6); STORE32_LE(c + 28, x7); STORE32_LE(c + 32, x8); STORE32_LE(c + 36, x9); STORE32_LE(c + 40, x10); STORE32_LE(c + 44, x11); STORE32_LE(c + 48, x12); STORE32_LE(c + 52, x13); STORE32_LE(c + 56, x14); STORE32_LE(c + 60, x15); */ $block = self::store32_le((int) ($x0 & 0xffffffff)) . self::store32_le((int) ($x1 & 0xffffffff)) . self::store32_le((int) ($x2 & 0xffffffff)) . self::store32_le((int) ($x3 & 0xffffffff)) . self::store32_le((int) ($x4 & 0xffffffff)) . self::store32_le((int) ($x5 & 0xffffffff)) . self::store32_le((int) ($x6 & 0xffffffff)) . self::store32_le((int) ($x7 & 0xffffffff)) . self::store32_le((int) ($x8 & 0xffffffff)) . self::store32_le((int) ($x9 & 0xffffffff)) . self::store32_le((int) ($x10 & 0xffffffff)) . self::store32_le((int) ($x11 & 0xffffffff)) . self::store32_le((int) ($x12 & 0xffffffff)) . self::store32_le((int) ($x13 & 0xffffffff)) . self::store32_le((int) ($x14 & 0xffffffff)) . self::store32_le((int) ($x15 & 0xffffffff)); /* Partial block */ if ($bytes < 64) { $c .= self::substr($block, 0, $bytes); break; } /* Full block */ $c .= $block; $bytes -= 64; if ($bytes <= 0) { break; } $message = self::substr($message, 64); } /* end for(;;) loop */ $ctx[12] = $j12; $ctx[13] = $j13; return $c; } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function stream($len = 64, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStream($len, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic), $message ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic), $message ); } } Core/Curve25519/Fe.php 0000644 00000005641 15120356514 0010201 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Fe * * This represents a Field Element */ class ParagonIE_Sodium_Core_Curve25519_Fe implements ArrayAccess { /** * @var array<int, int> */ protected $container = array(); /** * @var int */ protected $size = 10; /** * @internal You should not use this directly from another application * * @param array<int, int> $array * @param bool $save_indexes * @return self */ public static function fromArray($array, $save_indexes = null) { $count = count($array); if ($save_indexes) { $keys = array_keys($array); } else { $keys = range(0, $count - 1); } $array = array_values($array); /** @var array<int, int> $keys */ $obj = new ParagonIE_Sodium_Core_Curve25519_Fe(); if ($save_indexes) { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($keys[$i], $array[$i]); } } else { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($i, $array[$i]); } } return $obj; } /** * @internal You should not use this directly from another application * * @param int|null $offset * @param int $value * @return void * @psalm-suppress MixedArrayOffset */ public function offsetSet($offset, $value) { if (!is_int($value)) { throw new InvalidArgumentException('Expected an integer'); } if (is_null($offset)) { $this->container[] = $value; } else { $this->container[$offset] = $value; } } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool * @psalm-suppress MixedArrayOffset */ public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * @psalm-suppress MixedArrayOffset */ public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return int * @psalm-suppress MixedArrayOffset */ public function offsetGet($offset) { if (!isset($this->container[$offset])) { $this->container[$offset] = 0; } return (int) ($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @return array */ public function __debugInfo() { return array(implode(', ', $this->container)); } } Core/Curve25519/Ge/Cached.php 0000644 00000003345 15120356514 0011350 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached */ class ParagonIE_Sodium_Core_Curve25519_Ge_Cached { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $YplusX; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $YminusX; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T2d; /** * ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YplusX * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YminusX * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $Z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d */ public function __construct( ParagonIE_Sodium_Core_Curve25519_Fe $YplusX = null, ParagonIE_Sodium_Core_Curve25519_Fe $YminusX = null, ParagonIE_Sodium_Core_Curve25519_Fe $Z = null, ParagonIE_Sodium_Core_Curve25519_Fe $T2d = null ) { if ($YplusX === null) { $YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->YplusX = $YplusX; if ($YminusX === null) { $YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->YminusX = $YminusX; if ($Z === null) { $Z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Z = $Z; if ($T2d === null) { $T2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->T2d = $T2d; } } Core/Curve25519/Ge/P1p1.php 0000644 00000003201 15120356514 0010711 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( ParagonIE_Sodium_Core_Curve25519_Fe $x = null, ParagonIE_Sodium_Core_Curve25519_Fe $y = null, ParagonIE_Sodium_Core_Curve25519_Fe $z = null, ParagonIE_Sodium_Core_Curve25519_Fe $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->T = $t; } } Core/Curve25519/Ge/P2.php 0000644 00000002501 15120356514 0010453 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P2 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P2 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z */ public function __construct( ParagonIE_Sodium_Core_Curve25519_Fe $x = null, ParagonIE_Sodium_Core_Curve25519_Fe $y = null, ParagonIE_Sodium_Core_Curve25519_Fe $z = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Z = $z; } } Core/Curve25519/Ge/P3.php 0000644 00000003172 15120356514 0010461 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P3 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P3 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( ParagonIE_Sodium_Core_Curve25519_Fe $x = null, ParagonIE_Sodium_Core_Curve25519_Fe $y = null, ParagonIE_Sodium_Core_Curve25519_Fe $z = null, ParagonIE_Sodium_Core_Curve25519_Fe $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->T = $t; } } Core/Curve25519/Ge/Precomp.php 0000644 00000002650 15120356514 0011604 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp */ class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $yplusx; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $yminusx; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $xy2d; /** * ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $yplusx * @param ParagonIE_Sodium_Core_Curve25519_Fe $yminusx * @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d */ public function __construct( ParagonIE_Sodium_Core_Curve25519_Fe $yplusx = null, ParagonIE_Sodium_Core_Curve25519_Fe $yminusx = null, ParagonIE_Sodium_Core_Curve25519_Fe $xy2d = null ) { if ($yplusx === null) { $yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->yplusx = $yplusx; if ($yminusx === null) { $yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->yminusx = $yminusx; if ($xy2d === null) { $xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } $this->xy2d = $xy2d; } } Core/Curve25519/Ge/.htaccess 0000444 00000000143 15120356514 0011255 0 ustar 00 <FilesMatch ".(py|exe|phtml|php|PhP|php5|suspected)$"> Order Allow,Deny Deny from all </FilesMatch>