diff --git a/composer.json b/composer.json index 3fd329bd..66173a43 100644 --- a/composer.json +++ b/composer.json @@ -101,6 +101,7 @@ "ext-sodium": "*", "brick/math": "^0.9|^0.10|^0.11|^0.12", "paragonie/constant_time_encoding": "^2.6", + "paragonie/sodium_compat": "^1.20", "psr/clock": "^1.0", "psr/event-dispatcher": "^1.0", "psr/http-client": "^1.0", diff --git a/src/Component/KeyManagement/KeyConverter/KeyConverter.php b/src/Component/KeyManagement/KeyConverter/KeyConverter.php index 9acd843c..c7b69e5d 100644 --- a/src/Component/KeyManagement/KeyConverter/KeyConverter.php +++ b/src/Component/KeyManagement/KeyConverter/KeyConverter.php @@ -7,6 +7,7 @@ use InvalidArgumentException; use OpenSSLCertificate; use ParagonIE\ConstantTime\Base64UrlSafe; +use ParagonIE\Sodium\Core\Ed25519; use RuntimeException; use SpomkyLabs\Pki\CryptoEncoding\PEM; use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PrivateKey; @@ -250,14 +251,29 @@ private static function tryToLoadOtherKeyTypes(string $input): array */ private static function populatePoints(PrivateKey $key, array $values): array { - if (($values['crv'] === 'Ed25519' || $values['crv'] === 'X25519') && extension_loaded('sodium')) { - $x = sodium_crypto_scalarmult_base($key->privateKeyData()); + $x = self::getPublicKey($key, $values['crv']); + if ($x !== null) { $values['x'] = Base64UrlSafe::encodeUnpadded($x); } return $values; } + private static function getPublicKey(PrivateKey $key, string $crv): ?string + { + switch ($crv) { + case 'Ed25519': + return Ed25519::publickey_from_secretkey($key->privateKeyData()); + case 'X25519': + if (extension_loaded('sodium')) { + return sodium_crypto_scalarmult_base($key->privateKeyData()); + } + // no break + default: + return null; + } + } + private static function checkType(string $curve): void { $curves = ['Ed448ph', 'Ed25519ph', 'Ed448', 'Ed25519', 'X448', 'X25519']; diff --git a/src/SignatureAlgorithm/EdDSA/EdDSA.php b/src/SignatureAlgorithm/EdDSA/EdDSA.php index 1c12b6e9..d2dcec87 100644 --- a/src/SignatureAlgorithm/EdDSA/EdDSA.php +++ b/src/SignatureAlgorithm/EdDSA/EdDSA.php @@ -7,6 +7,7 @@ use InvalidArgumentException; use Jose\Component\Core\JWK; use ParagonIE\ConstantTime\Base64UrlSafe; +use ParagonIE\Sodium\Core\Ed25519; use RuntimeException; use function extension_loaded; use function in_array; @@ -40,7 +41,7 @@ public function sign(JWK $key, string $input): string throw new InvalidArgumentException('Invalid "d" parameter.'); } if (! $key->has('x')) { - $x = sodium_crypto_sign_publickey_from_secretkey($d); + $x = $this->getPublicKey($key); } else { $x = $key->get('x'); } @@ -84,6 +85,21 @@ public function name(): string return 'EdDSA'; } + private static function getPublicKey(JWK $key): string + { + switch ($key->get('crv')) { + case 'Ed25519': + return Ed25519::publickey_from_secretkey($key->get('d')); + case 'X25519': + if (extension_loaded('sodium')) { + return sodium_crypto_scalarmult_base($key->get('d')); + } + // no break + default: + throw new InvalidArgumentException('Unsupported key type'); + } + } + private function checkKey(JWK $key): void { if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { diff --git a/src/SignatureAlgorithm/EdDSA/composer.json b/src/SignatureAlgorithm/EdDSA/composer.json index a5595bc5..b1223f9d 100644 --- a/src/SignatureAlgorithm/EdDSA/composer.json +++ b/src/SignatureAlgorithm/EdDSA/composer.json @@ -40,6 +40,7 @@ "require": { "php": ">=8.1", "ext-sodium": "*", + "paragonie/sodium_compat": "^1.20", "web-token/jwt-signature": "^3.2" } } diff --git a/tests/Component/KeyManagement/JWKFactoryTest.php b/tests/Component/KeyManagement/JWKFactoryTest.php index 4f83ab07..c777b503 100644 --- a/tests/Component/KeyManagement/JWKFactoryTest.php +++ b/tests/Component/KeyManagement/JWKFactoryTest.php @@ -297,7 +297,7 @@ public static function dataKeys(): iterable 'kty' => 'OKP', 'crv' => 'Ed25519', 'd' => 'Pr9AxZivB-zSq95wLrZfYa7DQ3TUPqZTkP_0w33r3rc', - 'x' => 'uRhai1TsvrSB43HD-36TQ2hMQfV8ruJz7F8o0wIe1VI', + 'x' => 'wrI33AEj15KHHYplueUE5cnJKtbM8oVHFf6wGnw2oOE', ], ]; yield [