Skip to content

Commit 3eec531

Browse files
authored
ECKey Length fixed (#172)
1 parent 368327b commit 3eec531

File tree

5 files changed

+131
-174
lines changed

5 files changed

+131
-174
lines changed

src/Component/Core/Util/ECKey.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
namespace Jose\Component\Core\Util;
1515

1616
use Base64Url\Base64Url;
17+
use InvalidArgumentException;
1718
use Jose\Component\Core\JWK;
19+
use Jose\Component\Core\Util\Ecc\Curve;
20+
use Jose\Component\Core\Util\Ecc\NistCurve;
21+
use RuntimeException;
1822

1923
/**
2024
* @internal
@@ -82,6 +86,94 @@ public static function convertPrivateKeyToPEM(JWK $jwk): string
8286
return $pem;
8387
}
8488

89+
/**
90+
* Creates a EC key with the given curve and additional values.
91+
*
92+
* @param string $curve The curve
93+
* @param array $values values to configure the key
94+
*/
95+
public static function createECKey(string $curve, array $values = []): JWK
96+
{
97+
try {
98+
$jwk = self::createECKeyUsingOpenSSL($curve);
99+
} catch (\Exception $e) {
100+
$jwk = self::createECKeyUsingPurePhp($curve);
101+
}
102+
$values = \array_merge($values, $jwk);
103+
104+
return JWK::create($values);
105+
}
106+
107+
private static function createECKeyUsingPurePhp(string $curve): array
108+
{
109+
$nistCurve = static::getCurve($curve);
110+
$componentSize = (int) ceil($nistCurve->getSize() / 8);
111+
$privateKey = $nistCurve->createPrivateKey();
112+
$publicKey = $nistCurve->createPublicKey($privateKey);
113+
114+
return [
115+
'kty' => 'EC',
116+
'crv' => $curve,
117+
'd' => Base64Url::encode(str_pad(gmp_export($privateKey->getSecret()), $componentSize, "\0", STR_PAD_LEFT)),
118+
'x' => Base64Url::encode(str_pad(gmp_export($publicKey->getPoint()->getX()), $componentSize, "\0", STR_PAD_LEFT)),
119+
'y' => Base64Url::encode(str_pad(gmp_export($publicKey->getPoint()->getY()), $componentSize, "\0", STR_PAD_LEFT)),
120+
];
121+
}
122+
123+
private static function createECKeyUsingOpenSSL(string $curve): array
124+
{
125+
$key = openssl_pkey_new([
126+
'curve_name' => self::getOpensslCurveName($curve),
127+
'private_key_type' => OPENSSL_KEYTYPE_EC,
128+
]);
129+
$res = openssl_pkey_export($key, $out);
130+
if (false === $res) {
131+
throw new RuntimeException('Unable to create the key');
132+
}
133+
$res = openssl_pkey_get_private($out);
134+
135+
$details = openssl_pkey_get_details($res);
136+
137+
$nistCurve = static::getCurve($curve);
138+
$componentSize = (int) ceil($nistCurve->getSize() / 8);
139+
140+
return [
141+
'kty' => 'EC',
142+
'crv' => $curve,
143+
'x' => Base64Url::encode(str_pad($details['ec']['x'], $componentSize, "\0", STR_PAD_LEFT)),
144+
'y' => Base64Url::encode(str_pad($details['ec']['y'], $componentSize, "\0", STR_PAD_LEFT)),
145+
'd' => Base64Url::encode(str_pad($details['ec']['d'], $componentSize, "\0", STR_PAD_LEFT)),
146+
];
147+
}
148+
149+
private static function getCurve(string $curve): Curve
150+
{
151+
switch ($curve) {
152+
case 'P-256':
153+
return NistCurve::curve256();
154+
case 'P-384':
155+
return NistCurve::curve384();
156+
case 'P-521':
157+
return NistCurve::curve521();
158+
default:
159+
throw new InvalidArgumentException(\sprintf('The curve "%s" is not supported.', $curve));
160+
}
161+
}
162+
163+
private static function getOpensslCurveName(string $curve): string
164+
{
165+
switch ($curve) {
166+
case 'P-256':
167+
return 'prime256v1';
168+
case 'P-384':
169+
return 'secp384r1';
170+
case 'P-521':
171+
return 'secp521r1';
172+
default:
173+
throw new InvalidArgumentException(\sprintf('The curve "%s" is not supported.', $curve));
174+
}
175+
}
176+
85177
private static function p256PublicKey(): string
86178
{
87179
return \pack('H*',

src/Component/KeyManagement/JWKFactory.php

Lines changed: 15 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@
1414
namespace Jose\Component\KeyManagement;
1515

1616
use Base64Url\Base64Url;
17+
use InvalidArgumentException;
1718
use Jose\Component\Core\JWK;
1819
use Jose\Component\Core\JWKSet;
19-
use Jose\Component\Core\Util\Ecc\NistCurve;
20+
use Jose\Component\Core\Util\Ecc\Curve;
21+
use Jose\Component\Core\Util\ECKey;
2022
use Jose\Component\KeyManagement\KeyConverter\KeyConverter;
2123
use Jose\Component\KeyManagement\KeyConverter\RSAKey;
24+
use function openssl_pkey_get_details;
25+
use function openssl_pkey_new;
26+
use RuntimeException;
2227

2328
class JWKFactory
2429
{
@@ -31,18 +36,18 @@ class JWKFactory
3136
public static function createRSAKey(int $size, array $values = []): JWK
3237
{
3338
if (0 !== $size % 8) {
34-
throw new \InvalidArgumentException('Invalid key size.');
39+
throw new InvalidArgumentException('Invalid key size.');
3540
}
3641

3742
if (512 > $size) {
38-
throw new \InvalidArgumentException('Key length is too short. It needs to be at least 512 bits.');
43+
throw new InvalidArgumentException('Key length is too short. It needs to be at least 512 bits.');
3944
}
4045

41-
$key = \openssl_pkey_new([
46+
$key = openssl_pkey_new([
4247
'private_key_bits' => $size,
4348
'private_key_type' => OPENSSL_KEYTYPE_RSA,
4449
]);
45-
$details = \openssl_pkey_get_details($key);
50+
$details = openssl_pkey_get_details($key);
4651
\openssl_free_key($key);
4752
$rsa = RSAKey::createFromKeyDetails($details['rsa']);
4853
$values = \array_merge(
@@ -61,82 +66,7 @@ public static function createRSAKey(int $size, array $values = []): JWK
6166
*/
6267
public static function createECKey(string $curve, array $values = []): JWK
6368
{
64-
try {
65-
$jwk = self::createECKeyUsingOpenSSL($curve);
66-
} catch (\Exception $e) {
67-
$jwk = self::createECKeyUsingPurePhp($curve);
68-
}
69-
$values = \array_merge($values, $jwk);
70-
71-
return JWK::create($values);
72-
}
73-
74-
private static function createECKeyUsingPurePhp(string $curve): array
75-
{
76-
switch ($curve) {
77-
case 'P-256':
78-
$nistCurve = NistCurve::curve256();
79-
80-
break;
81-
case 'P-384':
82-
$nistCurve = NistCurve::curve384();
83-
84-
break;
85-
case 'P-521':
86-
$nistCurve = NistCurve::curve521();
87-
88-
break;
89-
default:
90-
throw new \InvalidArgumentException(\sprintf('The curve "%s" is not supported.', $curve));
91-
}
92-
93-
$privateKey = $nistCurve->createPrivateKey();
94-
$publicKey = $nistCurve->createPublicKey($privateKey);
95-
96-
return [
97-
'kty' => 'EC',
98-
'crv' => $curve,
99-
'd' => Base64Url::encode(\gmp_export($privateKey->getSecret())),
100-
'x' => Base64Url::encode(\gmp_export($publicKey->getPoint()->getX())),
101-
'y' => Base64Url::encode(\gmp_export($publicKey->getPoint()->getY())),
102-
];
103-
}
104-
105-
private static function createECKeyUsingOpenSSL(string $curve): array
106-
{
107-
$key = \openssl_pkey_new([
108-
'curve_name' => self::getOpensslCurveName($curve),
109-
'private_key_type' => OPENSSL_KEYTYPE_EC,
110-
]);
111-
$res = \openssl_pkey_export($key, $out);
112-
if (false === $res) {
113-
throw new \RuntimeException('Unable to create the key');
114-
}
115-
$res = \openssl_pkey_get_private($out);
116-
117-
$details = \openssl_pkey_get_details($res);
118-
119-
return [
120-
'kty' => 'EC',
121-
'crv' => $curve,
122-
'x' => Base64Url::encode($details['ec']['x']),
123-
'y' => Base64Url::encode($details['ec']['y']),
124-
'd' => Base64Url::encode($details['ec']['d']),
125-
];
126-
}
127-
128-
private static function getOpensslCurveName(string $curve): string
129-
{
130-
switch ($curve) {
131-
case 'P-256':
132-
return 'prime256v1';
133-
case 'P-384':
134-
return 'secp384r1';
135-
case 'P-521':
136-
return 'secp521r1';
137-
default:
138-
throw new \InvalidArgumentException(\sprintf('The curve "%s" is not supported.', $curve));
139-
}
69+
return ECKey::createECKey($curve, $values);
14070
}
14171

14272
/**
@@ -148,7 +78,7 @@ private static function getOpensslCurveName(string $curve): string
14878
public static function createOctKey(int $size, array $values = []): JWK
14979
{
15080
if (0 !== $size % 8) {
151-
throw new \InvalidArgumentException('Invalid key size.');
81+
throw new InvalidArgumentException('Invalid key size.');
15282
}
15383
$values = \array_merge(
15484
$values,
@@ -183,7 +113,7 @@ public static function createOKPKey(string $curve, array $values = []): JWK
183113

184114
break;
185115
default:
186-
throw new \InvalidArgumentException(\sprintf('Unsupported "%s" curve', $curve));
116+
throw new InvalidArgumentException(\sprintf('Unsupported "%s" curve', $curve));
187117
}
188118
$secretLength = mb_strlen($secret, '8bit');
189119
$d = mb_substr($secret, 0, -$secretLength / 2, '8bit');
@@ -231,7 +161,7 @@ public static function createFromJsonObject(string $value)
231161
{
232162
$json = \json_decode($value, true);
233163
if (!\is_array($json)) {
234-
throw new \InvalidArgumentException('Invalid key or key set.');
164+
throw new InvalidArgumentException('Invalid key or key set.');
235165
}
236166

237167
return self::createFromValues($json);
@@ -297,7 +227,7 @@ public static function createFromPKCS12CertificateFile(string $file, ?string $se
297227
{
298228
$res = \openssl_pkcs12_read(\file_get_contents($file), $certs, $secret);
299229
if (false === $res || !\is_array($certs) || !\array_key_exists('pkey', $certs)) {
300-
throw new \RuntimeException('Unable to load the certificates.');
230+
throw new RuntimeException('Unable to load the certificates.');
301231
}
302232

303233
return self::createFromKey($certs['pkey'], null, $additional_values);

src/EncryptionAlgorithm/Experimental/ContentEncryption/AESCCM.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
1515

16+
use InvalidArgumentException;
1617
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
18+
use function openssl_decrypt;
19+
use function openssl_encrypt;
1720

1821
abstract class AESCCM implements ContentEncryptionAlgorithm
1922
{
@@ -29,9 +32,9 @@ public function encryptContent(string $data, string $cek, string $iv, ?string $a
2932
$calculated_aad .= '.'.$aad;
3033
}
3134

32-
$C = \openssl_encrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad, $this->getTagLength());
35+
$C = openssl_encrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad, $this->getTagLength());
3336
if (false === $C) {
34-
throw new \InvalidArgumentException('Unable to encrypt the data.');
37+
throw new InvalidArgumentException('Unable to encrypt the data.');
3538
}
3639

3740
return $C;
@@ -47,9 +50,9 @@ public function decryptContent(string $data, string $cek, string $iv, ?string $a
4750
$calculated_aad .= '.'.$aad;
4851
}
4952

50-
$P = \openssl_decrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad);
53+
$P = openssl_decrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad);
5154
if (false === $P) {
52-
throw new \InvalidArgumentException('Unable to decrypt or to verify the tag.');
55+
throw new InvalidArgumentException('Unable to decrypt or to verify the tag.');
5356
}
5457

5558
return $P;

src/EncryptionAlgorithm/Experimental/Tests/AESCCMContentEncryptionTest.php

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)