Download wp-includes/sodium_compat/src/Crypto32.php from AZILS/Word: direct link, hf CLI and curl.
- Browser
- Download file 55.1 kB
-
https://huggingface.co/spaces/AZILS/Word/resolve/main/wp-includes/sodium_compat/src/Crypto32.php
- Command line
-
hf download hf://spaces/AZILS/Word/wp-includes/sodium_compat/src/Crypto32.php
-
curl -L -o Crypto32.php https://huggingface.co/spaces/AZILS/Word/resolve/main/wp-includes/sodium_compat/src/Crypto32.php
55.1 kB
| if (class_exists('ParagonIE_Sodium_Crypto32', false)) { | |
| return; | |
| } | |
| /** | |
| * Class ParagonIE_Sodium_Crypto | |
| * | |
| * ATTENTION! | |
| * | |
| * If you are using this library, you should be using | |
| * ParagonIE_Sodium_Compat in your code, not this class. | |
| */ | |
| abstract class ParagonIE_Sodium_Crypto32 | |
| { | |
| const aead_chacha20poly1305_KEYBYTES = 32; | |
| const aead_chacha20poly1305_NSECBYTES = 0; | |
| const aead_chacha20poly1305_NPUBBYTES = 8; | |
| const aead_chacha20poly1305_ABYTES = 16; | |
| const aead_chacha20poly1305_IETF_KEYBYTES = 32; | |
| const aead_chacha20poly1305_IETF_NSECBYTES = 0; | |
| const aead_chacha20poly1305_IETF_NPUBBYTES = 12; | |
| const aead_chacha20poly1305_IETF_ABYTES = 16; | |
| const aead_xchacha20poly1305_IETF_KEYBYTES = 32; | |
| const aead_xchacha20poly1305_IETF_NSECBYTES = 0; | |
| const aead_xchacha20poly1305_IETF_NPUBBYTES = 24; | |
| const aead_xchacha20poly1305_IETF_ABYTES = 16; | |
| const box_curve25519xsalsa20poly1305_SEEDBYTES = 32; | |
| const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32; | |
| const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32; | |
| const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32; | |
| const box_curve25519xsalsa20poly1305_NONCEBYTES = 24; | |
| const box_curve25519xsalsa20poly1305_MACBYTES = 16; | |
| const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16; | |
| const box_curve25519xsalsa20poly1305_ZEROBYTES = 32; | |
| const onetimeauth_poly1305_BYTES = 16; | |
| const onetimeauth_poly1305_KEYBYTES = 32; | |
| const secretbox_xsalsa20poly1305_KEYBYTES = 32; | |
| const secretbox_xsalsa20poly1305_NONCEBYTES = 24; | |
| const secretbox_xsalsa20poly1305_MACBYTES = 16; | |
| const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16; | |
| const secretbox_xsalsa20poly1305_ZEROBYTES = 32; | |
| const secretbox_xchacha20poly1305_KEYBYTES = 32; | |
| const secretbox_xchacha20poly1305_NONCEBYTES = 24; | |
| const secretbox_xchacha20poly1305_MACBYTES = 16; | |
| const secretbox_xchacha20poly1305_BOXZEROBYTES = 16; | |
| const secretbox_xchacha20poly1305_ZEROBYTES = 32; | |
| const stream_salsa20_KEYBYTES = 32; | |
| /** | |
| * AEAD Decryption with ChaCha20-Poly1305 | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_chacha20poly1305_decrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| /** @var int $len - Length of message (ciphertext + MAC) */ | |
| $len = ParagonIE_Sodium_Core32_Util::strlen($message); | |
| /** @var int $clen - Length of ciphertext */ | |
| $clen = $len - self::aead_chacha20poly1305_ABYTES; | |
| /** @var int $adlen - Length of associated data */ | |
| $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); | |
| /** @var string $mac - Message authentication code */ | |
| $mac = ParagonIE_Sodium_Core32_Util::substr( | |
| $message, | |
| $clen, | |
| self::aead_chacha20poly1305_ABYTES | |
| ); | |
| /** @var string $ciphertext - The encrypted message (sans MAC) */ | |
| $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen); | |
| /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( | |
| 32, | |
| $nonce, | |
| $key | |
| ); | |
| /* Recalculate the Poly1305 authentication tag (MAC): */ | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| } | |
| $state->update($ad); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); | |
| $state->update($ciphertext); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); | |
| $computed_mac = $state->finish(); | |
| /* Compare the given MAC with the recalculated MAC: */ | |
| if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { | |
| throw new SodiumException('Invalid MAC'); | |
| } | |
| // Here, we know that the MAC is valid, so we decrypt and return the plaintext | |
| return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( | |
| $ciphertext, | |
| $nonce, | |
| $key, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| } | |
| /** | |
| * AEAD Encryption with ChaCha20-Poly1305 | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_chacha20poly1305_encrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| /** @var int $len - Length of the plaintext message */ | |
| $len = ParagonIE_Sodium_Core32_Util::strlen($message); | |
| /** @var int $adlen - Length of the associated data */ | |
| $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); | |
| /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( | |
| 32, | |
| $nonce, | |
| $key | |
| ); | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| } | |
| /** @var string $ciphertext - Raw encrypted data */ | |
| $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( | |
| $message, | |
| $nonce, | |
| $key, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| $state->update($ad); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); | |
| $state->update($ciphertext); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); | |
| return $ciphertext . $state->finish(); | |
| } | |
| /** | |
| * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_chacha20poly1305_ietf_decrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| /** @var int $adlen - Length of associated data */ | |
| $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); | |
| /** @var int $len - Length of message (ciphertext + MAC) */ | |
| $len = ParagonIE_Sodium_Core32_Util::strlen($message); | |
| /** @var int $clen - Length of ciphertext */ | |
| $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; | |
| /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( | |
| 32, | |
| $nonce, | |
| $key | |
| ); | |
| /** @var string $mac - Message authentication code */ | |
| $mac = ParagonIE_Sodium_Core32_Util::substr( | |
| $message, | |
| $len - self::aead_chacha20poly1305_IETF_ABYTES, | |
| self::aead_chacha20poly1305_IETF_ABYTES | |
| ); | |
| /** @var string $ciphertext - The encrypted message (sans MAC) */ | |
| $ciphertext = ParagonIE_Sodium_Core32_Util::substr( | |
| $message, | |
| 0, | |
| $len - self::aead_chacha20poly1305_IETF_ABYTES | |
| ); | |
| /* Recalculate the Poly1305 authentication tag (MAC): */ | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| } | |
| $state->update($ad); | |
| $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); | |
| $state->update($ciphertext); | |
| $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); | |
| $computed_mac = $state->finish(); | |
| /* Compare the given MAC with the recalculated MAC: */ | |
| if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { | |
| throw new SodiumException('Invalid MAC'); | |
| } | |
| // Here, we know that the MAC is valid, so we decrypt and return the plaintext | |
| return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| $ciphertext, | |
| $nonce, | |
| $key, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| } | |
| /** | |
| * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_chacha20poly1305_ietf_encrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| /** @var int $len - Length of the plaintext message */ | |
| $len = ParagonIE_Sodium_Core32_Util::strlen($message); | |
| /** @var int $adlen - Length of the associated data */ | |
| $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); | |
| /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( | |
| 32, | |
| $nonce, | |
| $key | |
| ); | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| } | |
| /** @var string $ciphertext - Raw encrypted data */ | |
| $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| $message, | |
| $nonce, | |
| $key, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| $state->update($ad); | |
| $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); | |
| $state->update($ciphertext); | |
| $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); | |
| $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); | |
| return $ciphertext . $state->finish(); | |
| } | |
| /** | |
| * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_xchacha20poly1305_ietf_decrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), | |
| $key | |
| ); | |
| $nonceLast = "\x00\x00\x00\x00" . | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); | |
| return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); | |
| } | |
| /** | |
| * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $ad | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function aead_xchacha20poly1305_ietf_encrypt( | |
| $message = '', | |
| $ad = '', | |
| $nonce = '', | |
| $key = '' | |
| ) { | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), | |
| $key | |
| ); | |
| $nonceLast = "\x00\x00\x00\x00" . | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); | |
| return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); | |
| } | |
| /** | |
| * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $key | |
| * @return string | |
| * @throws TypeError | |
| */ | |
| public static function auth($message, $key) | |
| { | |
| return ParagonIE_Sodium_Core32_Util::substr( | |
| hash_hmac('sha512', $message, $key, true), | |
| 0, | |
| 32 | |
| ); | |
| } | |
| /** | |
| * HMAC-SHA-512-256 validation. Constant-time via hash_equals(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $mac | |
| * @param string $message | |
| * @param string $key | |
| * @return bool | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function auth_verify($mac, $message, $key) | |
| { | |
| return ParagonIE_Sodium_Core32_Util::hashEquals( | |
| $mac, | |
| self::auth($message, $key) | |
| ); | |
| } | |
| /** | |
| * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $plaintext | |
| * @param string $nonce | |
| * @param string $keypair | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box($plaintext, $nonce, $keypair) | |
| { | |
| return self::secretbox( | |
| $plaintext, | |
| $nonce, | |
| self::box_beforenm( | |
| self::box_secretkey($keypair), | |
| self::box_publickey($keypair) | |
| ) | |
| ); | |
| } | |
| /** | |
| * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $publicKey | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_seal($message, $publicKey) | |
| { | |
| /** @var string $ephemeralKeypair */ | |
| $ephemeralKeypair = self::box_keypair(); | |
| /** @var string $ephemeralSK */ | |
| $ephemeralSK = self::box_secretkey($ephemeralKeypair); | |
| /** @var string $ephemeralPK */ | |
| $ephemeralPK = self::box_publickey($ephemeralKeypair); | |
| /** @var string $nonce */ | |
| $nonce = self::generichash( | |
| $ephemeralPK . $publicKey, | |
| '', | |
| 24 | |
| ); | |
| /** @var string $keypair - The combined keypair used in crypto_box() */ | |
| $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); | |
| /** @var string $ciphertext Ciphertext + MAC from crypto_box */ | |
| $ciphertext = self::box($message, $nonce, $keypair); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); | |
| ParagonIE_Sodium_Compat::memzero($ephemeralSK); | |
| ParagonIE_Sodium_Compat::memzero($nonce); | |
| } catch (SodiumException $ex) { | |
| $ephemeralKeypair = null; | |
| $ephemeralSK = null; | |
| $nonce = null; | |
| } | |
| return $ephemeralPK . $ciphertext; | |
| } | |
| /** | |
| * Opens a message encrypted via box_seal(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $keypair | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_seal_open($message, $keypair) | |
| { | |
| /** @var string $ephemeralPK */ | |
| $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32); | |
| /** @var string $ciphertext (ciphertext + MAC) */ | |
| $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32); | |
| /** @var string $secretKey */ | |
| $secretKey = self::box_secretkey($keypair); | |
| /** @var string $publicKey */ | |
| $publicKey = self::box_publickey($keypair); | |
| /** @var string $nonce */ | |
| $nonce = self::generichash( | |
| $ephemeralPK . $publicKey, | |
| '', | |
| 24 | |
| ); | |
| /** @var string $keypair */ | |
| $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); | |
| /** @var string $m */ | |
| $m = self::box_open($ciphertext, $nonce, $keypair); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($secretKey); | |
| ParagonIE_Sodium_Compat::memzero($ephemeralPK); | |
| ParagonIE_Sodium_Compat::memzero($nonce); | |
| } catch (SodiumException $ex) { | |
| $secretKey = null; | |
| $ephemeralPK = null; | |
| $nonce = null; | |
| } | |
| return $m; | |
| } | |
| /** | |
| * Used by crypto_box() to get the crypto_secretbox() key. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $sk | |
| * @param string $pk | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_beforenm($sk, $pk) | |
| { | |
| return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20( | |
| str_repeat("\x00", 16), | |
| self::scalarmult($sk, $pk) | |
| ); | |
| } | |
| /** | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @return string | |
| * @throws Exception | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_keypair() | |
| { | |
| $sKey = random_bytes(32); | |
| $pKey = self::scalarmult_base($sKey); | |
| return $sKey . $pKey; | |
| } | |
| /** | |
| * @param string $seed | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_seed_keypair($seed) | |
| { | |
| $sKey = ParagonIE_Sodium_Core32_Util::substr( | |
| hash('sha512', $seed, true), | |
| 0, | |
| 32 | |
| ); | |
| $pKey = self::scalarmult_base($sKey); | |
| return $sKey . $pKey; | |
| } | |
| /** | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $sKey | |
| * @param string $pKey | |
| * @return string | |
| * @throws TypeError | |
| */ | |
| public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) | |
| { | |
| return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) . | |
| ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32); | |
| } | |
| /** | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $keypair | |
| * @return string | |
| * @throws RangeException | |
| * @throws TypeError | |
| */ | |
| public static function box_secretkey($keypair) | |
| { | |
| if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) { | |
| throw new RangeException( | |
| 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' | |
| ); | |
| } | |
| return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32); | |
| } | |
| /** | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $keypair | |
| * @return string | |
| * @throws RangeException | |
| * @throws TypeError | |
| */ | |
| public static function box_publickey($keypair) | |
| { | |
| if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { | |
| throw new RangeException( | |
| 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' | |
| ); | |
| } | |
| return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32); | |
| } | |
| /** | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $sKey | |
| * @return string | |
| * @throws RangeException | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_publickey_from_secretkey($sKey) | |
| { | |
| if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { | |
| throw new RangeException( | |
| 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.' | |
| ); | |
| } | |
| return self::scalarmult_base($sKey); | |
| } | |
| /** | |
| * Decrypt a message encrypted with box(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $ciphertext | |
| * @param string $nonce | |
| * @param string $keypair | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function box_open($ciphertext, $nonce, $keypair) | |
| { | |
| return self::secretbox_open( | |
| $ciphertext, | |
| $nonce, | |
| self::box_beforenm( | |
| self::box_secretkey($keypair), | |
| self::box_publickey($keypair) | |
| ) | |
| ); | |
| } | |
| /** | |
| * Calculate a BLAKE2b hash. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string|null $key | |
| * @param int $outlen | |
| * @return string | |
| * @throws RangeException | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function generichash($message, $key = '', $outlen = 32) | |
| { | |
| // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized | |
| ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); | |
| $k = null; | |
| if (!empty($key)) { | |
| /** @var SplFixedArray $k */ | |
| $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); | |
| if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { | |
| throw new RangeException('Invalid key size'); | |
| } | |
| } | |
| /** @var SplFixedArray $in */ | |
| $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); | |
| /** @var SplFixedArray $ctx */ | |
| $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen); | |
| ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count()); | |
| /** @var SplFixedArray $out */ | |
| $out = new SplFixedArray($outlen); | |
| $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out); | |
| /** @var array<int, int> */ | |
| $outArray = $out->toArray(); | |
| return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); | |
| } | |
| /** | |
| * Finalize a BLAKE2b hashing context, returning the hash. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $ctx | |
| * @param int $outlen | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function generichash_final($ctx, $outlen = 32) | |
| { | |
| if (!is_string($ctx)) { | |
| throw new TypeError('Context must be a string'); | |
| } | |
| $out = new SplFixedArray($outlen); | |
| /** @var SplFixedArray $context */ | |
| $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); | |
| /** @var SplFixedArray $out */ | |
| $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out); | |
| /** @var array<int, int> */ | |
| $outArray = $out->toArray(); | |
| return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); | |
| } | |
| /** | |
| * Initialize a hashing context for BLAKE2b. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $key | |
| * @param int $outputLength | |
| * @return string | |
| * @throws RangeException | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function generichash_init($key = '', $outputLength = 32) | |
| { | |
| // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized | |
| ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); | |
| $k = null; | |
| if (!empty($key)) { | |
| $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); | |
| if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { | |
| throw new RangeException('Invalid key size'); | |
| } | |
| } | |
| /** @var SplFixedArray $ctx */ | |
| $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength); | |
| return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); | |
| } | |
| /** | |
| * Initialize a hashing context for BLAKE2b. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $key | |
| * @param int $outputLength | |
| * @param string $salt | |
| * @param string $personal | |
| * @return string | |
| * @throws RangeException | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function generichash_init_salt_personal( | |
| $key = '', | |
| $outputLength = 32, | |
| $salt = '', | |
| $personal = '' | |
| ) { | |
| // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized | |
| ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); | |
| $k = null; | |
| if (!empty($key)) { | |
| $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); | |
| if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { | |
| throw new RangeException('Invalid key size'); | |
| } | |
| } | |
| if (!empty($salt)) { | |
| $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt); | |
| } else { | |
| $s = null; | |
| } | |
| if (!empty($salt)) { | |
| $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal); | |
| } else { | |
| $p = null; | |
| } | |
| /** @var SplFixedArray $ctx */ | |
| $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p); | |
| return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); | |
| } | |
| /** | |
| * Update a hashing context for BLAKE2b with $message | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $ctx | |
| * @param string $message | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function generichash_update($ctx, $message) | |
| { | |
| // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized | |
| ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); | |
| /** @var SplFixedArray $context */ | |
| $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); | |
| /** @var SplFixedArray $in */ | |
| $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); | |
| ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count()); | |
| return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context); | |
| } | |
| /** | |
| * Libsodium's crypto_kx(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $my_sk | |
| * @param string $their_pk | |
| * @param string $client_pk | |
| * @param string $server_pk | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) | |
| { | |
| return self::generichash( | |
| self::scalarmult($my_sk, $their_pk) . | |
| $client_pk . | |
| $server_pk | |
| ); | |
| } | |
| /** | |
| * ECDH over Curve25519 | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $sKey | |
| * @param string $pKey | |
| * @return string | |
| * | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function scalarmult($sKey, $pKey) | |
| { | |
| $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); | |
| self::scalarmult_throw_if_zero($q); | |
| return $q; | |
| } | |
| /** | |
| * ECDH over Curve25519, using the basepoint. | |
| * Used to get a secret key from a public key. | |
| * | |
| * @param string $secret | |
| * @return string | |
| * | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function scalarmult_base($secret) | |
| { | |
| $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret); | |
| self::scalarmult_throw_if_zero($q); | |
| return $q; | |
| } | |
| /** | |
| * This throws an Error if a zero public key was passed to the function. | |
| * | |
| * @param string $q | |
| * @return void | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| protected static function scalarmult_throw_if_zero($q) | |
| { | |
| $d = 0; | |
| for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { | |
| $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]); | |
| } | |
| /* branch-free variant of === 0 */ | |
| if (-(1 & (($d - 1) >> 8))) { | |
| throw new SodiumException('Zero public key is not allowed'); | |
| } | |
| } | |
| /** | |
| * XSalsa20-Poly1305 authenticated symmetric-key encryption. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $plaintext | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function secretbox($plaintext, $nonce, $key) | |
| { | |
| /** @var string $subkey */ | |
| $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); | |
| /** @var string $block0 */ | |
| $block0 = str_repeat("\x00", 32); | |
| /** @var int $mlen - Length of the plaintext message */ | |
| $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); | |
| $mlen0 = $mlen; | |
| if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { | |
| $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; | |
| } | |
| $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); | |
| /** @var string $block0 */ | |
| $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( | |
| $block0, | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| $subkey | |
| ); | |
| /** @var string $c */ | |
| $c = ParagonIE_Sodium_Core32_Util::substr( | |
| $block0, | |
| self::secretbox_xsalsa20poly1305_ZEROBYTES | |
| ); | |
| if ($mlen > $mlen0) { | |
| $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $plaintext, | |
| self::secretbox_xsalsa20poly1305_ZEROBYTES | |
| ), | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| 1, | |
| $subkey | |
| ); | |
| } | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $block0, | |
| 0, | |
| self::onetimeauth_poly1305_KEYBYTES | |
| ) | |
| ); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| ParagonIE_Sodium_Compat::memzero($subkey); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| $subkey = null; | |
| } | |
| $state->update($c); | |
| /** @var string $c - MAC || ciphertext */ | |
| $c = $state->finish() . $c; | |
| unset($state); | |
| return $c; | |
| } | |
| /** | |
| * Decrypt a ciphertext generated via secretbox(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $ciphertext | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function secretbox_open($ciphertext, $nonce, $key) | |
| { | |
| /** @var string $mac */ | |
| $mac = ParagonIE_Sodium_Core32_Util::substr( | |
| $ciphertext, | |
| 0, | |
| self::secretbox_xsalsa20poly1305_MACBYTES | |
| ); | |
| /** @var string $c */ | |
| $c = ParagonIE_Sodium_Core32_Util::substr( | |
| $ciphertext, | |
| self::secretbox_xsalsa20poly1305_MACBYTES | |
| ); | |
| /** @var int $clen */ | |
| $clen = ParagonIE_Sodium_Core32_Util::strlen($c); | |
| /** @var string $subkey */ | |
| $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); | |
| /** @var string $block0 */ | |
| $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( | |
| 64, | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| $subkey | |
| ); | |
| $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( | |
| $mac, | |
| $c, | |
| ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) | |
| ); | |
| if (!$verified) { | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($subkey); | |
| } catch (SodiumException $ex) { | |
| $subkey = null; | |
| } | |
| throw new SodiumException('Invalid MAC'); | |
| } | |
| /** @var string $m - Decrypted message */ | |
| $m = ParagonIE_Sodium_Core32_Util::xorStrings( | |
| ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), | |
| ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) | |
| ); | |
| if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { | |
| // We had more than 1 block, so let's continue to decrypt the rest. | |
| $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $c, | |
| self::secretbox_xsalsa20poly1305_ZEROBYTES | |
| ), | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| 1, | |
| (string) $subkey | |
| ); | |
| } | |
| return $m; | |
| } | |
| /** | |
| * XChaCha20-Poly1305 authenticated symmetric-key encryption. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $plaintext | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) | |
| { | |
| /** @var string $subkey */ | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), | |
| $key | |
| ); | |
| $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); | |
| /** @var string $block0 */ | |
| $block0 = str_repeat("\x00", 32); | |
| /** @var int $mlen - Length of the plaintext message */ | |
| $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); | |
| $mlen0 = $mlen; | |
| if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { | |
| $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; | |
| } | |
| $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); | |
| /** @var string $block0 */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( | |
| $block0, | |
| $nonceLast, | |
| $subkey | |
| ); | |
| /** @var string $c */ | |
| $c = ParagonIE_Sodium_Core32_Util::substr( | |
| $block0, | |
| self::secretbox_xchacha20poly1305_ZEROBYTES | |
| ); | |
| if ($mlen > $mlen0) { | |
| $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $plaintext, | |
| self::secretbox_xchacha20poly1305_ZEROBYTES | |
| ), | |
| $nonceLast, | |
| $subkey, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| } | |
| $state = new ParagonIE_Sodium_Core32_Poly1305_State( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $block0, | |
| 0, | |
| self::onetimeauth_poly1305_KEYBYTES | |
| ) | |
| ); | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($block0); | |
| ParagonIE_Sodium_Compat::memzero($subkey); | |
| } catch (SodiumException $ex) { | |
| $block0 = null; | |
| $subkey = null; | |
| } | |
| $state->update($c); | |
| /** @var string $c - MAC || ciphertext */ | |
| $c = $state->finish() . $c; | |
| unset($state); | |
| return $c; | |
| } | |
| /** | |
| * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $ciphertext | |
| * @param string $nonce | |
| * @param string $key | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) | |
| { | |
| /** @var string $mac */ | |
| $mac = ParagonIE_Sodium_Core32_Util::substr( | |
| $ciphertext, | |
| 0, | |
| self::secretbox_xchacha20poly1305_MACBYTES | |
| ); | |
| /** @var string $c */ | |
| $c = ParagonIE_Sodium_Core32_Util::substr( | |
| $ciphertext, | |
| self::secretbox_xchacha20poly1305_MACBYTES | |
| ); | |
| /** @var int $clen */ | |
| $clen = ParagonIE_Sodium_Core32_Util::strlen($c); | |
| /** @var string $subkey */ | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key); | |
| /** @var string $block0 */ | |
| $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( | |
| 64, | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| $subkey | |
| ); | |
| $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( | |
| $mac, | |
| $c, | |
| ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) | |
| ); | |
| if (!$verified) { | |
| try { | |
| ParagonIE_Sodium_Compat::memzero($subkey); | |
| } catch (SodiumException $ex) { | |
| $subkey = null; | |
| } | |
| throw new SodiumException('Invalid MAC'); | |
| } | |
| /** @var string $m - Decrypted message */ | |
| $m = ParagonIE_Sodium_Core32_Util::xorStrings( | |
| ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), | |
| ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) | |
| ); | |
| if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { | |
| // We had more than 1 block, so let's continue to decrypt the rest. | |
| $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( | |
| ParagonIE_Sodium_Core32_Util::substr( | |
| $c, | |
| self::secretbox_xchacha20poly1305_ZEROBYTES | |
| ), | |
| ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), | |
| (string) $subkey, | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| } | |
| return $m; | |
| } | |
| /** | |
| * @param string $key | |
| * @return array<int, string> Returns a state and a header. | |
| * @throws Exception | |
| * @throws SodiumException | |
| */ | |
| public static function secretstream_xchacha20poly1305_init_push($key) | |
| { | |
| # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); | |
| $out = random_bytes(24); | |
| # crypto_core_hchacha20(state->k, out, k, NULL); | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key); | |
| $state = new ParagonIE_Sodium_Core32_SecretStream_State( | |
| $subkey, | |
| ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4) | |
| ); | |
| # _crypto_secretstream_xchacha20poly1305_counter_reset(state); | |
| $state->counterReset(); | |
| # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, | |
| # crypto_secretstream_xchacha20poly1305_INONCEBYTES); | |
| # memset(state->_pad, 0, sizeof state->_pad); | |
| return array( | |
| $state->toString(), | |
| $out | |
| ); | |
| } | |
| /** | |
| * @param string $key | |
| * @param string $header | |
| * @return string Returns a state. | |
| * @throws Exception | |
| */ | |
| public static function secretstream_xchacha20poly1305_init_pull($key, $header) | |
| { | |
| # crypto_core_hchacha20(state->k, in, k, NULL); | |
| $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( | |
| ParagonIE_Sodium_Core32_Util::substr($header, 0, 16), | |
| $key | |
| ); | |
| $state = new ParagonIE_Sodium_Core32_SecretStream_State( | |
| $subkey, | |
| ParagonIE_Sodium_Core32_Util::substr($header, 16) | |
| ); | |
| $state->counterReset(); | |
| # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, | |
| # crypto_secretstream_xchacha20poly1305_INONCEBYTES); | |
| # memset(state->_pad, 0, sizeof state->_pad); | |
| # return 0; | |
| return $state->toString(); | |
| } | |
| /** | |
| * @param string $state | |
| * @param string $msg | |
| * @param string $aad | |
| * @param int $tag | |
| * @return string | |
| * @throws SodiumException | |
| */ | |
| public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) | |
| { | |
| $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); | |
| # crypto_onetimeauth_poly1305_state poly1305_state; | |
| # unsigned char block[64U]; | |
| # unsigned char slen[8U]; | |
| # unsigned char *c; | |
| # unsigned char *mac; | |
| $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg); | |
| $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); | |
| if ((($msglen + 63) >> 6) > 0xfffffffe) { | |
| throw new SodiumException( | |
| 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' | |
| ); | |
| } | |
| # if (outlen_p != NULL) { | |
| # *outlen_p = 0U; | |
| # } | |
| # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { | |
| # sodium_misuse(); | |
| # } | |
| # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); | |
| # crypto_onetimeauth_poly1305_init(&poly1305_state, block); | |
| # sodium_memzero(block, sizeof block); | |
| $auth = new ParagonIE_Sodium_Core32_Poly1305_State( | |
| ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) | |
| ); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); | |
| $auth->update($aad); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, | |
| # (0x10 - adlen) & 0xf); | |
| $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); | |
| # memset(block, 0, sizeof block); | |
| # block[0] = tag; | |
| # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, | |
| # state->nonce, 1U, state->k); | |
| $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63), | |
| $st->getCombinedNonce(), | |
| $st->getKey(), | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); | |
| $auth->update($block); | |
| # out[0] = block[0]; | |
| $out = $block[0]; | |
| # c = out + (sizeof tag); | |
| # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); | |
| $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| $msg, | |
| $st->getCombinedNonce(), | |
| $st->getKey(), | |
| ParagonIE_Sodium_Core32_Util::store64_le(2) | |
| ); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); | |
| $auth->update($cipher); | |
| $out .= $cipher; | |
| unset($cipher); | |
| # crypto_onetimeauth_poly1305_update | |
| # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); | |
| $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); | |
| # STORE64_LE(slen, (uint64_t) adlen); | |
| $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); | |
| $auth->update($slen); | |
| # STORE64_LE(slen, (sizeof block) + mlen); | |
| $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); | |
| $auth->update($slen); | |
| # mac = c + mlen; | |
| # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); | |
| $mac = $auth->finish(); | |
| $out .= $mac; | |
| # sodium_memzero(&poly1305_state, sizeof poly1305_state); | |
| unset($auth); | |
| # XOR_BUF(STATE_INONCE(state), mac, | |
| # crypto_secretstream_xchacha20poly1305_INONCEBYTES); | |
| $st->xorNonce($mac); | |
| # sodium_increment(STATE_COUNTER(state), | |
| # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); | |
| $st->incrementCounter(); | |
| // Overwrite by reference: | |
| $state = $st->toString(); | |
| /** @var bool $rekey */ | |
| $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; | |
| # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || | |
| # sodium_is_zero(STATE_COUNTER(state), | |
| # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { | |
| # crypto_secretstream_xchacha20poly1305_rekey(state); | |
| # } | |
| if ($rekey || $st->needsRekey()) { | |
| // DO REKEY | |
| self::secretstream_xchacha20poly1305_rekey($state); | |
| } | |
| # if (outlen_p != NULL) { | |
| # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; | |
| # } | |
| return $out; | |
| } | |
| /** | |
| * @param string $state | |
| * @param string $cipher | |
| * @param string $aad | |
| * @return bool|array{0: string, 1: int} | |
| * @throws SodiumException | |
| */ | |
| public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') | |
| { | |
| $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); | |
| $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher); | |
| # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; | |
| $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; | |
| $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); | |
| # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { | |
| # sodium_misuse(); | |
| # } | |
| if ((($msglen + 63) >> 6) > 0xfffffffe) { | |
| throw new SodiumException( | |
| 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' | |
| ); | |
| } | |
| # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); | |
| # crypto_onetimeauth_poly1305_init(&poly1305_state, block); | |
| # sodium_memzero(block, sizeof block); | |
| $auth = new ParagonIE_Sodium_Core32_Poly1305_State( | |
| ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) | |
| ); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); | |
| $auth->update($aad); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, | |
| # (0x10 - adlen) & 0xf); | |
| $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); | |
| # memset(block, 0, sizeof block); | |
| # block[0] = in[0]; | |
| # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, | |
| # state->nonce, 1U, state->k); | |
| $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| $cipher[0] . str_repeat("\0", 63), | |
| $st->getCombinedNonce(), | |
| $st->getKey(), | |
| ParagonIE_Sodium_Core32_Util::store64_le(1) | |
| ); | |
| # tag = block[0]; | |
| # block[0] = in[0]; | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); | |
| $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]); | |
| $block[0] = $cipher[0]; | |
| $auth->update($block); | |
| # c = in + (sizeof tag); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); | |
| $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen)); | |
| # crypto_onetimeauth_poly1305_update | |
| # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); | |
| $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); | |
| # STORE64_LE(slen, (uint64_t) adlen); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); | |
| $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); | |
| $auth->update($slen); | |
| # STORE64_LE(slen, (sizeof block) + mlen); | |
| # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); | |
| $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); | |
| $auth->update($slen); | |
| # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); | |
| # sodium_memzero(&poly1305_state, sizeof poly1305_state); | |
| $mac = $auth->finish(); | |
| # stored_mac = c + mlen; | |
| # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { | |
| # sodium_memzero(mac, sizeof mac); | |
| # return -1; | |
| # } | |
| $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16); | |
| if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) { | |
| return false; | |
| } | |
| # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); | |
| $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen), | |
| $st->getCombinedNonce(), | |
| $st->getKey(), | |
| ParagonIE_Sodium_Core32_Util::store64_le(2) | |
| ); | |
| # XOR_BUF(STATE_INONCE(state), mac, | |
| # crypto_secretstream_xchacha20poly1305_INONCEBYTES); | |
| $st->xorNonce($mac); | |
| # sodium_increment(STATE_COUNTER(state), | |
| # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); | |
| $st->incrementCounter(); | |
| # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || | |
| # sodium_is_zero(STATE_COUNTER(state), | |
| # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { | |
| # crypto_secretstream_xchacha20poly1305_rekey(state); | |
| # } | |
| // Overwrite by reference: | |
| $state = $st->toString(); | |
| /** @var bool $rekey */ | |
| $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; | |
| if ($rekey || $st->needsRekey()) { | |
| // DO REKEY | |
| self::secretstream_xchacha20poly1305_rekey($state); | |
| } | |
| return array($out, $tag); | |
| } | |
| /** | |
| * @param string $state | |
| * @return void | |
| * @throws SodiumException | |
| */ | |
| public static function secretstream_xchacha20poly1305_rekey(&$state) | |
| { | |
| $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); | |
| # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + | |
| # crypto_secretstream_xchacha20poly1305_INONCEBYTES]; | |
| # size_t i; | |
| # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { | |
| # new_key_and_inonce[i] = state->k[i]; | |
| # } | |
| $new_key_and_inonce = $st->getKey(); | |
| # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { | |
| # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = | |
| # STATE_INONCE(state)[i]; | |
| # } | |
| $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8); | |
| # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, | |
| # sizeof new_key_and_inonce, | |
| # state->nonce, state->k); | |
| $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( | |
| $new_key_and_inonce, | |
| $st->getCombinedNonce(), | |
| $st->getKey(), | |
| ParagonIE_Sodium_Core32_Util::store64_le(0) | |
| )); | |
| # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { | |
| # state->k[i] = new_key_and_inonce[i]; | |
| # } | |
| # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { | |
| # STATE_INONCE(state)[i] = | |
| # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; | |
| # } | |
| # _crypto_secretstream_xchacha20poly1305_counter_reset(state); | |
| $st->counterReset(); | |
| $state = $st->toString(); | |
| } | |
| /** | |
| * Detached Ed25519 signature. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $sk | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function sign_detached($message, $sk) | |
| { | |
| return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk); | |
| } | |
| /** | |
| * Attached Ed25519 signature. (Returns a signed message.) | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $message | |
| * @param string $sk | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function sign($message, $sk) | |
| { | |
| return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk); | |
| } | |
| /** | |
| * Opens a signed message. If valid, returns the message. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $signedMessage | |
| * @param string $pk | |
| * @return string | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function sign_open($signedMessage, $pk) | |
| { | |
| return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk); | |
| } | |
| /** | |
| * Verify a detached signature of a given message and public key. | |
| * | |
| * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. | |
| * | |
| * @param string $signature | |
| * @param string $message | |
| * @param string $pk | |
| * @return bool | |
| * @throws SodiumException | |
| * @throws TypeError | |
| */ | |
| public static function sign_verify_detached($signature, $message, $pk) | |
| { | |
| return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk); | |
| } | |
| } | |