diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/sodium_compat/src/Crypto.php --- a/wp/wp-includes/sodium_compat/src/Crypto.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/sodium_compat/src/Crypto.php Tue Dec 15 13:49:49 2020 +0100 @@ -778,6 +778,53 @@ } /** + * 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_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + if (!empty($key)) { + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + if (!empty($salt)) { + $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt); + } else { + $s = null; + } + if (!empty($salt)) { + $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal); + } else { + $p = null; + } + + /** @var SplFixedArray $ctx */ + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p); + + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); + } + + /** * Update a hashing context for BLAKE2b with $message * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. @@ -1186,6 +1233,362 @@ } /** + * @param string $key + * @return array 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_Core_HChaCha20::hChaCha20($out, $key); + $state = new ParagonIE_Sodium_Core_SecretStream_State( + $subkey, + ParagonIE_Sodium_Core_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_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($header, 0, 16), + $key + ); + $state = new ParagonIE_Sodium_Core_SecretStream_State( + $subkey, + ParagonIE_Sodium_Core_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_Core_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_Core_Util::strlen($msg); + $aadlen = ParagonIE_Sodium_Core_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_Core_Poly1305_State( + ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStreamXorIc( + ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStreamXorIc( + $msg, + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_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_Core_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_Core_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_Core_SecretStream_State::fromString($state); + + $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher); + # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; + $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; + $aadlen = ParagonIE_Sodium_Core_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_Core_Poly1305_State( + ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStreamXorIc( + $cipher[0] . str_repeat("\0", 63), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + # tag = block[0]; + # block[0] = in[0]; + # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + $tag = ParagonIE_Sodium_Core_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_Core_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_Core_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_Core_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_Core_Util::substr($cipher, $msglen + 1, 16); + if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) { + return false; + } + + # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); + $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_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_Core_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_Core_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_Core_ChaCha20::ietfStreamXorIc( + $new_key_and_inonce, + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_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.