Skip to content

Commit

Permalink
Test SecureFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
paragonie-security committed May 1, 2024
1 parent 1f6df4d commit 8d481ff
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 18 deletions.
18 changes: 9 additions & 9 deletions src/Curves/CurveFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ class CurveFactory
public static function getCurveByName(string $name): NamedCurveFp
{
$adapter = MathAdapterFactory::getAdapter();
$nistFactory = self::getNistFactory($adapter);
$brainpoolFactory = self::getBrainpoolFactory($adapter);
$secpFactory = self::getSecpFactory($adapter);
$nistFactory = static::getNistFactory($adapter);
$brainpoolFactory = static::getBrainpoolFactory($adapter);
$secpFactory = static::getSecpFactory($adapter);

switch ($name) {
case NistCurve::NAME_P192:
Expand Down Expand Up @@ -62,9 +62,9 @@ public static function getCurveByName(string $name): NamedCurveFp
public static function getGeneratorByName(string $name): GeneratorPoint
{
$adapter = MathAdapterFactory::getAdapter();
$nistFactory = self::getNistFactory($adapter);
$brainpoolFactory = self::getBrainpoolFactory($adapter);
$secpFactory = self::getSecpFactory($adapter);
$nistFactory = static::getNistFactory($adapter);
$brainpoolFactory = static::getBrainpoolFactory($adapter);
$secpFactory = static::getSecpFactory($adapter);

switch ($name) {
case NistCurve::NAME_P192:
Expand Down Expand Up @@ -104,7 +104,7 @@ public static function getGeneratorByName(string $name): GeneratorPoint
* @param GmpMathInterface $math
* @return NistCurve
*/
private static function getNistFactory(GmpMathInterface $math): NistCurve
protected static function getNistFactory(GmpMathInterface $math): NistCurve
{
return new NistCurve($math);
}
Expand All @@ -113,7 +113,7 @@ private static function getNistFactory(GmpMathInterface $math): NistCurve
* @param GmpMathInterface $math
* @return BrainpoolCurve
*/
private static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCurve
protected static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCurve
{
return new BrainpoolCurve($math);
}
Expand All @@ -122,7 +122,7 @@ private static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCu
* @param GmpMathInterface $math
* @return SecgCurve
*/
private static function getSecpFactory(GmpMathInterface $math): SecgCurve
protected static function getSecpFactory(GmpMathInterface $math): SecgCurve
{
return new SecgCurve($math);
}
Expand Down
48 changes: 44 additions & 4 deletions src/Curves/SecgCurve.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use GMP;
use Mdanter\Ecc\Math\GmpMathInterface;
use Mdanter\Ecc\Optimized\K256;
use Mdanter\Ecc\Optimized\P256;
use Mdanter\Ecc\Optimized\P384;
use Mdanter\Ecc\Primitives\CurveParameters;
use Mdanter\Ecc\Primitives\GeneratorPoint;
use Mdanter\Ecc\Random\RandomNumberGeneratorInterface;
Expand Down Expand Up @@ -203,6 +205,42 @@ public function curve256r1(): NamedCurveFp
return new NamedCurveFp(self::NAME_SECP_256R1, $parameters, $this->adapter);
}


/**
* Returns an NIST P-256 curve.
*
* @return NamedCurveFp
*/
public function optimizedCurve256r1(): NamedCurveFp
{
/** @var GMP $p */
$p = gmp_init('115792089210356248762697446949407573530086143415290314195533631308867097853951', 10);
/** @var GMP $b */
$b = gmp_init('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b', 16);

/** @var GMP $minusThree */
$minusThree = gmp_init(-3, 10);
$parameters = new CurveParameters(256, $p, $minusThree, $b);

return (new OptimizedCurveFp(self::NAME_SECP_256R1, $parameters, $this->adapter))
->setOptimizedCurveOps(new P256());
}

public function optimizedCurve384r1(): NamedCurveFp
{
/** @var GMP $p */
$p = gmp_init('39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319', 10);
/** @var GMP $b */
$b = gmp_init('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef', 16);

/** @var GMP $minus3 */
$minus3 = gmp_init(-3, 10);
$parameters = new CurveParameters(384, $p, $minus3, $b);

return (new OptimizedCurveFp(self::NAME_SECP_384R1, $parameters, $this->adapter))
->setOptimizedCurveOps(new P384());
}

/**
* @param ?RandomNumberGeneratorInterface $randomGenerator
* @param bool $optimized
Expand All @@ -211,9 +249,10 @@ public function curve256r1(): NamedCurveFp
public function generator256r1(?RandomNumberGeneratorInterface $randomGenerator = null, bool $optimized = false): GeneratorPoint
{
if ($optimized) {
return (new NistCurve($this->adapter))->generator256($randomGenerator, true);
$curve = $this->optimizedCurve256r1();
} else {
$curve = $this->curve256r1();
}
$curve = $this->curve256r1();

/** @var GMP $order */
$order = gmp_init('0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16);
Expand Down Expand Up @@ -250,9 +289,10 @@ public function curve384r1(): NamedCurveFp
public function generator384r1(?RandomNumberGeneratorInterface $randomGenerator = null, bool $optimized = false): GeneratorPoint
{
if ($optimized) {
return (new NistCurve($this->adapter))->generator256($randomGenerator, true);
$curve = $this->optimizedCurve384r1();
} else {
$curve = $this->curve384r1();
}
$curve = $this->curve384r1();

/** @var GMP $order */
$order = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973', 16);
Expand Down
93 changes: 90 additions & 3 deletions src/Curves/SecureCurveFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,106 @@

namespace Mdanter\Ecc\Curves;

use Mdanter\Ecc\Exception\InsecureCurveException;
use Mdanter\Ecc\Exception\UnsupportedCurveException;
use Mdanter\Ecc\Math\GmpMathInterface;
use Mdanter\Ecc\Math\MathAdapterFactory;
use Mdanter\Ecc\Primitives\GeneratorPoint;

/**
* Similar to CurveFactory, but only returns secure implementations
*/
class SecureCurveFactory extends CurveFactory
{
/**
* @param string $name
* @return NamedCurveFp
*/
public static function getCurveByName(string $name): NamedCurveFp
{
$adapter = MathAdapterFactory::getAdapter();
$nistFactory = static::getNistFactory($adapter);
$brainpoolFactory = static::getBrainpoolFactory($adapter);
$secpFactory = static::getSecpFactory($adapter);

switch ($name) {
case SecgCurve::NAME_SECP_112R1:
case SecgCurve::NAME_SECP_192K1:
case NistCurve::NAME_P192:
case NistCurve::NAME_P224:
throw new InsecureCurveException('This is not a secure curve: '. $name);
case SecgCurve::NAME_SECP_256K1:
return $secpFactory->optimizedCurve256k1();
case SecgCurve::NAME_SECP_256R1:
return $secpFactory->optimizedCurve256r1();
case NistCurve::NAME_P256:
return $nistFactory->optimizedCurve256();
case SecgCurve::NAME_SECP_384R1:
return $secpFactory->optimizedCurve384r1();
case NistCurve::NAME_P384:
return $nistFactory->optimizedCurve384();
case NistCurve::NAME_P521:
return $nistFactory->optimizedCurve521();
case BrainpoolCurve::NAME_P256R1:
return $brainpoolFactory->optimizedCurve256r1();
case BrainpoolCurve::NAME_P384R1:
return $brainpoolFactory->optimizedCurve384r1();
case BrainpoolCurve::NAME_P512R1:
return $brainpoolFactory->optimizedCurve512r1();
default:
$error = new UnsupportedCurveException('Unknown curve.');
$error->setCurveName($name);
throw $error;
}
}

/**
* @param string $name
* @return GeneratorPoint
*/
public static function getGeneratorByName(string $name): GeneratorPoint
{
$adapter = MathAdapterFactory::getAdapter();
$nistFactory = static::getNistFactory($adapter);
$brainpoolFactory = static::getBrainpoolFactory($adapter);
$secpFactory = static::getSecpFactory($adapter);

switch ($name) {
case SecgCurve::NAME_SECP_112R1:
case SecgCurve::NAME_SECP_192K1:
case NistCurve::NAME_P192:
case NistCurve::NAME_P224:
throw new InsecureCurveException('This is not a secure curve: '. $name);
case NistCurve::NAME_P256:
return $nistFactory->generator256(null, true);
case NistCurve::NAME_P384:
return $nistFactory->generator384(null, true);
case NistCurve::NAME_P521:
return $nistFactory->generator521(null, true);
case BrainpoolCurve::NAME_P256R1:
return $brainpoolFactory->generator256r1(null, true);
case BrainpoolCurve::NAME_P384R1:
return $brainpoolFactory->generator384r1(null, true);
case BrainpoolCurve::NAME_P512R1:
return $brainpoolFactory->generator512r1(null, true);
case SecgCurve::NAME_SECP_256K1:
return $secpFactory->generator256k1(null, true);
case SecgCurve::NAME_SECP_256R1:
return $secpFactory->generator256r1(null, true);
case SecgCurve::NAME_SECP_384R1:
return $secpFactory->generator384r1(null, true);
default:
$error = new UnsupportedCurveException('Unknown generator.');
$error->setCurveName($name);
throw $error;
}
}

/**
* @param GmpMathInterface $math
* @return NistCurve
*/
private static function getNistFactory(GmpMathInterface $math): NistCurve
protected static function getNistFactory(GmpMathInterface $math): NistCurve
{
return new SecureNistCurve($math);
}
Expand All @@ -23,7 +110,7 @@ private static function getNistFactory(GmpMathInterface $math): NistCurve
* @param GmpMathInterface $math
* @return BrainpoolCurve
*/
private static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCurve
protected static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCurve
{
return new SecureBrainpoolCurve($math);
}
Expand All @@ -32,7 +119,7 @@ private static function getBrainpoolFactory(GmpMathInterface $math): BrainpoolCu
* @param GmpMathInterface $math
* @return SecgCurve
*/
private static function getSecpFactory(GmpMathInterface $math): SecgCurve
protected static function getSecpFactory(GmpMathInterface $math): SecgCurve
{
return new SecureSecgCurve($math);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Curves/SecureSecgCurve.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function curve256r1(): NamedCurveFp
{
$curve = parent::curve256r1();
if (!$curve->isOpensslAvailable()) {
throw new InsecureCurveException('Cannot securely use non-optimized secp256k1 without OpenSSL support');
throw new InsecureCurveException('Cannot securely use non-optimized secp256r1 without OpenSSL support');
}
return $curve;
}
Expand All @@ -50,7 +50,7 @@ public function curve384r1(): NamedCurveFp
{
$curve = parent::curve384r1();
if (!$curve->isOpensslAvailable()) {
throw new InsecureCurveException('Cannot securely use non-optimized secp256k1 without OpenSSL support');
throw new InsecureCurveException('Cannot securely use non-optimized secp384r1 without OpenSSL support');
}
return $curve;
}
Expand Down
69 changes: 69 additions & 0 deletions tests/unit/Curves/SecureFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace Mdanter\Ecc\Tests\Curves;

use Mdanter\Ecc\Curves\BrainpoolCurve;
use Mdanter\Ecc\Curves\SecureCurveFactory;
use Mdanter\Ecc\Curves\NistCurve;
use Mdanter\Ecc\Curves\SecgCurve;
use Mdanter\Ecc\Exception\InsecureCurveException;
use Mdanter\Ecc\Tests\AbstractTestCase;

class SecureFactoryTest extends AbstractTestCase
{
public function getInsecureCurves(): array
{
return [
[NistCurve::NAME_P192],
[NistCurve::NAME_P224],
[SecgCurve::NAME_SECP_112R1],
[SecgCurve::NAME_SECP_192K1],
];
}

public function getCurveNames(): array
{
return [
[NistCurve::NAME_P256],
[NistCurve::NAME_P384],
[NistCurve::NAME_P521],
[BrainpoolCurve::NAME_P256R1],
[BrainpoolCurve::NAME_P384R1],
[BrainpoolCurve::NAME_P512R1],
[SecgCurve::NAME_SECP_256R1],
[SecgCurve::NAME_SECP_256K1],
[SecgCurve::NAME_SECP_384R1],
];
}

/**
* @param string $name
* @dataProvider getInsecureCurves
*/
public function testThrowsIfInsecureCurve(string $name): void
{
$this->expectException(InsecureCurveException::class);
SecureCurveFactory::getCurveByName($name);
}
/**
* @param string $name
* @dataProvider getInsecureCurves
*/
public function testThrowsIfInsecureGenerator(string $name): void
{
$this->expectException(InsecureCurveException::class);
SecureCurveFactory::getGeneratorByName($name);
}

/**
* @param string $name
* @dataProvider getCurveNames
*/
public function testLoadsCurveByName(string $name): void
{
$curve = SecureCurveFactory::getCurveByName($name);
$generator = SecureCurveFactory::getGeneratorByName($name);
$this->assertEquals($name, $curve->getName());
$this->assertEquals($name, $generator->getCurve()->getName());
}
}

0 comments on commit 8d481ff

Please sign in to comment.