mirror of
https://github.com/WordPress/WordPress.git
synced 2024-12-22 09:07:59 +01:00
Upgrade/Install: Add missing files from the sodium_compat v1.21.1 update.
Follow-up to [58752]. Props paulkevan. See #61686. Built from https://develop.svn.wordpress.org/trunk@58753 git-svn-id: http://core.svn.wordpress.org/trunk@58155 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
f0b4b44d1e
commit
3870065e31
130
wp-includes/sodium_compat/lib/php84compat.php
Normal file
130
wp-includes/sodium_compat/lib/php84compat.php
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once dirname(dirname(__FILE__)) . '/autoload.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file will monkey patch the pure-PHP implementation in place of the
|
||||||
|
* PECL functions and constants, but only if they do not already exist.
|
||||||
|
*
|
||||||
|
* Thus, the functions or constants just proxy to the appropriate
|
||||||
|
* ParagonIE_Sodium_Compat method or class constant, respectively.
|
||||||
|
*/
|
||||||
|
foreach (array(
|
||||||
|
'CRYPTO_AEAD_AESGIS128L_KEYBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS128L_NSECBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS128L_NPUBBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS128L_ABYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS256_KEYBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS256_NSECBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS256_NPUBBYTES',
|
||||||
|
'CRYPTO_AEAD_AESGIS256_ABYTES',
|
||||||
|
) as $constant
|
||||||
|
) {
|
||||||
|
if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
|
||||||
|
define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_callable('sodium_crypto_aead_aegis128l_decrypt')) {
|
||||||
|
/**
|
||||||
|
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt()
|
||||||
|
* @param string $ciphertext
|
||||||
|
* @param string $additional_data
|
||||||
|
* @param string $nonce
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
function sodium_crypto_aead_aegis128l_decrypt(
|
||||||
|
$ciphertext,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$key
|
||||||
|
) {
|
||||||
|
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt(
|
||||||
|
$ciphertext,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_callable('sodium_crypto_aead_aegis128l_encrypt')) {
|
||||||
|
/**
|
||||||
|
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt()
|
||||||
|
* @param string $message
|
||||||
|
* @param string $additional_data
|
||||||
|
* @param string $nonce
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
* @throws TypeError
|
||||||
|
*/
|
||||||
|
function sodium_crypto_aead_aegis128l_encrypt(
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$message,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$key
|
||||||
|
) {
|
||||||
|
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt(
|
||||||
|
$message,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_callable('sodium_crypto_aead_aegis256_decrypt')) {
|
||||||
|
/**
|
||||||
|
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
|
||||||
|
* @param string $ciphertext
|
||||||
|
* @param string $additional_data
|
||||||
|
* @param string $nonce
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
function sodium_crypto_aead_aegis256_decrypt(
|
||||||
|
$ciphertext,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$key
|
||||||
|
) {
|
||||||
|
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_decrypt(
|
||||||
|
$ciphertext,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_callable('sodium_crypto_aead_aegis256_encrypt')) {
|
||||||
|
/**
|
||||||
|
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
|
||||||
|
* @param string $message
|
||||||
|
* @param string $additional_data
|
||||||
|
* @param string $nonce
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
* @throws TypeError
|
||||||
|
*/
|
||||||
|
function sodium_crypto_aead_aegis256_encrypt(
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$message,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
#[\SensitiveParameter]
|
||||||
|
$key
|
||||||
|
) {
|
||||||
|
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt(
|
||||||
|
$message,
|
||||||
|
$additional_data,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
10
wp-includes/sodium_compat/lib/php84compat_const.php
Normal file
10
wp-includes/sodium_compat/lib/php84compat_const.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 32;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS128L_ABYTES = 32;
|
||||||
|
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES = 32;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS256_NSECBYTES = 0;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32;
|
||||||
|
const SODIUM_CRYPTO_AEAD_AEGIS256_ABYTES = 32;
|
284
wp-includes/sodium_compat/src/Core/AEGIS/State128L.php
Normal file
284
wp-includes/sodium_compat/src/Core/AEGIS/State128L.php
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
|
||||||
|
}
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParagonIE_Sodium_Core_AEGIS_State128L
|
||||||
|
{
|
||||||
|
/** @var array<int, string> $state */
|
||||||
|
protected $state;
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->state = array_fill(0, 8, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Only use this for unit tests!
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getState()
|
||||||
|
{
|
||||||
|
return array_values($this->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $input
|
||||||
|
* @return self
|
||||||
|
* @throws SodiumException
|
||||||
|
*
|
||||||
|
* @internal Only for unit tests
|
||||||
|
*/
|
||||||
|
public static function initForUnitTests(array $input)
|
||||||
|
{
|
||||||
|
if (count($input) < 8) {
|
||||||
|
throw new SodiumException('invalid input');
|
||||||
|
}
|
||||||
|
$state = new self();
|
||||||
|
for ($i = 0; $i < 8; ++$i) {
|
||||||
|
$state->state[$i] = $input[$i];
|
||||||
|
}
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function init($key, $nonce)
|
||||||
|
{
|
||||||
|
$state = new self();
|
||||||
|
|
||||||
|
// S0 = key ^ nonce
|
||||||
|
$state->state[0] = $key ^ $nonce;
|
||||||
|
// S1 = C1
|
||||||
|
$state->state[1] = SODIUM_COMPAT_AEGIS_C1;
|
||||||
|
// S2 = C0
|
||||||
|
$state->state[2] = SODIUM_COMPAT_AEGIS_C0;
|
||||||
|
// S3 = C1
|
||||||
|
$state->state[3] = SODIUM_COMPAT_AEGIS_C1;
|
||||||
|
// S4 = key ^ nonce
|
||||||
|
$state->state[4] = $key ^ $nonce;
|
||||||
|
// S5 = key ^ C0
|
||||||
|
$state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0;
|
||||||
|
// S6 = key ^ C1
|
||||||
|
$state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1;
|
||||||
|
// S7 = key ^ C0
|
||||||
|
$state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0;
|
||||||
|
|
||||||
|
// Repeat(10, Update(nonce, key))
|
||||||
|
for ($i = 0; $i < 10; ++$i) {
|
||||||
|
$state->update($nonce, $key);
|
||||||
|
}
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $ai
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function absorb($ai)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) {
|
||||||
|
throw new SodiumException('Input must be two AES blocks in size');
|
||||||
|
}
|
||||||
|
$t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16);
|
||||||
|
$t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16);
|
||||||
|
return $this->update($t0, $t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $ci
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public function dec($ci)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) {
|
||||||
|
throw new SodiumException('Input must be two AES blocks in size');
|
||||||
|
}
|
||||||
|
|
||||||
|
// z0 = S6 ^ S1 ^ (S2 & S3)
|
||||||
|
$z0 = $this->state[6]
|
||||||
|
^ $this->state[1]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
// z1 = S2 ^ S5 ^ (S6 & S7)
|
||||||
|
$z1 = $this->state[2]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
|
||||||
|
|
||||||
|
// t0, t1 = Split(xi, 128)
|
||||||
|
$t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16);
|
||||||
|
$t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16);
|
||||||
|
|
||||||
|
// out0 = t0 ^ z0
|
||||||
|
// out1 = t1 ^ z1
|
||||||
|
$out0 = $t0 ^ $z0;
|
||||||
|
$out1 = $t1 ^ $z1;
|
||||||
|
|
||||||
|
// Update(out0, out1)
|
||||||
|
// xi = out0 || out1
|
||||||
|
$this->update($out0, $out1);
|
||||||
|
return $out0 . $out1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $cn
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function decPartial($cn)
|
||||||
|
{
|
||||||
|
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
|
||||||
|
|
||||||
|
// z0 = S6 ^ S1 ^ (S2 & S3)
|
||||||
|
$z0 = $this->state[6]
|
||||||
|
^ $this->state[1]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
// z1 = S2 ^ S5 ^ (S6 & S7)
|
||||||
|
$z1 = $this->state[2]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
|
||||||
|
|
||||||
|
// t0, t1 = Split(ZeroPad(cn, 256), 128)
|
||||||
|
$cn = str_pad($cn, 32, "\0", STR_PAD_RIGHT);
|
||||||
|
$t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16);
|
||||||
|
$t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16);
|
||||||
|
// out0 = t0 ^ z0
|
||||||
|
// out1 = t1 ^ z1
|
||||||
|
$out0 = $t0 ^ $z0;
|
||||||
|
$out1 = $t1 ^ $z1;
|
||||||
|
|
||||||
|
// xn = Truncate(out0 || out1, |cn|)
|
||||||
|
$xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len);
|
||||||
|
|
||||||
|
// v0, v1 = Split(ZeroPad(xn, 256), 128)
|
||||||
|
$padded = str_pad($xn, 32, "\0", STR_PAD_RIGHT);
|
||||||
|
$v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16);
|
||||||
|
$v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16);
|
||||||
|
// Update(v0, v1)
|
||||||
|
$this->update($v0, $v1);
|
||||||
|
|
||||||
|
// return xn
|
||||||
|
return $xn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $xi
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public function enc($xi)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) {
|
||||||
|
throw new SodiumException('Input must be two AES blocks in size');
|
||||||
|
}
|
||||||
|
|
||||||
|
// z0 = S6 ^ S1 ^ (S2 & S3)
|
||||||
|
$z0 = $this->state[6]
|
||||||
|
^ $this->state[1]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
// z1 = S2 ^ S5 ^ (S6 & S7)
|
||||||
|
$z1 = $this->state[2]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
|
||||||
|
|
||||||
|
// t0, t1 = Split(xi, 128)
|
||||||
|
$t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16);
|
||||||
|
$t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16);
|
||||||
|
|
||||||
|
// out0 = t0 ^ z0
|
||||||
|
// out1 = t1 ^ z1
|
||||||
|
$out0 = $t0 ^ $z0;
|
||||||
|
$out1 = $t1 ^ $z1;
|
||||||
|
|
||||||
|
// Update(t0, t1)
|
||||||
|
// ci = out0 || out1
|
||||||
|
$this->update($t0, $t1);
|
||||||
|
|
||||||
|
// return ci
|
||||||
|
return $out0 . $out1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $ad_len_bits
|
||||||
|
* @param int $msg_len_bits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function finalize($ad_len_bits, $msg_len_bits)
|
||||||
|
{
|
||||||
|
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
|
||||||
|
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
|
||||||
|
$t = $this->state[2] ^ $encoded;
|
||||||
|
for ($i = 0; $i < 7; ++$i) {
|
||||||
|
$this->update($t, $t);
|
||||||
|
}
|
||||||
|
return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) .
|
||||||
|
($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $m0
|
||||||
|
* @param string $m1
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function update($m0, $m1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
S'0 = AESRound(S7, S0 ^ M0)
|
||||||
|
S'1 = AESRound(S0, S1)
|
||||||
|
S'2 = AESRound(S1, S2)
|
||||||
|
S'3 = AESRound(S2, S3)
|
||||||
|
S'4 = AESRound(S3, S4 ^ M1)
|
||||||
|
S'5 = AESRound(S4, S5)
|
||||||
|
S'6 = AESRound(S5, S6)
|
||||||
|
S'7 = AESRound(S6, S7)
|
||||||
|
*/
|
||||||
|
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[7], $this->state[0] ^ $m0,
|
||||||
|
$this->state[0], $this->state[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[1], $this->state[2],
|
||||||
|
$this->state[2], $this->state[3]
|
||||||
|
);
|
||||||
|
|
||||||
|
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[3], $this->state[4] ^ $m1,
|
||||||
|
$this->state[4], $this->state[5]
|
||||||
|
);
|
||||||
|
list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[5], $this->state[6],
|
||||||
|
$this->state[6], $this->state[7]
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
S0 = S'0
|
||||||
|
S1 = S'1
|
||||||
|
S2 = S'2
|
||||||
|
S3 = S'3
|
||||||
|
S4 = S'4
|
||||||
|
S5 = S'5
|
||||||
|
S6 = S'6
|
||||||
|
S7 = S'7
|
||||||
|
*/
|
||||||
|
$this->state[0] = $s_0;
|
||||||
|
$this->state[1] = $s_1;
|
||||||
|
$this->state[2] = $s_2;
|
||||||
|
$this->state[3] = $s_3;
|
||||||
|
$this->state[4] = $s_4;
|
||||||
|
$this->state[5] = $s_5;
|
||||||
|
$this->state[6] = $s_6;
|
||||||
|
$this->state[7] = $s_7;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
240
wp-includes/sodium_compat/src/Core/AEGIS/State256.php
Normal file
240
wp-includes/sodium_compat/src/Core/AEGIS/State256.php
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State256', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
|
||||||
|
}
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParagonIE_Sodium_Core_AEGIS_State256
|
||||||
|
{
|
||||||
|
/** @var array<int, string> $state */
|
||||||
|
protected $state;
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->state = array_fill(0, 6, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Only use this for unit tests!
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getState()
|
||||||
|
{
|
||||||
|
return array_values($this->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $input
|
||||||
|
* @return self
|
||||||
|
* @throws SodiumException
|
||||||
|
*
|
||||||
|
* @internal Only for unit tests
|
||||||
|
*/
|
||||||
|
public static function initForUnitTests(array $input)
|
||||||
|
{
|
||||||
|
if (count($input) < 6) {
|
||||||
|
throw new SodiumException('invalid input');
|
||||||
|
}
|
||||||
|
$state = new self();
|
||||||
|
for ($i = 0; $i < 6; ++$i) {
|
||||||
|
$state->state[$i] = $input[$i];
|
||||||
|
}
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function init($key, $nonce)
|
||||||
|
{
|
||||||
|
$state = new self();
|
||||||
|
$k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16);
|
||||||
|
$k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16);
|
||||||
|
$n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16);
|
||||||
|
$n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16);
|
||||||
|
|
||||||
|
// S0 = k0 ^ n0
|
||||||
|
// S1 = k1 ^ n1
|
||||||
|
// S2 = C1
|
||||||
|
// S3 = C0
|
||||||
|
// S4 = k0 ^ C0
|
||||||
|
// S5 = k1 ^ C1
|
||||||
|
$k0_n0 = $k0 ^ $n0;
|
||||||
|
$k1_n1 = $k1 ^ $n1;
|
||||||
|
$state->state[0] = $k0_n0;
|
||||||
|
$state->state[1] = $k1_n1;
|
||||||
|
$state->state[2] = SODIUM_COMPAT_AEGIS_C1;
|
||||||
|
$state->state[3] = SODIUM_COMPAT_AEGIS_C0;
|
||||||
|
$state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0;
|
||||||
|
$state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1;
|
||||||
|
|
||||||
|
// Repeat(4,
|
||||||
|
// Update(k0)
|
||||||
|
// Update(k1)
|
||||||
|
// Update(k0 ^ n0)
|
||||||
|
// Update(k1 ^ n1)
|
||||||
|
// )
|
||||||
|
for ($i = 0; $i < 4; ++$i) {
|
||||||
|
$state->update($k0);
|
||||||
|
$state->update($k1);
|
||||||
|
$state->update($k0 ^ $n0);
|
||||||
|
$state->update($k1 ^ $n1);
|
||||||
|
}
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $ai
|
||||||
|
* @return self
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public function absorb($ai)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) {
|
||||||
|
throw new SodiumException('Input must be an AES block in size');
|
||||||
|
}
|
||||||
|
return $this->update($ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $ci
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public function dec($ci)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) {
|
||||||
|
throw new SodiumException('Input must be an AES block in size');
|
||||||
|
}
|
||||||
|
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
|
||||||
|
$z = $this->state[1]
|
||||||
|
^ $this->state[4]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
$xi = $ci ^ $z;
|
||||||
|
$this->update($xi);
|
||||||
|
return $xi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $cn
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function decPartial($cn)
|
||||||
|
{
|
||||||
|
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
|
||||||
|
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
|
||||||
|
$z = $this->state[1]
|
||||||
|
^ $this->state[4]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
|
||||||
|
// t = ZeroPad(cn, 128)
|
||||||
|
$t = str_pad($cn, 16, "\0", STR_PAD_RIGHT);
|
||||||
|
|
||||||
|
// out = t ^ z
|
||||||
|
$out = $t ^ $z;
|
||||||
|
|
||||||
|
// xn = Truncate(out, |cn|)
|
||||||
|
$xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len);
|
||||||
|
|
||||||
|
// v = ZeroPad(xn, 128)
|
||||||
|
$v = str_pad($xn, 16, "\0", STR_PAD_RIGHT);
|
||||||
|
// Update(v)
|
||||||
|
$this->update($v);
|
||||||
|
|
||||||
|
// return xn
|
||||||
|
return $xn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $xi
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public function enc($xi)
|
||||||
|
{
|
||||||
|
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) {
|
||||||
|
throw new SodiumException('Input must be an AES block in size');
|
||||||
|
}
|
||||||
|
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
|
||||||
|
$z = $this->state[1]
|
||||||
|
^ $this->state[4]
|
||||||
|
^ $this->state[5]
|
||||||
|
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
|
||||||
|
$this->update($xi);
|
||||||
|
return $xi ^ $z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $ad_len_bits
|
||||||
|
* @param int $msg_len_bits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function finalize($ad_len_bits, $msg_len_bits)
|
||||||
|
{
|
||||||
|
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
|
||||||
|
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
|
||||||
|
$t = $this->state[3] ^ $encoded;
|
||||||
|
|
||||||
|
for ($i = 0; $i < 7; ++$i) {
|
||||||
|
$this->update($t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) .
|
||||||
|
($this->state[3] ^ $this->state[4] ^ $this->state[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $m
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function update($m)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
S'0 = AESRound(S5, S0 ^ M)
|
||||||
|
S'1 = AESRound(S0, S1)
|
||||||
|
S'2 = AESRound(S1, S2)
|
||||||
|
S'3 = AESRound(S2, S3)
|
||||||
|
S'4 = AESRound(S3, S4)
|
||||||
|
S'5 = AESRound(S4, S5)
|
||||||
|
*/
|
||||||
|
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[5],$this->state[0] ^ $m,
|
||||||
|
$this->state[0], $this->state[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[1], $this->state[2],
|
||||||
|
$this->state[2], $this->state[3]
|
||||||
|
);
|
||||||
|
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
|
||||||
|
$this->state[3], $this->state[4],
|
||||||
|
$this->state[4], $this->state[5]
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
S0 = S'0
|
||||||
|
S1 = S'1
|
||||||
|
S2 = S'2
|
||||||
|
S3 = S'3
|
||||||
|
S4 = S'4
|
||||||
|
S5 = S'5
|
||||||
|
*/
|
||||||
|
$this->state[0] = $s_0;
|
||||||
|
$this->state[1] = $s_1;
|
||||||
|
$this->state[2] = $s_2;
|
||||||
|
$this->state[3] = $s_3;
|
||||||
|
$this->state[4] = $s_4;
|
||||||
|
$this->state[5] = $s_5;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
119
wp-includes/sodium_compat/src/Core/AEGIS128L.php
Normal file
119
wp-includes/sodium_compat/src/Core/AEGIS128L.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
|
||||||
|
}
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $ct
|
||||||
|
* @param string $tag
|
||||||
|
* @param string $ad
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function decrypt($ct, $tag, $ad, $key, $nonce)
|
||||||
|
{
|
||||||
|
$state = self::init($key, $nonce);
|
||||||
|
$ad_blocks = (self::strlen($ad) + 31) >> 5;
|
||||||
|
for ($i = 0; $i < $ad_blocks; ++$i) {
|
||||||
|
$ai = self::substr($ad, $i << 5, 32);
|
||||||
|
if (self::strlen($ai) < 32) {
|
||||||
|
$ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$state->absorb($ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = '';
|
||||||
|
$cn = self::strlen($ct) & 31;
|
||||||
|
$ct_blocks = self::strlen($ct) >> 5;
|
||||||
|
for ($i = 0; $i < $ct_blocks; ++$i) {
|
||||||
|
$msg .= $state->dec(self::substr($ct, $i << 5, 32));
|
||||||
|
}
|
||||||
|
if ($cn) {
|
||||||
|
$start = $ct_blocks << 5;
|
||||||
|
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
|
||||||
|
}
|
||||||
|
$expected_tag = $state->finalize(
|
||||||
|
self::strlen($ad) << 3,
|
||||||
|
self::strlen($msg) << 3
|
||||||
|
);
|
||||||
|
if (!self::hashEquals($expected_tag, $tag)) {
|
||||||
|
try {
|
||||||
|
// The RFC says to erase msg, so we shall try:
|
||||||
|
ParagonIE_Sodium_Compat::memzero($msg);
|
||||||
|
} catch (SodiumException $ex) {
|
||||||
|
// Do nothing if we cannot memzero
|
||||||
|
}
|
||||||
|
throw new SodiumException('verification failed');
|
||||||
|
}
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $msg
|
||||||
|
* @param string $ad
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function encrypt($msg, $ad, $key, $nonce)
|
||||||
|
{
|
||||||
|
$state = self::init($key, $nonce);
|
||||||
|
// ad_blocks = Split(ZeroPad(ad, 256), 256)
|
||||||
|
// for ai in ad_blocks:
|
||||||
|
// Absorb(ai)
|
||||||
|
$ad_len = self::strlen($ad);
|
||||||
|
$msg_len = self::strlen($msg);
|
||||||
|
$ad_blocks = ($ad_len + 31) >> 5;
|
||||||
|
for ($i = 0; $i < $ad_blocks; ++$i) {
|
||||||
|
$ai = self::substr($ad, $i << 5, 32);
|
||||||
|
if (self::strlen($ai) < 32) {
|
||||||
|
$ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$state->absorb($ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
// msg_blocks = Split(ZeroPad(msg, 256), 256)
|
||||||
|
// for xi in msg_blocks:
|
||||||
|
// ct = ct || Enc(xi)
|
||||||
|
$ct = '';
|
||||||
|
$msg_blocks = ($msg_len + 31) >> 5;
|
||||||
|
for ($i = 0; $i < $msg_blocks; ++$i) {
|
||||||
|
$xi = self::substr($msg, $i << 5, 32);
|
||||||
|
if (self::strlen($xi) < 32) {
|
||||||
|
$xi = str_pad($xi, 32, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$ct .= $state->enc($xi);
|
||||||
|
}
|
||||||
|
// tag = Finalize(|ad|, |msg|)
|
||||||
|
// ct = Truncate(ct, |msg|)
|
||||||
|
$tag = $state->finalize(
|
||||||
|
$ad_len << 3,
|
||||||
|
$msg_len << 3
|
||||||
|
);
|
||||||
|
// return ct and tag
|
||||||
|
return array(
|
||||||
|
self::substr($ct, 0, $msg_len),
|
||||||
|
$tag
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return ParagonIE_Sodium_Core_AEGIS_State128L
|
||||||
|
*/
|
||||||
|
public static function init($key, $nonce)
|
||||||
|
{
|
||||||
|
return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce);
|
||||||
|
}
|
||||||
|
}
|
118
wp-includes/sodium_compat/src/Core/AEGIS256.php
Normal file
118
wp-includes/sodium_compat/src/Core/AEGIS256.php
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
|
||||||
|
}
|
||||||
|
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
|
||||||
|
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParagonIE_Sodium_Core_AEGIS256 extends ParagonIE_Sodium_Core_AES
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $ct
|
||||||
|
* @param string $tag
|
||||||
|
* @param string $ad
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function decrypt($ct, $tag, $ad, $key, $nonce)
|
||||||
|
{
|
||||||
|
$state = self::init($key, $nonce);
|
||||||
|
|
||||||
|
// ad_blocks = Split(ZeroPad(ad, 128), 128)
|
||||||
|
$ad_blocks = (self::strlen($ad) + 15) >> 4;
|
||||||
|
// for ai in ad_blocks:
|
||||||
|
// Absorb(ai)
|
||||||
|
for ($i = 0; $i < $ad_blocks; ++$i) {
|
||||||
|
$ai = self::substr($ad, $i << 4, 16);
|
||||||
|
if (self::strlen($ai) < 16) {
|
||||||
|
$ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$state->absorb($ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = '';
|
||||||
|
$cn = self::strlen($ct) & 15;
|
||||||
|
$ct_blocks = self::strlen($ct) >> 4;
|
||||||
|
// ct_blocks = Split(ZeroPad(ct, 128), 128)
|
||||||
|
// cn = Tail(ct, |ct| mod 128)
|
||||||
|
for ($i = 0; $i < $ct_blocks; ++$i) {
|
||||||
|
$msg .= $state->dec(self::substr($ct, $i << 4, 16));
|
||||||
|
}
|
||||||
|
// if cn is not empty:
|
||||||
|
// msg = msg || DecPartial(cn)
|
||||||
|
if ($cn) {
|
||||||
|
$start = $ct_blocks << 4;
|
||||||
|
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
|
||||||
|
}
|
||||||
|
$expected_tag = $state->finalize(
|
||||||
|
self::strlen($ad) << 3,
|
||||||
|
self::strlen($msg) << 3
|
||||||
|
);
|
||||||
|
if (!self::hashEquals($expected_tag, $tag)) {
|
||||||
|
try {
|
||||||
|
// The RFC says to erase msg, so we shall try:
|
||||||
|
ParagonIE_Sodium_Compat::memzero($msg);
|
||||||
|
} catch (SodiumException $ex) {
|
||||||
|
// Do nothing if we cannot memzero
|
||||||
|
}
|
||||||
|
throw new SodiumException('verification failed');
|
||||||
|
}
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $msg
|
||||||
|
* @param string $ad
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return array
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function encrypt($msg, $ad, $key, $nonce)
|
||||||
|
{
|
||||||
|
$state = self::init($key, $nonce);
|
||||||
|
$ad_len = self::strlen($ad);
|
||||||
|
$msg_len = self::strlen($msg);
|
||||||
|
$ad_blocks = ($ad_len + 15) >> 4;
|
||||||
|
for ($i = 0; $i < $ad_blocks; ++$i) {
|
||||||
|
$ai = self::substr($ad, $i << 4, 16);
|
||||||
|
if (self::strlen($ai) < 16) {
|
||||||
|
$ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$state->absorb($ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ct = '';
|
||||||
|
$msg_blocks = ($msg_len + 15) >> 4;
|
||||||
|
for ($i = 0; $i < $msg_blocks; ++$i) {
|
||||||
|
$xi = self::substr($msg, $i << 4, 16);
|
||||||
|
if (self::strlen($xi) < 16) {
|
||||||
|
$xi = str_pad($xi, 16, "\0", STR_PAD_RIGHT);
|
||||||
|
}
|
||||||
|
$ct .= $state->enc($xi);
|
||||||
|
}
|
||||||
|
$tag = $state->finalize(
|
||||||
|
$ad_len << 3,
|
||||||
|
$msg_len << 3
|
||||||
|
);
|
||||||
|
return array(
|
||||||
|
self::substr($ct, 0, $msg_len),
|
||||||
|
$tag
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param string $nonce
|
||||||
|
* @return ParagonIE_Sodium_Core_AEGIS_State256
|
||||||
|
*/
|
||||||
|
public static function init($key, $nonce)
|
||||||
|
{
|
||||||
|
return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce);
|
||||||
|
}
|
||||||
|
}
|
518
wp-includes/sodium_compat/src/Core/AES.php
Normal file
518
wp-includes/sodium_compat/src/Core/AES.php
Normal file
@ -0,0 +1,518 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AES', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitsliced implementation of the AES block cipher.
|
||||||
|
*
|
||||||
|
* Based on the implementation provided by BearSSL.
|
||||||
|
*
|
||||||
|
* @internal This should only be used by sodium_compat
|
||||||
|
*/
|
||||||
|
class ParagonIE_Sodium_Core_AES extends ParagonIE_Sodium_Core_Util
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int[] AES round constants
|
||||||
|
*/
|
||||||
|
private static $Rcon = array(
|
||||||
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates the values of $q!
|
||||||
|
*
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function sbox(ParagonIE_Sodium_Core_AES_Block $q)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int $x0
|
||||||
|
* @var int $x1
|
||||||
|
* @var int $x2
|
||||||
|
* @var int $x3
|
||||||
|
* @var int $x4
|
||||||
|
* @var int $x5
|
||||||
|
* @var int $x6
|
||||||
|
* @var int $x7
|
||||||
|
*/
|
||||||
|
$x0 = $q[7] & self::U32_MAX;
|
||||||
|
$x1 = $q[6] & self::U32_MAX;
|
||||||
|
$x2 = $q[5] & self::U32_MAX;
|
||||||
|
$x3 = $q[4] & self::U32_MAX;
|
||||||
|
$x4 = $q[3] & self::U32_MAX;
|
||||||
|
$x5 = $q[2] & self::U32_MAX;
|
||||||
|
$x6 = $q[1] & self::U32_MAX;
|
||||||
|
$x7 = $q[0] & self::U32_MAX;
|
||||||
|
|
||||||
|
$y14 = $x3 ^ $x5;
|
||||||
|
$y13 = $x0 ^ $x6;
|
||||||
|
$y9 = $x0 ^ $x3;
|
||||||
|
$y8 = $x0 ^ $x5;
|
||||||
|
$t0 = $x1 ^ $x2;
|
||||||
|
$y1 = $t0 ^ $x7;
|
||||||
|
$y4 = $y1 ^ $x3;
|
||||||
|
$y12 = $y13 ^ $y14;
|
||||||
|
$y2 = $y1 ^ $x0;
|
||||||
|
$y5 = $y1 ^ $x6;
|
||||||
|
$y3 = $y5 ^ $y8;
|
||||||
|
$t1 = $x4 ^ $y12;
|
||||||
|
$y15 = $t1 ^ $x5;
|
||||||
|
$y20 = $t1 ^ $x1;
|
||||||
|
$y6 = $y15 ^ $x7;
|
||||||
|
$y10 = $y15 ^ $t0;
|
||||||
|
$y11 = $y20 ^ $y9;
|
||||||
|
$y7 = $x7 ^ $y11;
|
||||||
|
$y17 = $y10 ^ $y11;
|
||||||
|
$y19 = $y10 ^ $y8;
|
||||||
|
$y16 = $t0 ^ $y11;
|
||||||
|
$y21 = $y13 ^ $y16;
|
||||||
|
$y18 = $x0 ^ $y16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-linear section.
|
||||||
|
*/
|
||||||
|
$t2 = $y12 & $y15;
|
||||||
|
$t3 = $y3 & $y6;
|
||||||
|
$t4 = $t3 ^ $t2;
|
||||||
|
$t5 = $y4 & $x7;
|
||||||
|
$t6 = $t5 ^ $t2;
|
||||||
|
$t7 = $y13 & $y16;
|
||||||
|
$t8 = $y5 & $y1;
|
||||||
|
$t9 = $t8 ^ $t7;
|
||||||
|
$t10 = $y2 & $y7;
|
||||||
|
$t11 = $t10 ^ $t7;
|
||||||
|
$t12 = $y9 & $y11;
|
||||||
|
$t13 = $y14 & $y17;
|
||||||
|
$t14 = $t13 ^ $t12;
|
||||||
|
$t15 = $y8 & $y10;
|
||||||
|
$t16 = $t15 ^ $t12;
|
||||||
|
$t17 = $t4 ^ $t14;
|
||||||
|
$t18 = $t6 ^ $t16;
|
||||||
|
$t19 = $t9 ^ $t14;
|
||||||
|
$t20 = $t11 ^ $t16;
|
||||||
|
$t21 = $t17 ^ $y20;
|
||||||
|
$t22 = $t18 ^ $y19;
|
||||||
|
$t23 = $t19 ^ $y21;
|
||||||
|
$t24 = $t20 ^ $y18;
|
||||||
|
|
||||||
|
$t25 = $t21 ^ $t22;
|
||||||
|
$t26 = $t21 & $t23;
|
||||||
|
$t27 = $t24 ^ $t26;
|
||||||
|
$t28 = $t25 & $t27;
|
||||||
|
$t29 = $t28 ^ $t22;
|
||||||
|
$t30 = $t23 ^ $t24;
|
||||||
|
$t31 = $t22 ^ $t26;
|
||||||
|
$t32 = $t31 & $t30;
|
||||||
|
$t33 = $t32 ^ $t24;
|
||||||
|
$t34 = $t23 ^ $t33;
|
||||||
|
$t35 = $t27 ^ $t33;
|
||||||
|
$t36 = $t24 & $t35;
|
||||||
|
$t37 = $t36 ^ $t34;
|
||||||
|
$t38 = $t27 ^ $t36;
|
||||||
|
$t39 = $t29 & $t38;
|
||||||
|
$t40 = $t25 ^ $t39;
|
||||||
|
|
||||||
|
$t41 = $t40 ^ $t37;
|
||||||
|
$t42 = $t29 ^ $t33;
|
||||||
|
$t43 = $t29 ^ $t40;
|
||||||
|
$t44 = $t33 ^ $t37;
|
||||||
|
$t45 = $t42 ^ $t41;
|
||||||
|
$z0 = $t44 & $y15;
|
||||||
|
$z1 = $t37 & $y6;
|
||||||
|
$z2 = $t33 & $x7;
|
||||||
|
$z3 = $t43 & $y16;
|
||||||
|
$z4 = $t40 & $y1;
|
||||||
|
$z5 = $t29 & $y7;
|
||||||
|
$z6 = $t42 & $y11;
|
||||||
|
$z7 = $t45 & $y17;
|
||||||
|
$z8 = $t41 & $y10;
|
||||||
|
$z9 = $t44 & $y12;
|
||||||
|
$z10 = $t37 & $y3;
|
||||||
|
$z11 = $t33 & $y4;
|
||||||
|
$z12 = $t43 & $y13;
|
||||||
|
$z13 = $t40 & $y5;
|
||||||
|
$z14 = $t29 & $y2;
|
||||||
|
$z15 = $t42 & $y9;
|
||||||
|
$z16 = $t45 & $y14;
|
||||||
|
$z17 = $t41 & $y8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bottom linear transformation.
|
||||||
|
*/
|
||||||
|
$t46 = $z15 ^ $z16;
|
||||||
|
$t47 = $z10 ^ $z11;
|
||||||
|
$t48 = $z5 ^ $z13;
|
||||||
|
$t49 = $z9 ^ $z10;
|
||||||
|
$t50 = $z2 ^ $z12;
|
||||||
|
$t51 = $z2 ^ $z5;
|
||||||
|
$t52 = $z7 ^ $z8;
|
||||||
|
$t53 = $z0 ^ $z3;
|
||||||
|
$t54 = $z6 ^ $z7;
|
||||||
|
$t55 = $z16 ^ $z17;
|
||||||
|
$t56 = $z12 ^ $t48;
|
||||||
|
$t57 = $t50 ^ $t53;
|
||||||
|
$t58 = $z4 ^ $t46;
|
||||||
|
$t59 = $z3 ^ $t54;
|
||||||
|
$t60 = $t46 ^ $t57;
|
||||||
|
$t61 = $z14 ^ $t57;
|
||||||
|
$t62 = $t52 ^ $t58;
|
||||||
|
$t63 = $t49 ^ $t58;
|
||||||
|
$t64 = $z4 ^ $t59;
|
||||||
|
$t65 = $t61 ^ $t62;
|
||||||
|
$t66 = $z1 ^ $t63;
|
||||||
|
$s0 = $t59 ^ $t63;
|
||||||
|
$s6 = $t56 ^ ~$t62;
|
||||||
|
$s7 = $t48 ^ ~$t60;
|
||||||
|
$t67 = $t64 ^ $t65;
|
||||||
|
$s3 = $t53 ^ $t66;
|
||||||
|
$s4 = $t51 ^ $t66;
|
||||||
|
$s5 = $t47 ^ $t65;
|
||||||
|
$s1 = $t64 ^ ~$s3;
|
||||||
|
$s2 = $t55 ^ ~$t67;
|
||||||
|
|
||||||
|
$q[7] = $s0 & self::U32_MAX;
|
||||||
|
$q[6] = $s1 & self::U32_MAX;
|
||||||
|
$q[5] = $s2 & self::U32_MAX;
|
||||||
|
$q[4] = $s3 & self::U32_MAX;
|
||||||
|
$q[3] = $s4 & self::U32_MAX;
|
||||||
|
$q[2] = $s5 & self::U32_MAX;
|
||||||
|
$q[1] = $s6 & self::U32_MAX;
|
||||||
|
$q[0] = $s7 & self::U32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates the values of $q!
|
||||||
|
*
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function invSbox(ParagonIE_Sodium_Core_AES_Block $q)
|
||||||
|
{
|
||||||
|
self::processInversion($q);
|
||||||
|
self::sbox($q);
|
||||||
|
self::processInversion($q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is some boilerplate code needed to invert an S-box. Rather than repeat the code
|
||||||
|
* twice, I moved it to a protected method.
|
||||||
|
*
|
||||||
|
* Mutates $q
|
||||||
|
*
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected static function processInversion(ParagonIE_Sodium_Core_AES_Block $q)
|
||||||
|
{
|
||||||
|
$q0 = (~$q[0]) & self::U32_MAX;
|
||||||
|
$q1 = (~$q[1]) & self::U32_MAX;
|
||||||
|
$q2 = $q[2] & self::U32_MAX;
|
||||||
|
$q3 = $q[3] & self::U32_MAX;
|
||||||
|
$q4 = $q[4] & self::U32_MAX;
|
||||||
|
$q5 = (~$q[5]) & self::U32_MAX;
|
||||||
|
$q6 = (~$q[6]) & self::U32_MAX;
|
||||||
|
$q7 = $q[7] & self::U32_MAX;
|
||||||
|
$q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX;
|
||||||
|
$q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX;
|
||||||
|
$q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX;
|
||||||
|
$q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX;
|
||||||
|
$q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX;
|
||||||
|
$q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX;
|
||||||
|
$q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX;
|
||||||
|
$q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $x
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function subWord($x)
|
||||||
|
{
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
|
||||||
|
array($x, $x, $x, $x, $x, $x, $x, $x)
|
||||||
|
);
|
||||||
|
$q->orthogonalize();
|
||||||
|
self::sbox($q);
|
||||||
|
$q->orthogonalize();
|
||||||
|
return $q[0] & self::U32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the key schedule from a given random key
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return ParagonIE_Sodium_Core_AES_KeySchedule
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function keySchedule($key)
|
||||||
|
{
|
||||||
|
$key_len = self::strlen($key);
|
||||||
|
switch ($key_len) {
|
||||||
|
case 16:
|
||||||
|
$num_rounds = 10;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
$num_rounds = 12;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
$num_rounds = 14;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new SodiumException('Invalid key length: ' . $key_len);
|
||||||
|
}
|
||||||
|
$skey = array();
|
||||||
|
$comp_skey = array();
|
||||||
|
$nk = $key_len >> 2;
|
||||||
|
$nkf = ($num_rounds + 1) << 2;
|
||||||
|
$tmp = 0;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $nk; ++$i) {
|
||||||
|
$tmp = self::load_4(self::substr($key, $i << 2, 4));
|
||||||
|
$skey[($i << 1)] = $tmp;
|
||||||
|
$skey[($i << 1) + 1] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) {
|
||||||
|
if ($j === 0) {
|
||||||
|
$tmp = (($tmp & 0xff) << 24) | ($tmp >> 8);
|
||||||
|
$tmp = (self::subWord($tmp) ^ self::$Rcon[$k]) & self::U32_MAX;
|
||||||
|
} elseif ($nk > 6 && $j === 4) {
|
||||||
|
$tmp = self::subWord($tmp);
|
||||||
|
}
|
||||||
|
$tmp ^= $skey[($i - $nk) << 1];
|
||||||
|
$skey[($i << 1)] = $tmp & self::U32_MAX;
|
||||||
|
$skey[($i << 1) + 1] = $tmp & self::U32_MAX;
|
||||||
|
if (++$j === $nk) {
|
||||||
|
/** @psalm-suppress LoopInvalidation */
|
||||||
|
$j = 0;
|
||||||
|
++$k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < $nkf; $i += 4) {
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
|
||||||
|
array_slice($skey, $i << 1, 8)
|
||||||
|
);
|
||||||
|
$q->orthogonalize();
|
||||||
|
// We have to overwrite $skey since we're not using C pointers like BearSSL did
|
||||||
|
for ($j = 0; $j < 8; ++$j) {
|
||||||
|
$skey[($i << 1) + $j] = $q[$j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) {
|
||||||
|
$comp_skey[$i] = ($skey[$j] & 0x55555555)
|
||||||
|
| ($skey[$j + 1] & 0xAAAAAAAA);
|
||||||
|
}
|
||||||
|
return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates $q
|
||||||
|
*
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_KeySchedule $skey
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @param int $offset
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function addRoundKey(
|
||||||
|
ParagonIE_Sodium_Core_AES_Block $q,
|
||||||
|
ParagonIE_Sodium_Core_AES_KeySchedule $skey,
|
||||||
|
$offset = 0
|
||||||
|
) {
|
||||||
|
$block = $skey->getRoundKey($offset);
|
||||||
|
for ($j = 0; $j < 8; ++$j) {
|
||||||
|
$q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mainly exists for testing, as we need the round key features for AEGIS.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function decryptBlockECB($message, $key)
|
||||||
|
{
|
||||||
|
if (self::strlen($message) !== 16) {
|
||||||
|
throw new SodiumException('decryptBlockECB() expects a 16 byte message');
|
||||||
|
}
|
||||||
|
$skey = self::keySchedule($key)->expand();
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
$q[0] = self::load_4(self::substr($message, 0, 4));
|
||||||
|
$q[2] = self::load_4(self::substr($message, 4, 4));
|
||||||
|
$q[4] = self::load_4(self::substr($message, 8, 4));
|
||||||
|
$q[6] = self::load_4(self::substr($message, 12, 4));
|
||||||
|
|
||||||
|
$q->orthogonalize();
|
||||||
|
self::bitsliceDecryptBlock($skey, $q);
|
||||||
|
$q->orthogonalize();
|
||||||
|
|
||||||
|
return self::store32_le($q[0]) .
|
||||||
|
self::store32_le($q[2]) .
|
||||||
|
self::store32_le($q[4]) .
|
||||||
|
self::store32_le($q[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mainly exists for testing, as we need the round key features for AEGIS.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
* @throws SodiumException
|
||||||
|
*/
|
||||||
|
public static function encryptBlockECB($message, $key)
|
||||||
|
{
|
||||||
|
if (self::strlen($message) !== 16) {
|
||||||
|
throw new SodiumException('encryptBlockECB() expects a 16 byte message');
|
||||||
|
}
|
||||||
|
$comp_skey = self::keySchedule($key);
|
||||||
|
$skey = $comp_skey->expand();
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
$q[0] = self::load_4(self::substr($message, 0, 4));
|
||||||
|
$q[2] = self::load_4(self::substr($message, 4, 4));
|
||||||
|
$q[4] = self::load_4(self::substr($message, 8, 4));
|
||||||
|
$q[6] = self::load_4(self::substr($message, 12, 4));
|
||||||
|
|
||||||
|
$q->orthogonalize();
|
||||||
|
self::bitsliceEncryptBlock($skey, $q);
|
||||||
|
$q->orthogonalize();
|
||||||
|
|
||||||
|
return self::store32_le($q[0]) .
|
||||||
|
self::store32_le($q[2]) .
|
||||||
|
self::store32_le($q[4]) .
|
||||||
|
self::store32_le($q[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates $q
|
||||||
|
*
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function bitsliceEncryptBlock(
|
||||||
|
ParagonIE_Sodium_Core_AES_Expanded $skey,
|
||||||
|
ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
) {
|
||||||
|
self::addRoundKey($q, $skey);
|
||||||
|
for ($u = 1; $u < $skey->getNumRounds(); ++$u) {
|
||||||
|
self::sbox($q);
|
||||||
|
$q->shiftRows();
|
||||||
|
$q->mixColumns();
|
||||||
|
self::addRoundKey($q, $skey, ($u << 3));
|
||||||
|
}
|
||||||
|
self::sbox($q);
|
||||||
|
$q->shiftRows();
|
||||||
|
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $x
|
||||||
|
* @param string $y
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function aesRound($x, $y)
|
||||||
|
{
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
$q[0] = self::load_4(self::substr($x, 0, 4));
|
||||||
|
$q[2] = self::load_4(self::substr($x, 4, 4));
|
||||||
|
$q[4] = self::load_4(self::substr($x, 8, 4));
|
||||||
|
$q[6] = self::load_4(self::substr($x, 12, 4));
|
||||||
|
|
||||||
|
$rk = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
$rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4));
|
||||||
|
$rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4));
|
||||||
|
$rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4));
|
||||||
|
$rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4));
|
||||||
|
|
||||||
|
$q->orthogonalize();
|
||||||
|
self::sbox($q);
|
||||||
|
$q->shiftRows();
|
||||||
|
$q->mixColumns();
|
||||||
|
$q->orthogonalize();
|
||||||
|
// add round key without key schedule:
|
||||||
|
for ($i = 0; $i < 8; ++$i) {
|
||||||
|
$q[$i] ^= $rk[$i];
|
||||||
|
}
|
||||||
|
return self::store32_le($q[0]) .
|
||||||
|
self::store32_le($q[2]) .
|
||||||
|
self::store32_le($q[4]) .
|
||||||
|
self::store32_le($q[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process two AES blocks in one shot.
|
||||||
|
*
|
||||||
|
* @param string $b0 First AES block
|
||||||
|
* @param string $rk0 First round key
|
||||||
|
* @param string $b1 Second AES block
|
||||||
|
* @param string $rk1 Second round key
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public static function doubleRound($b0, $rk0, $b1, $rk1)
|
||||||
|
{
|
||||||
|
$q = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
// First block
|
||||||
|
$q[0] = self::load_4(self::substr($b0, 0, 4));
|
||||||
|
$q[2] = self::load_4(self::substr($b0, 4, 4));
|
||||||
|
$q[4] = self::load_4(self::substr($b0, 8, 4));
|
||||||
|
$q[6] = self::load_4(self::substr($b0, 12, 4));
|
||||||
|
// Second block
|
||||||
|
$q[1] = self::load_4(self::substr($b1, 0, 4));
|
||||||
|
$q[3] = self::load_4(self::substr($b1, 4, 4));
|
||||||
|
$q[5] = self::load_4(self::substr($b1, 8, 4));
|
||||||
|
$q[7] = self::load_4(self::substr($b1, 12, 4));;
|
||||||
|
|
||||||
|
$rk = ParagonIE_Sodium_Core_AES_Block::init();
|
||||||
|
// First round key
|
||||||
|
$rk[0] = self::load_4(self::substr($rk0, 0, 4));
|
||||||
|
$rk[2] = self::load_4(self::substr($rk0, 4, 4));
|
||||||
|
$rk[4] = self::load_4(self::substr($rk0, 8, 4));
|
||||||
|
$rk[6] = self::load_4(self::substr($rk0, 12, 4));
|
||||||
|
// Second round key
|
||||||
|
$rk[1] = self::load_4(self::substr($rk1, 0, 4));
|
||||||
|
$rk[3] = self::load_4(self::substr($rk1, 4, 4));
|
||||||
|
$rk[5] = self::load_4(self::substr($rk1, 8, 4));
|
||||||
|
$rk[7] = self::load_4(self::substr($rk1, 12, 4));
|
||||||
|
|
||||||
|
$q->orthogonalize();
|
||||||
|
self::sbox($q);
|
||||||
|
$q->shiftRows();
|
||||||
|
$q->mixColumns();
|
||||||
|
$q->orthogonalize();
|
||||||
|
// add round key without key schedule:
|
||||||
|
for ($i = 0; $i < 8; ++$i) {
|
||||||
|
$q[$i] ^= $rk[$i];
|
||||||
|
}
|
||||||
|
return array(
|
||||||
|
self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]),
|
||||||
|
self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
|
||||||
|
* @param ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function bitsliceDecryptBlock(
|
||||||
|
ParagonIE_Sodium_Core_AES_Expanded $skey,
|
||||||
|
ParagonIE_Sodium_Core_AES_Block $q
|
||||||
|
) {
|
||||||
|
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
|
||||||
|
for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) {
|
||||||
|
$q->inverseShiftRows();
|
||||||
|
self::invSbox($q);
|
||||||
|
self::addRoundKey($q, $skey, ($u << 3));
|
||||||
|
$q->inverseMixColumns();
|
||||||
|
}
|
||||||
|
$q->inverseShiftRows();
|
||||||
|
self::invSbox($q);
|
||||||
|
self::addRoundKey($q, $skey, ($u << 3));
|
||||||
|
}
|
||||||
|
}
|
343
wp-includes/sodium_compat/src/Core/AES/Block.php
Normal file
343
wp-includes/sodium_compat/src/Core/AES/Block.php
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal This should only be used by sodium_compat
|
||||||
|
*/
|
||||||
|
class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<int, int>
|
||||||
|
*/
|
||||||
|
protected $values = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $size
|
||||||
|
*/
|
||||||
|
public function __construct($size = 8)
|
||||||
|
{
|
||||||
|
parent::__construct($size);
|
||||||
|
$this->size = $size;
|
||||||
|
$this->values = array_fill(0, $size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function init()
|
||||||
|
{
|
||||||
|
return new self(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal You should not use this directly from another application
|
||||||
|
*
|
||||||
|
* @param array<int, int> $array
|
||||||
|
* @param bool $save_indexes
|
||||||
|
* @return self
|
||||||
|
*
|
||||||
|
* @psalm-suppress MethodSignatureMismatch
|
||||||
|
*/
|
||||||
|
#[ReturnTypeWillChange]
|
||||||
|
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_AES_Block();
|
||||||
|
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 MethodSignatureMismatch
|
||||||
|
* @psalm-suppress MixedArrayOffset
|
||||||
|
*/
|
||||||
|
#[ReturnTypeWillChange]
|
||||||
|
public function offsetSet($offset, $value)
|
||||||
|
{
|
||||||
|
if (!is_int($value)) {
|
||||||
|
throw new InvalidArgumentException('Expected an integer');
|
||||||
|
}
|
||||||
|
if (is_null($offset)) {
|
||||||
|
$this->values[] = $value;
|
||||||
|
} else {
|
||||||
|
$this->values[$offset] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal You should not use this directly from another application
|
||||||
|
*
|
||||||
|
* @param int $offset
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @psalm-suppress MethodSignatureMismatch
|
||||||
|
* @psalm-suppress MixedArrayOffset
|
||||||
|
*/
|
||||||
|
#[ReturnTypeWillChange]
|
||||||
|
public function offsetExists($offset)
|
||||||
|
{
|
||||||
|
return isset($this->values[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal You should not use this directly from another application
|
||||||
|
*
|
||||||
|
* @param int $offset
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-suppress MethodSignatureMismatch
|
||||||
|
* @psalm-suppress MixedArrayOffset
|
||||||
|
*/
|
||||||
|
#[ReturnTypeWillChange]
|
||||||
|
public function offsetUnset($offset)
|
||||||
|
{
|
||||||
|
unset($this->values[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal You should not use this directly from another application
|
||||||
|
*
|
||||||
|
* @param int $offset
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @psalm-suppress MethodSignatureMismatch
|
||||||
|
* @psalm-suppress MixedArrayOffset
|
||||||
|
*/
|
||||||
|
#[ReturnTypeWillChange]
|
||||||
|
public function offsetGet($offset)
|
||||||
|
{
|
||||||
|
if (!isset($this->values[$offset])) {
|
||||||
|
$this->values[$offset] = 0;
|
||||||
|
}
|
||||||
|
return (int) ($this->values[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal You should not use this directly from another application
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function __debugInfo()
|
||||||
|
{
|
||||||
|
$out = array();
|
||||||
|
foreach ($this->values as $v) {
|
||||||
|
$out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
return array(implode(', ', $out));
|
||||||
|
/*
|
||||||
|
return array(implode(', ', $this->values));
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $cl low bit mask
|
||||||
|
* @param int $ch high bit mask
|
||||||
|
* @param int $s shift
|
||||||
|
* @param int $x index 1
|
||||||
|
* @param int $y index 2
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function swapN($cl, $ch, $s, $x, $y)
|
||||||
|
{
|
||||||
|
static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$a = $this->values[$x] & $u32mask;
|
||||||
|
$b = $this->values[$y] & $u32mask;
|
||||||
|
// (x) = (a & cl) | ((b & cl) << (s));
|
||||||
|
$this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask);
|
||||||
|
// (y) = ((a & ch) >> (s)) | (b & ch);
|
||||||
|
$this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $x index 1
|
||||||
|
* @param int $y index 2
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function swap2($x, $y)
|
||||||
|
{
|
||||||
|
return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $x index 1
|
||||||
|
* @param int $y index 2
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function swap4($x, $y)
|
||||||
|
{
|
||||||
|
return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $x index 1
|
||||||
|
* @param int $y index 2
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function swap8($x, $y)
|
||||||
|
{
|
||||||
|
return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function orthogonalize()
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->swap2(0, 1)
|
||||||
|
->swap2(2, 3)
|
||||||
|
->swap2(4, 5)
|
||||||
|
->swap2(6, 7)
|
||||||
|
|
||||||
|
->swap4(0, 2)
|
||||||
|
->swap4(1, 3)
|
||||||
|
->swap4(4, 6)
|
||||||
|
->swap4(5, 7)
|
||||||
|
|
||||||
|
->swap8(0, 4)
|
||||||
|
->swap8(1, 5)
|
||||||
|
->swap8(2, 6)
|
||||||
|
->swap8(3, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function shiftRows()
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < 8; ++$i) {
|
||||||
|
$x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$this->values[$i] = (
|
||||||
|
($x & 0x000000FF)
|
||||||
|
| (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6)
|
||||||
|
| (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4)
|
||||||
|
| (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2)
|
||||||
|
) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $x
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function rotr16($x)
|
||||||
|
{
|
||||||
|
return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function mixColumns()
|
||||||
|
{
|
||||||
|
$q0 = $this->values[0];
|
||||||
|
$q1 = $this->values[1];
|
||||||
|
$q2 = $this->values[2];
|
||||||
|
$q3 = $this->values[3];
|
||||||
|
$q4 = $this->values[4];
|
||||||
|
$q5 = $this->values[5];
|
||||||
|
$q6 = $this->values[6];
|
||||||
|
$q7 = $this->values[7];
|
||||||
|
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
|
||||||
|
$this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
|
||||||
|
$this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
|
||||||
|
$this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
|
||||||
|
$this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
|
||||||
|
$this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
|
||||||
|
$this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
|
||||||
|
$this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
|
||||||
|
$this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function inverseMixColumns()
|
||||||
|
{
|
||||||
|
$q0 = $this->values[0];
|
||||||
|
$q1 = $this->values[1];
|
||||||
|
$q2 = $this->values[2];
|
||||||
|
$q3 = $this->values[3];
|
||||||
|
$q4 = $this->values[4];
|
||||||
|
$q5 = $this->values[5];
|
||||||
|
$q6 = $this->values[6];
|
||||||
|
$q7 = $this->values[7];
|
||||||
|
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
|
||||||
|
$this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
|
||||||
|
$this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
|
||||||
|
$this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
|
||||||
|
$this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
|
||||||
|
$this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
|
||||||
|
$this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
|
||||||
|
$this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
|
||||||
|
$this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function inverseShiftRows()
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < 8; ++$i) {
|
||||||
|
$x = $this->values[$i];
|
||||||
|
$this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & (
|
||||||
|
($x & 0x000000FF)
|
||||||
|
| (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6)
|
||||||
|
| (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4)
|
||||||
|
| (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
14
wp-includes/sodium_compat/src/Core/AES/Expanded.php
Normal file
14
wp-includes/sodium_compat/src/Core/AES/Expanded.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AES_Expanded', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal This should only be used by sodium_compat
|
||||||
|
*/
|
||||||
|
class ParagonIE_Sodium_Core_AES_Expanded extends ParagonIE_Sodium_Core_AES_KeySchedule
|
||||||
|
{
|
||||||
|
/** @var bool $expanded */
|
||||||
|
protected $expanded = true;
|
||||||
|
}
|
82
wp-includes/sodium_compat/src/Core/AES/KeySchedule.php
Normal file
82
wp-includes/sodium_compat/src/Core/AES/KeySchedule.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal This should only be used by sodium_compat
|
||||||
|
*/
|
||||||
|
class ParagonIE_Sodium_Core_AES_KeySchedule
|
||||||
|
{
|
||||||
|
/** @var array<int, int> $skey -- has size 120 */
|
||||||
|
protected $skey;
|
||||||
|
|
||||||
|
/** @var bool $expanded */
|
||||||
|
protected $expanded = false;
|
||||||
|
|
||||||
|
/** @var int $numRounds */
|
||||||
|
private $numRounds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $skey
|
||||||
|
* @param int $numRounds
|
||||||
|
*/
|
||||||
|
public function __construct(array $skey, $numRounds = 10)
|
||||||
|
{
|
||||||
|
$this->skey = $skey;
|
||||||
|
$this->numRounds = $numRounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value at an arbitrary index. Mostly used for unit testing.
|
||||||
|
*
|
||||||
|
* @param int $i
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function get($i)
|
||||||
|
{
|
||||||
|
return $this->skey[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getNumRounds()
|
||||||
|
{
|
||||||
|
return $this->numRounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @return ParagonIE_Sodium_Core_AES_Block
|
||||||
|
*/
|
||||||
|
public function getRoundKey($offset)
|
||||||
|
{
|
||||||
|
return ParagonIE_Sodium_Core_AES_Block::fromArray(
|
||||||
|
array_slice($this->skey, $offset, 8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an expanded key schedule
|
||||||
|
*
|
||||||
|
* @return ParagonIE_Sodium_Core_AES_Expanded
|
||||||
|
*/
|
||||||
|
public function expand()
|
||||||
|
{
|
||||||
|
$exp = new ParagonIE_Sodium_Core_AES_Expanded(
|
||||||
|
array_fill(0, 120, 0),
|
||||||
|
$this->numRounds
|
||||||
|
);
|
||||||
|
$n = ($exp->numRounds + 1) << 2;
|
||||||
|
for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) {
|
||||||
|
$x = $y = $this->skey[$u];
|
||||||
|
$x &= 0x55555555;
|
||||||
|
$exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
$y &= 0xAAAAAAAA;
|
||||||
|
$exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
|
||||||
|
}
|
||||||
|
return $exp;
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '6.7-alpha-58752';
|
$wp_version = '6.7-alpha-58753';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
Loading…
Reference in New Issue
Block a user