diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5798531e..2b7e6858 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,8 +38,7 @@ jobs: strategy: matrix: operating-system: ['ubuntu-latest'] - php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] - # php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - name: Checkout diff --git a/autoload-phpunit.php b/autoload-phpunit.php index 7c180faf..44060056 100644 --- a/autoload-phpunit.php +++ b/autoload-phpunit.php @@ -6,3 +6,6 @@ require_once (dirname(__FILE__) . '/tests/phpunit-shim.php'); } require_once (dirname(__FILE__) . '/autoload.php'); +if (PHP_VERSION_ID >= 50300) { + require_once(dirname(__FILE__) . '/lib/php84compat.php'); +} diff --git a/autoload.php b/autoload.php index fd12f87b..bfd9e4a0 100644 --- a/autoload.php +++ b/autoload.php @@ -54,6 +54,9 @@ function sodiumCompatAutoloader($class) // unless PHP >= 5.3.0 require_once dirname(__FILE__) . '/lib/namespaced.php'; require_once dirname(__FILE__) . '/lib/sodium_compat.php'; + if (!defined('SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES')) { + require_once dirname(__FILE__) . '/lib/php84compat_const.php'; + } } else { require_once dirname(__FILE__) . '/src/PHP52/SplFixedArray.php'; } @@ -71,5 +74,8 @@ function sodiumCompatAutoloader($class) // Older versions of {PHP, ext/sodium} will not define these require_once(dirname(__FILE__) . '/lib/php72compat.php'); } +if (PHP_VERSION_ID < 80400 || !extension_loaded('sodium')) { + require_once dirname(__FILE__) . '/lib/php84compat.php'; +} require_once(dirname(__FILE__) . '/lib/stream-xchacha20.php'); require_once(dirname(__FILE__) . '/lib/ristretto255.php'); diff --git a/lib/php72compat.php b/lib/php72compat.php index ee81d4e7..f813e563 100644 --- a/lib/php72compat.php +++ b/lib/php72compat.php @@ -14,14 +14,6 @@ 'BASE64_VARIANT_ORIGINAL_NO_PADDING', 'BASE64_VARIANT_URLSAFE', 'BASE64_VARIANT_URLSAFE_NO_PADDING', - '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', 'CRYPTO_AEAD_AES256GCM_KEYBYTES', 'CRYPTO_AEAD_AES256GCM_NSECBYTES', 'CRYPTO_AEAD_AES256GCM_NPUBBYTES', @@ -184,88 +176,6 @@ function sodium_compare($string1, $string2) return ParagonIE_Sodium_Compat::compare($string1, $string2); } } -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, $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($message, $additional_data, $nonce, $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, $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($message, $additional_data, $nonce, $key) - { - return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt( - $message, - $additional_data, - $nonce, - $key - ); - } -} if (!is_callable('sodium_crypto_aead_aes256gcm_decrypt')) { /** * @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt() diff --git a/lib/php84compat.php b/lib/php84compat.php new file mode 100644 index 00000000..d7a317ce --- /dev/null +++ b/lib/php84compat.php @@ -0,0 +1,108 @@ +<?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, $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($message, $additional_data, $nonce, $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, $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($message, $additional_data, $nonce, $key) + { + return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt( + $message, + $additional_data, + $nonce, + $key + ); + } +} diff --git a/lib/php84compat_const.php b/lib/php84compat_const.php new file mode 100644 index 00000000..ee1ed911 --- /dev/null +++ b/lib/php84compat_const.php @@ -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; diff --git a/src/Core/AES/Block.php b/src/Core/AES/Block.php index 47ff4a69..070eb8d3 100644 --- a/src/Core/AES/Block.php +++ b/src/Core/AES/Block.php @@ -18,7 +18,10 @@ class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray * @var int */ protected $size; - + + /** + * @param int $size + */ public function __construct($size = 8) { parent::__construct($size); @@ -26,6 +29,9 @@ public function __construct($size = 8) $this->values = array_fill(0, $size, 0); } + /** + * @return self + */ public static function init() { return new self(8); @@ -37,6 +43,8 @@ public static function init() * @param array<int, int> $array * @param bool $save_indexes * @return self + * + * @psalm-suppress MethodSignatureMismatch */ #[ReturnTypeWillChange] public static function fromArray($array, $save_indexes = null) @@ -70,6 +78,8 @@ public static function fromArray($array, $save_indexes = null) * @param int|null $offset * @param int $value * @return void + * + * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] @@ -90,6 +100,8 @@ public function offsetSet($offset, $value) * * @param int $offset * @return bool + * + * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] @@ -103,6 +115,8 @@ public function offsetExists($offset) * * @param int $offset * @return void + * + * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] @@ -116,6 +130,8 @@ public function offsetUnset($offset) * * @param int $offset * @return int + * + * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] diff --git a/src/Core/Curve25519/Ge/Cached.php b/src/Core/Curve25519/Ge/Cached.php index 39bf8977..06774ba4 100644 --- a/src/Core/Curve25519/Ge/Cached.php +++ b/src/Core/Curve25519/Ge/Cached.php @@ -40,26 +40,38 @@ class ParagonIE_Sodium_Core_Curve25519_Ge_Cached * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d */ public function __construct( - ParagonIE_Sodium_Core_Curve25519_Fe $YplusX = null, - ParagonIE_Sodium_Core_Curve25519_Fe $YminusX = null, - ParagonIE_Sodium_Core_Curve25519_Fe $Z = null, - ParagonIE_Sodium_Core_Curve25519_Fe $T2d = null + $YplusX = null, + $YminusX = null, + $Z = null, + $T2d = null ) { if ($YplusX === null) { $YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($YplusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->YplusX = $YplusX; if ($YminusX === null) { $YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($YminusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->YminusX = $YminusX; if ($Z === null) { $Z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Z = $Z; if ($T2d === null) { $T2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($T2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->T2d = $T2d; } } diff --git a/src/Core/Curve25519/Ge/P1p1.php b/src/Core/Curve25519/Ge/P1p1.php index a63d6ab2..62d36eb0 100644 --- a/src/Core/Curve25519/Ge/P1p1.php +++ b/src/Core/Curve25519/Ge/P1p1.php @@ -39,26 +39,38 @@ class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( - ParagonIE_Sodium_Core_Curve25519_Fe $x = null, - ParagonIE_Sodium_Core_Curve25519_Fe $y = null, - ParagonIE_Sodium_Core_Curve25519_Fe $z = null, - ParagonIE_Sodium_Core_Curve25519_Fe $t = null + $x = null, + $y = null, + $z = null, + $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->T = $t; } } diff --git a/src/Core/Curve25519/Ge/P2.php b/src/Core/Curve25519/Ge/P2.php index aee4000d..029be720 100644 --- a/src/Core/Curve25519/Ge/P2.php +++ b/src/Core/Curve25519/Ge/P2.php @@ -34,21 +34,30 @@ class ParagonIE_Sodium_Core_Curve25519_Ge_P2 * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z */ public function __construct( - ParagonIE_Sodium_Core_Curve25519_Fe $x = null, - ParagonIE_Sodium_Core_Curve25519_Fe $y = null, - ParagonIE_Sodium_Core_Curve25519_Fe $z = null + $x = null, + $y = null, + $z = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Z = $z; } } diff --git a/src/Core/Curve25519/Ge/P3.php b/src/Core/Curve25519/Ge/P3.php index 00f5b27a..e5b2fe45 100644 --- a/src/Core/Curve25519/Ge/P3.php +++ b/src/Core/Curve25519/Ge/P3.php @@ -40,26 +40,38 @@ class ParagonIE_Sodium_Core_Curve25519_Ge_P3 * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( - ParagonIE_Sodium_Core_Curve25519_Fe $x = null, - ParagonIE_Sodium_Core_Curve25519_Fe $y = null, - ParagonIE_Sodium_Core_Curve25519_Fe $z = null, - ParagonIE_Sodium_Core_Curve25519_Fe $t = null + $x = null, + $y = null, + $z = null, + $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->T = $t; } } diff --git a/src/Core/Curve25519/Ge/Precomp.php b/src/Core/Curve25519/Ge/Precomp.php index 59611c10..2503d7a6 100644 --- a/src/Core/Curve25519/Ge/Precomp.php +++ b/src/Core/Curve25519/Ge/Precomp.php @@ -34,21 +34,30 @@ class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp * @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d */ public function __construct( - ParagonIE_Sodium_Core_Curve25519_Fe $yplusx = null, - ParagonIE_Sodium_Core_Curve25519_Fe $yminusx = null, - ParagonIE_Sodium_Core_Curve25519_Fe $xy2d = null + $yplusx = null, + $yminusx = null, + $xy2d = null ) { if ($yplusx === null) { $yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($yplusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->yplusx = $yplusx; if ($yminusx === null) { $yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($yminusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->yminusx = $yminusx; if ($xy2d === null) { $xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } + if (!($xy2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { + throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); + } $this->xy2d = $xy2d; } } diff --git a/tests/compat/PHP84Test.php b/tests/compat/PHP84Test.php index c990e096..a1b58759 100644 --- a/tests/compat/PHP84Test.php +++ b/tests/compat/PHP84Test.php @@ -7,7 +7,7 @@ class PHP84Test extends PHPUnit_Framework_TestCase */ public function before() { - if (PHP_VERSION_ID < 80400) { + if (PHP_VERSION_ID < 80400 || !extension_loaded('sodium')) { $this->markTestSkipped('PHP < 8.4.0; skipping PHP 8.4 compatibility test suite.'); } ParagonIE_Sodium_Compat::$disableFallbackForUnitTests = true; diff --git a/tests/phpunit-shim.php b/tests/phpunit-shim.php index d19dad64..b8462607 100644 --- a/tests/phpunit-shim.php +++ b/tests/phpunit-shim.php @@ -3,4 +3,4 @@ if (!class_exists('PHPUnit_Framework_TestCase')) { class PHPUnit_Framework_TestCase extends TestCase {} -} +} \ No newline at end of file