Skip to content

Key factory #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions performance/KeyFactory/KeyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2018 Spomky-Labs
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

namespace Jose\Performance\KeyFactory;

use Base64Url\Base64Url;
use Jose\Component\Core\JWK;
use Jose\Component\Core\Util\Ecc\NistCurve;

/**
* @Revs(1000)
* @Groups({"KeyFactory"})
*/
final class KeyFactory
{
/**
* @Subject()
*/
public function usingThePurePhpMethod()
{
$curve = NistCurve::curve256();
$privateKey = $curve->createPrivateKey();
$publicKey = $curve->createPublicKey($privateKey);

JWK::create([
'kty' => 'EC',
'crv' => $curve,
'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
]);
}

/**
* @Subject()
*/
public function usingOpenSSL()
{
$key = openssl_pkey_new([
'curve_name' => 'prime256v1',
'private_key_type' => OPENSSL_KEYTYPE_EC,
]);
$res = openssl_pkey_export($key, $out);
if (false === $res) {
throw new \RuntimeException('Unable to create the key');
}
$res = openssl_pkey_get_private($out);

$details = openssl_pkey_get_details($res);

JWK::create([
'kty' => 'EC',
'crv' => 'P-256',
'x' => Base64Url::encode($details['ec']['x']),
'y' => Base64Url::encode($details['ec']['y']),
'd' => Base64Url::encode($details['ec']['d']),
]);
}
}
36 changes: 18 additions & 18 deletions src/Component/Core/Util/Ecc/NistCurve.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ class NistCurve
*/
public static function curve256(): Curve
{
$p = gmp_init('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
$a = gmp_init('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc', 16);
$b = gmp_init('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b', 16);
$x = gmp_init('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296', 16);
$y = gmp_init('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5', 16);
$n = gmp_init('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 16);
$p = gmp_init('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
$a = gmp_init('ffffffff00000001000000000000000000000000fffffffffffffffffffffffc', 16);
$b = gmp_init('5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b', 16);
$x = gmp_init('6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296', 16);
$y = gmp_init('4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5', 16);
$n = gmp_init('ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 16);
$generator = Point::create($x, $y, $n);

return new Curve(256, $p, $a, $b, $generator);
Expand All @@ -67,12 +67,12 @@ public static function curve256(): Curve
*/
public static function curve384(): Curve
{
$p = gmp_init('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff', 16);
$a = gmp_init('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc', 16);
$b = gmp_init('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef', 16);
$x = gmp_init('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7', 16);
$y = gmp_init('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f', 16);
$n = gmp_init('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973', 16);
$p = gmp_init('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff', 16);
$a = gmp_init('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc', 16);
$b = gmp_init('b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef', 16);
$x = gmp_init('aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7', 16);
$y = gmp_init('3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f', 16);
$n = gmp_init('ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973', 16);
$generator = Point::create($x, $y, $n);

return new Curve(384, $p, $a, $b, $generator);
Expand All @@ -85,12 +85,12 @@ public static function curve384(): Curve
*/
public static function curve521(): Curve
{
$p = gmp_init('0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
$a = gmp_init('0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc', 16);
$b = gmp_init('0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00', 16);
$x = gmp_init('0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66', 16);
$y = gmp_init('0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650', 16);
$n = gmp_init('0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409', 16);
$p = gmp_init('000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
$a = gmp_init('000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc', 16);
$b = gmp_init('00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00', 16);
$x = gmp_init('000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66', 16);
$y = gmp_init('0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650', 16);
$n = gmp_init('000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409', 16);
$generator = Point::create($x, $y, $n);

return new Curve(521, $p, $a, $b, $generator);
Expand Down
99 changes: 89 additions & 10 deletions src/Component/Encryption/Algorithm/KeyEncryption/ECDHES.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,17 +264,13 @@ private function convertDecToBin(\GMP $dec): string
*/
public function createECKey(string $crv): JWK
{
$curve = $this->getCurve($crv);
$privateKey = $curve->createPrivateKey();
$point = $curve->createPublicKey($privateKey)->getPoint();
try {
$jwk = self::createECKeyUsingOpenSSL($crv);
} catch (\Exception $e) {
$jwk = self::createECKeyUsingPurePhp($crv);
}

return JWK::create([
'kty' => 'EC',
'crv' => $crv,
'x' => Base64Url::encode($this->convertDecToBin($point->getX())),
'y' => Base64Url::encode($this->convertDecToBin($point->getY())),
'd' => Base64Url::encode($this->convertDecToBin($privateKey->getSecret())),
]);
return JWK::create($jwk);
}

/**
Expand Down Expand Up @@ -308,4 +304,87 @@ public static function createOKPKey(string $curve): JWK
'd' => Base64Url::encode($d),
]);
}

/**
* @param string $curve
*
* @return array
*/
private static function createECKeyUsingPurePhp(string $curve): array
{
switch ($curve) {
case 'P-256':
$nistCurve = NistCurve::curve256();

break;
case 'P-384':
$nistCurve = NistCurve::curve384();

break;
case 'P-521':
$nistCurve = NistCurve::curve521();

break;
default:
throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve));
}

$privateKey = $nistCurve->createPrivateKey();
$publicKey = $nistCurve->createPublicKey($privateKey);

return [
'kty' => 'EC',
'crv' => $curve,
'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
];
}

/**
* @param string $curve
*
* @return array
*/
private static function createECKeyUsingOpenSSL(string $curve): array
{
$key = openssl_pkey_new([
'curve_name' => self::getOpensslCurveName($curve),
'private_key_type' => OPENSSL_KEYTYPE_EC,
]);
$res = openssl_pkey_export($key, $out);
if (false === $res) {
throw new \RuntimeException('Unable to create the key');
}
$res = openssl_pkey_get_private($out);

$details = openssl_pkey_get_details($res);

return [
'kty' => 'EC',
'crv' => $curve,
'd' => Base64Url::encode($details['ec']['d']),
'x' => Base64Url::encode($details['ec']['x']),
'y' => Base64Url::encode($details['ec']['y']),
];
}

/**
* @param string $curve
*
* @return string
*/
private static function getOpensslCurveName(string $curve): string
{
switch ($curve) {
case 'P-256':
return 'prime256v1';
case 'P-384':
return 'secp384r1';
case 'P-521':
return 'secp521r1';
default:
throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve));
}
}
}
81 changes: 70 additions & 11 deletions src/Component/KeyManagement/JWKFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ public static function createRSAKey(int $size, array $values = []): JWK
* @return JWK
*/
public static function createECKey(string $curve, array $values = []): JWK
{
try {
$jwk = self::createECKeyUsingOpenSSL($curve);
} catch (\Exception $e) {
$jwk = self::createECKeyUsingPurePhp($curve);
}
$values = array_merge($values, $jwk);

return JWK::create($values);
}

/**
* @param string $curve
*
* @return array
*/
private static function createECKeyUsingPurePhp(string $curve): array
{
switch ($curve) {
case 'P-256':
Expand All @@ -84,18 +101,60 @@ public static function createECKey(string $curve, array $values = []): JWK
$privateKey = $nistCurve->createPrivateKey();
$publicKey = $nistCurve->createPublicKey($privateKey);

$values = array_merge(
$values,
[
'kty' => 'EC',
'crv' => $curve,
'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
]
);
return [
'kty' => 'EC',
'crv' => $curve,
'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
];
}

return JWK::create($values);
/**
* @param string $curve
*
* @return array
*/
private static function createECKeyUsingOpenSSL(string $curve): array
{
$key = openssl_pkey_new([
'curve_name' => self::getOpensslCurveName($curve),
'private_key_type' => OPENSSL_KEYTYPE_EC,
]);
$res = openssl_pkey_export($key, $out);
if (false === $res) {
throw new \RuntimeException('Unable to create the key');
}
$res = openssl_pkey_get_private($out);

$details = openssl_pkey_get_details($res);

return [
'kty' => 'EC',
'crv' => $curve,
'x' => Base64Url::encode(bin2hex($details['ec']['x'])),
'y' => Base64Url::encode(bin2hex($details['ec']['y'])),
'd' => Base64Url::encode(bin2hex($details['ec']['d'])),
];
}

/**
* @param string $curve
*
* @return string
*/
private static function getOpensslCurveName(string $curve): string
{
switch ($curve) {
case 'P-256':
return 'prime256v1';
case 'P-384':
return 'secp384r1';
case 'P-521':
return 'secp521r1';
default:
throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve));
}
}

/**
Expand Down