diff --git a/src/Component/Console/AddKeyIntoKeysetCommand.php b/src/Component/Console/AddKeyIntoKeysetCommand.php index a1d3d70e..49e3a16f 100644 --- a/src/Component/Console/AddKeyIntoKeysetCommand.php +++ b/src/Component/Console/AddKeyIntoKeysetCommand.php @@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:add:key', description: 'Add a key into a key set.',)] +#[AsCommand(name: 'keyset:add:key', description: 'Add a key into a key set.')] final class AddKeyIntoKeysetCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/EcKeyGeneratorCommand.php b/src/Component/Console/EcKeyGeneratorCommand.php index 5dd1f2fb..ba6c381a 100644 --- a/src/Component/Console/EcKeyGeneratorCommand.php +++ b/src/Component/Console/EcKeyGeneratorCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:generate:ec', description: 'Generate an EC key (JWK format)',)] +#[AsCommand(name: 'key:generate:ec', description: 'Generate an EC key (JWK format)')] final class EcKeyGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/EcKeysetGeneratorCommand.php b/src/Component/Console/EcKeysetGeneratorCommand.php index d5e2c652..366d2174 100644 --- a/src/Component/Console/EcKeysetGeneratorCommand.php +++ b/src/Component/Console/EcKeysetGeneratorCommand.php @@ -13,7 +13,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:generate:ec', description: 'Generate an EC key set (JWKSet format)',)] +#[AsCommand(name: 'keyset:generate:ec', description: 'Generate an EC key set (JWKSet format)')] final class EcKeysetGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/GetThumbprintCommand.php b/src/Component/Console/GetThumbprintCommand.php index a9fce63f..d8075c31 100644 --- a/src/Component/Console/GetThumbprintCommand.php +++ b/src/Component/Console/GetThumbprintCommand.php @@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:thumbprint', description: 'Get the thumbprint of a JWK key.',)] +#[AsCommand(name: 'key:thumbprint', description: 'Get the thumbprint of a JWK key.')] final class GetThumbprintCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/JKULoaderCommand.php b/src/Component/Console/JKULoaderCommand.php index 87ddf9c0..47b4f1a6 100644 --- a/src/Component/Console/JKULoaderCommand.php +++ b/src/Component/Console/JKULoaderCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:load:jku', description: 'Loads a key set from an url.',)] +#[AsCommand(name: 'keyset:load:jku', description: 'Loads a key set from an url.')] final class JKULoaderCommand extends ObjectOutputCommand { public function __construct( diff --git a/src/Component/Console/KeyAnalyzerCommand.php b/src/Component/Console/KeyAnalyzerCommand.php index 9408ea01..04b88370 100644 --- a/src/Component/Console/KeyAnalyzerCommand.php +++ b/src/Component/Console/KeyAnalyzerCommand.php @@ -17,7 +17,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:analyze', description: 'JWK quality analyzer.',)] +#[AsCommand(name: 'key:analyze', description: 'JWK quality analyzer.')] final class KeyAnalyzerCommand extends Command { public function __construct( diff --git a/src/Component/Console/KeyFileLoaderCommand.php b/src/Component/Console/KeyFileLoaderCommand.php index 4988c1fd..2598c314 100644 --- a/src/Component/Console/KeyFileLoaderCommand.php +++ b/src/Component/Console/KeyFileLoaderCommand.php @@ -13,7 +13,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:load:key', description: 'Loads a key from a key file (JWK format)',)] +#[AsCommand(name: 'key:load:key', description: 'Loads a key from a key file (JWK format)')] final class KeyFileLoaderCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/KeysetAnalyzerCommand.php b/src/Component/Console/KeysetAnalyzerCommand.php index dd4eddf1..e26778bb 100644 --- a/src/Component/Console/KeysetAnalyzerCommand.php +++ b/src/Component/Console/KeysetAnalyzerCommand.php @@ -19,13 +19,12 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:analyze', description: 'JWKSet quality analyzer.',)] +#[AsCommand(name: 'keyset:analyze', description: 'JWKSet quality analyzer.')] final class KeysetAnalyzerCommand extends Command { public function __construct( private readonly KeysetAnalyzerManager $keysetAnalyzerManager, - private readonly KeyAnalyzerManager $keyAnalyzerManager, - string $name = null + private readonly KeyAnalyzerManager $keyAnalyzerManager ) { parent::__construct(); } diff --git a/src/Component/Console/MergeKeysetCommand.php b/src/Component/Console/MergeKeysetCommand.php index 85b12127..25dd2906 100644 --- a/src/Component/Console/MergeKeysetCommand.php +++ b/src/Component/Console/MergeKeysetCommand.php @@ -13,7 +13,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:merge', description: 'Merge several key sets into one.',)] +#[AsCommand(name: 'keyset:merge', description: 'Merge several key sets into one.')] final class MergeKeysetCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/OctKeyGeneratorCommand.php b/src/Component/Console/OctKeyGeneratorCommand.php index 44fdb1d1..ccef3772 100644 --- a/src/Component/Console/OctKeyGeneratorCommand.php +++ b/src/Component/Console/OctKeyGeneratorCommand.php @@ -11,7 +11,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:generate:oct', description: 'Generate an octet key (JWK format)',)] +#[AsCommand(name: 'key:generate:oct', description: 'Generate an octet key (JWK format)')] final class OctKeyGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/OctKeysetGeneratorCommand.php b/src/Component/Console/OctKeysetGeneratorCommand.php index 9259b65b..ed74ce23 100644 --- a/src/Component/Console/OctKeysetGeneratorCommand.php +++ b/src/Component/Console/OctKeysetGeneratorCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:generate:oct', description: 'Generate a key set with octet keys (JWK format)',)] +#[AsCommand(name: 'keyset:generate:oct', description: 'Generate a key set with octet keys (JWK format)')] final class OctKeysetGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/OkpKeyGeneratorCommand.php b/src/Component/Console/OkpKeyGeneratorCommand.php index 69dfa2da..bfcc9a8c 100644 --- a/src/Component/Console/OkpKeyGeneratorCommand.php +++ b/src/Component/Console/OkpKeyGeneratorCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:generate:okp', description: 'Generate an Octet Key Pair key (JWK format)',)] +#[AsCommand(name: 'key:generate:okp', description: 'Generate an Octet Key Pair key (JWK format)')] final class OkpKeyGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/OptimizeRsaKeyCommand.php b/src/Component/Console/OptimizeRsaKeyCommand.php index 15322c8e..0210f393 100644 --- a/src/Component/Console/OptimizeRsaKeyCommand.php +++ b/src/Component/Console/OptimizeRsaKeyCommand.php @@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:optimize', description: 'Optimize a RSA key by calculating additional primes (CRT).',)] +#[AsCommand(name: 'key:optimize', description: 'Optimize a RSA key by calculating additional primes (CRT).')] final class OptimizeRsaKeyCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/P12CertificateLoaderCommand.php b/src/Component/Console/P12CertificateLoaderCommand.php index 07f007cc..3c9ab4f5 100644 --- a/src/Component/Console/P12CertificateLoaderCommand.php +++ b/src/Component/Console/P12CertificateLoaderCommand.php @@ -13,7 +13,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:load:p12', description: 'Load a key from a P12 certificate file.',)] +#[AsCommand(name: 'key:load:p12', description: 'Load a key from a P12 certificate file.')] final class P12CertificateLoaderCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/PemConverterCommand.php b/src/Component/Console/PemConverterCommand.php index 8703d7e8..0ad02bda 100644 --- a/src/Component/Console/PemConverterCommand.php +++ b/src/Component/Console/PemConverterCommand.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:convert:pkcs1', description: 'Converts a RSA or EC key into PKCS#1 key.',)] +#[AsCommand(name: 'key:convert:pkcs1', description: 'Converts a RSA or EC key into PKCS#1 key.')] final class PemConverterCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/RotateKeysetCommand.php b/src/Component/Console/RotateKeysetCommand.php index fd62855d..966e39a9 100644 --- a/src/Component/Console/RotateKeysetCommand.php +++ b/src/Component/Console/RotateKeysetCommand.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:rotate', description: 'Rotate a key set.',)] +#[AsCommand(name: 'keyset:rotate', description: 'Rotate a key set.')] final class RotateKeysetCommand extends ObjectOutputCommand { protected function configure(): void diff --git a/src/Component/Console/RsaKeyGeneratorCommand.php b/src/Component/Console/RsaKeyGeneratorCommand.php index 1148b63f..b8646442 100644 --- a/src/Component/Console/RsaKeyGeneratorCommand.php +++ b/src/Component/Console/RsaKeyGeneratorCommand.php @@ -11,7 +11,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:generate:rsa', description: 'Generate a RSA key (JWK format)',)] +#[AsCommand(name: 'key:generate:rsa', description: 'Generate a RSA key (JWK format)')] final class RsaKeyGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/RsaKeysetGeneratorCommand.php b/src/Component/Console/RsaKeysetGeneratorCommand.php index 48794852..a36d069f 100644 --- a/src/Component/Console/RsaKeysetGeneratorCommand.php +++ b/src/Component/Console/RsaKeysetGeneratorCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:generate:rsa', description: 'Generate a key set with RSA keys (JWK format)',)] +#[AsCommand(name: 'keyset:generate:rsa', description: 'Generate a key set with RSA keys (JWK format)')] final class RsaKeysetGeneratorCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/X509CertificateLoaderCommand.php b/src/Component/Console/X509CertificateLoaderCommand.php index befe05a2..e2570def 100644 --- a/src/Component/Console/X509CertificateLoaderCommand.php +++ b/src/Component/Console/X509CertificateLoaderCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'key:load:x509', description: 'Load a key from a X.509 certificate file.',)] +#[AsCommand(name: 'key:load:x509', description: 'Load a key from a X.509 certificate file.')] final class X509CertificateLoaderCommand extends GeneratorCommand { protected function configure(): void diff --git a/src/Component/Console/X5ULoaderCommand.php b/src/Component/Console/X5ULoaderCommand.php index 5e9a5fd6..2971beab 100644 --- a/src/Component/Console/X5ULoaderCommand.php +++ b/src/Component/Console/X5ULoaderCommand.php @@ -12,12 +12,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'keyset:load:x5u', description: 'Loads a key set from an url.',)] +#[AsCommand(name: 'keyset:load:x5u', description: 'Loads a key set from an url.')] final class X5ULoaderCommand extends ObjectOutputCommand { public function __construct( - private readonly X5UFactory $x5uFactory, - ?string $name = null + private readonly X5UFactory $x5uFactory ) { parent::__construct(); } diff --git a/src/Component/KeyManagement/JWKFactory.php b/src/Component/KeyManagement/JWKFactory.php index 0e0b528a..88e483d5 100644 --- a/src/Component/KeyManagement/JWKFactory.php +++ b/src/Component/KeyManagement/JWKFactory.php @@ -106,7 +106,7 @@ public static function createOKPKey(string $curve, array $values = []): JWK switch ($curve) { case 'X25519': $keyPair = sodium_crypto_box_keypair(); - $secret = $keyPair; + $d = sodium_crypto_box_secretkey($keyPair); $x = sodium_crypto_box_publickey($keyPair); break; @@ -114,6 +114,8 @@ public static function createOKPKey(string $curve, array $values = []): JWK case 'Ed25519': $keyPair = sodium_crypto_sign_keypair(); $secret = sodium_crypto_sign_secretkey($keyPair); + $secretLength = mb_strlen($secret, '8bit'); + $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); $x = sodium_crypto_sign_publickey($keyPair); break; @@ -121,8 +123,6 @@ public static function createOKPKey(string $curve, array $values = []): JWK default: throw new InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve)); } - $secretLength = mb_strlen($secret, '8bit'); - $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); $values = array_merge( $values, diff --git a/src/EncryptionAlgorithm/KeyEncryption/ECDHES/AbstractECDH.php b/src/EncryptionAlgorithm/KeyEncryption/ECDHES/AbstractECDH.php index 80bab7fa..105048c6 100644 --- a/src/EncryptionAlgorithm/KeyEncryption/ECDHES/AbstractECDH.php +++ b/src/EncryptionAlgorithm/KeyEncryption/ECDHES/AbstractECDH.php @@ -293,7 +293,9 @@ private function createOKPKey(string $curve): JWK case 'Ed25519': $keyPair = sodium_crypto_sign_keypair(); - $d = sodium_crypto_sign_secretkey($keyPair); + $secret = sodium_crypto_sign_secretkey($keyPair); + $secretLength = mb_strlen($secret, '8bit'); + $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); $x = sodium_crypto_sign_publickey($keyPair); break; diff --git a/tests/EncryptionAlgorithm/KeyEncryption/ECDHES/ECDHESKeyAgreementTest.php b/tests/EncryptionAlgorithm/KeyEncryption/ECDHES/ECDHESKeyAgreementTest.php index 94c7bdf4..5ae4d9c3 100644 --- a/tests/EncryptionAlgorithm/KeyEncryption/ECDHES/ECDHESKeyAgreementTest.php +++ b/tests/EncryptionAlgorithm/KeyEncryption/ECDHES/ECDHESKeyAgreementTest.php @@ -26,7 +26,7 @@ final class ECDHESKeyAgreementTest extends TestCase * * @test */ - public function getAgreementKey(): void + public function getAgreementKeyWithEllipticCurveKey(): void { $receiver = new JWK([ 'kty' => 'EC', @@ -51,6 +51,76 @@ public function getAgreementKey(): void static::assertArrayHasKey('y', $additional_header_values['epk']); } + /** + * @see https://tools.ietf.org/html/rfc7518#appendix-C + * + * @test + */ + public function getAgreementKeyWithA128KeyWrapAndWithOctetKeyPairKey(): void + { + $header = [ + 'enc' => 'A128GCM', + ]; + + $private = new JWK([ + 'kty' => 'OKP', + 'crv' => 'X25519', + 'd' => 'uns2Byv3po_cjjG8XRCtU-lEOrOgLbsDr5cXHmgjVvA', + 'x' => 'k8IkMMO9I0foCYqEcbfM49DjEoWpHdho_GKNMXk1rFw', + ]); + $public = $private->toPublic(); + + $cek = [ + 4, + 211, + 31, + 197, + 84, + 157, + 252, + 254, + 11, + 100, + 157, + 250, + 63, + 170, + 106, + 206, + 107, + 124, + 212, + 45, + 111, + 107, + 9, + 219, + 200, + 177, + 0, + 240, + 143, + 156, + 44, + 207, + ]; + foreach ($cek as $key => $value) { + $cek[$key] = str_pad(dechex($value), 2, '0', STR_PAD_LEFT); + } + $cek = hex2bin(implode('', $cek)); + + $ecdh_es = new ECDHESA128KW(); + $encrypted_cek = $ecdh_es->wrapAgreementKey($public, null, $cek, 128, $header, $header); + static::assertArrayHasKey('epk', $header); + static::assertArrayHasKey('crv', $header['epk']); + static::assertArrayHasKey('kty', $header['epk']); + static::assertArrayHasKey('x', $header['epk']); + static::assertArrayNotHasKey('y', $header['epk']); + static::assertSame('X25519', $header['epk']['crv']); + static::assertSame('OKP', $header['epk']['kty']); + static::assertSame($cek, $ecdh_es->unwrapAgreementKey($private, null, $encrypted_cek, 128, $header)); + } + /** * @test */ diff --git a/tests/EncryptionAlgorithm/KeyEncryption/ECDHSS/ECDHSSKeyAgreementTest.php b/tests/EncryptionAlgorithm/KeyEncryption/ECDHSS/ECDHSSKeyAgreementTest.php index 3c7d5ea5..2ee6dd08 100644 --- a/tests/EncryptionAlgorithm/KeyEncryption/ECDHSS/ECDHSSKeyAgreementTest.php +++ b/tests/EncryptionAlgorithm/KeyEncryption/ECDHSS/ECDHSSKeyAgreementTest.php @@ -52,6 +52,82 @@ public function getAgreementKey(): void static::assertArrayNotHasKey('epk', $additional_header_values); } + /** + * @test + */ + public function getAgreementKeyWithA128KeyWrapAndOctetKeyPairKey(): void + { + $additional_header_values = [ + 'enc' => 'A128GCM', + ]; + $sender = new JWK([ + 'kty' => 'OKP', + 'crv' => 'X25519', + 'd' => 'uns2Byv3po_cjjG8XRCtU-lEOrOgLbsDr5cXHmgjVvA', + 'x' => 'k8IkMMO9I0foCYqEcbfM49DjEoWpHdho_GKNMXk1rFw', + ]); + $receiver = new JWK([ + 'kty' => 'EC', + 'crv' => 'X25519', + 'd' => 'tzF6dJQtUYj2G60lzzw70A8BGeE_KDDofUdwwm9qIEU', + 'x' => 'q9mRLLKfK-_SosZoBFs5LaDxSB9KaqbRaenvzy1_lAA', + ]); + + $cek = [ + 4, + 211, + 31, + 197, + 84, + 157, + 252, + 254, + 11, + 100, + 157, + 250, + 63, + 170, + 106, + 206, + 107, + 124, + 212, + 45, + 111, + 107, + 9, + 219, + 200, + 177, + 0, + 240, + 143, + 156, + 44, + 207, + ]; + foreach ($cek as $key => $value) { + $cek[$key] = str_pad(dechex($value), 2, '0', STR_PAD_LEFT); + } + $cek = hex2bin(implode('', $cek)); + + $ecdh_ss = new ECDHSSA128KW(); + $encrypted_cek = $ecdh_ss->wrapAgreementKey( + $receiver->toPublic(), + $sender, + $cek, + 128, + $additional_header_values, + $additional_header_values + ); + static::assertArrayNotHasKey('epk', $additional_header_values); + static::assertSame( + $cek, + $ecdh_ss->unwrapAgreementKey($sender->toPublic(), $receiver, $encrypted_cek, 128, $additional_header_values) + ); + } + /** * @test */