1
0
mirror of https://github.com/danog/tgseclib.git synced 2024-11-30 04:39:02 +01:00

add support for Curve448

This commit is contained in:
terrafrost 2019-08-08 08:01:49 -05:00
parent 7cf5facae7
commit 68f3d7d8af
7 changed files with 160 additions and 30 deletions

View File

@ -30,6 +30,7 @@ use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\PrimeField;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\EC\Curves\Curve25519;
use phpseclib\Math\PrimeField\Integer as PrimeInteger;
/**
@ -202,7 +203,8 @@ class Montgomery extends Base
$temp = $da->subtract($cb);
$z5 = $x1->multiply($temp->multiply($temp));
$x4 = $aa->multiply($bb);
$z4 = $e->multiply($bb->add($this->a24->multiply($e)));
$temp = static::class == Curve25519::class ? $bb : $aa;
$z4 = $e->multiply($temp->add($this->a24->multiply($e)));
return [
[$x4, $z4],

View File

@ -36,7 +36,7 @@ class Curve25519 extends Montgomery
);
$this->setBasePoint(
new BigInteger(9),
new BigInteger('14781619447589544791020593568409986887264606134616475288964881837755586237401', 16)
new BigInteger('14781619447589544791020593568409986887264606134616475288964881837755586237401')
);
*/
}

View File

@ -0,0 +1,71 @@
<?php
/**
* Curve448
*
* PHP version 5 and 7
*
* @category Crypt
* @package EC
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\EC\Curves;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Crypt\EC\BaseCurves\Montgomery;
use phpseclib\Math\BigInteger;
class Curve448 extends Montgomery
{
public function __construct()
{
// 2^448 - 2^224 - 1
$this->setModulo(new BigInteger(
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->a24 = $this->factory->newInteger(new BigInteger('39081'));
$this->p = [$this->factory->newInteger(new BigInteger(5))];
// 2^446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d
$this->setOrder(new BigInteger(
'3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3', 16));
/*
$this->setCoefficients(
new BigInteger('156326'), // a
);
$this->setBasePoint(
new BigInteger(5),
new BigInteger(
'355293926785568175264127502063783334808976399387714271831880898' .
'435169088786967410002932673765864550910142774147268105838985595290' .
'606362')
);
*/
}
/**
* Multiply a point on the curve by a scalar
*
* Modifies the scalar as described at https://tools.ietf.org/html/rfc7748#page-8
*
* @return array
*/
public function multiplyPoint(array $p, Integer $d)
{
//$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes())));
//return [$this->factory->newInteger(new BigInteger($r, 256))];
$d = $d->toBytes();
$d[0] = $d[0] & "\xFC";
$d = strrev($d);
$d|= "\x80";
$d = $this->factory->newInteger(new BigInteger($d, 256));
return parent::multiplyPoint($p, $d);
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* Curve25519 Private Key Handler
* Montgomery Private Key Handler
*
* "Naked" Curve25519 private keys can pretty much be any sequence of random 32x bytes so unless
* we have a "hidden" key handler pretty much every 32 byte string will be loaded as a curve25519
@ -23,17 +23,19 @@
namespace phpseclib\Crypt\EC\Formats\Keys;
use phpseclib\Crypt\EC\Curves\Curve25519;
use phpseclib\Crypt\EC\Curves\Curve448;
use phpseclib\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Math\BigInteger;
/**
* Curve25519 Private Key Handler
* Montgomery Curve Private Key Handler
*
* @package EC
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class Curve25519Private
abstract class MontgomeryPrivate
{
/**
* Is invisible flag
@ -52,10 +54,19 @@ abstract class Curve25519Private
*/
public static function load($key, $password = '')
{
$curve = new Curve25519();
switch (strlen($key)) {
case 32:
$curve = new Curve25519;
break;
case 56:
$curve = new Curve448;
break;
default:
throw new \LengthException('The only supported lengths are 32 and 56');
}
$components = ['curve' => $curve];
$components['dA'] = $components['curve']->convertInteger(new BigInteger($key, -256));
$components['dA'] = $components['curve']->convertInteger(new BigInteger($key, 256));
// note that EC::getEncodedCoordinates does some additional "magic" (it does strrev on the result)
$components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
@ -66,13 +77,13 @@ abstract class Curve25519Private
* Convert an EC public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\EC\Curves\Curve25519 $curve
* @param \phpseclib\Crypt\EC\Curves\MontgomeryCurve $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(Curve25519 $curve, array $publicKey)
public static function savePublicKey(MontgomeryCurve $curve, array $publicKey)
{
return strrev($publicKey[0]->toBytes(true));
return strrev($publicKey[0]->toBytes());
}
/**
@ -80,13 +91,13 @@ abstract class Curve25519Private
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\EC\Curves\Curve25519 $curve
* @param \phpseclib\Crypt\EC\Curves\Montgomery $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, Curve25519 $curve, array $publicKey, $password = '')
public static function savePrivateKey(Integer $privateKey, MontgomeryCurve $curve, array $publicKey, $password = '')
{
return $privateKey->toBytes(true);
return $privateKey->toBytes();
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* Curve25519 Public Key Handler
* Montgomery Public Key Handler
*
* PHP version 5
*
@ -16,17 +16,19 @@
namespace phpseclib\Crypt\EC\Formats\Keys;
use phpseclib\Crypt\EC\Curves\Curve25519;
use phpseclib\Crypt\EC\Curves\Curve448;
use phpseclib\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Math\BigInteger;
/**
* Curve25519 Public Key Handler
* Montgomery Public Key Handler
*
* @package EC
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class Curve25519Public
abstract class MontgomeryPublic
{
/**
* Is invisible flag
@ -45,10 +47,19 @@ abstract class Curve25519Public
*/
public static function load($key, $password = '')
{
$curve = new Curve25519();
switch (strlen($key)) {
case 32:
$curve = new Curve25519;
break;
case 56:
$curve = new Curve448;
break;
default:
throw new \LengthException('The only supported lengths are 32 and 56');
}
$components = ['curve' => $curve];
$components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key), -256))];
$components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key), 256))];
return $components;
}
@ -57,12 +68,12 @@ abstract class Curve25519Public
* Convert an EC public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\EC\Curves\Curve25519 $curve
* @param \phpseclib\Crypt\EC\Curves\Montgomery $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(Curve25519 $curve, array $publicKey)
public static function savePublicKey(MontgomeryCurve $curve, array $publicKey)
{
return strrev($publicKey[0]->toBytes(true));
return strrev($publicKey[0]->toBytes());
}
}

View File

@ -235,9 +235,7 @@ class PrivateKey extends EC implements Common\PrivateKey
{
$format = 'PKCS8';
if ($this->curve instanceof MontgomeryCurve) {
$format = $this->curve instanceof Curve25519 ?
'Curve25519Public' :
'Curve448Public';
$format = 'MontgomeryPublic';
}
$type = self::validatePlugin('Keys', $format, 'savePublicKey');

View File

@ -153,11 +153,11 @@ Q3ADAIcv9LEmTBnSAOsCs1K9ExAmSv/T2/4+9dW28UYb+p/uV477d1wf+nCWS6VU
$aes->setIV(substr($key, 16, 16));
$encrypted =
$ourEphemeralPublic->toString('Curve25519Public') .
$ourEphemeralPublic->toString('MontgomeryPublic') .
$aes->encrypt($plaintext);
$theirPublic = substr($encrypted, 0, 32);
$theirPublic = EC::loadFormat('Curve25519Public', $theirPublic);
$theirPublic = EC::loadFormat('MontgomeryPublic', $theirPublic);
$ourPrivate = $theirPrivate;
@ -205,20 +205,20 @@ Q3ADAIcv9LEmTBnSAOsCs1K9ExAmSv/T2/4+9dW28UYb+p/uV477d1wf+nCWS6VU
{
// utilizing test vector from https://tools.ietf.org/html/rfc7748#section-6.1
$alicePrivate = EC::loadFormat('Curve25519Private', pack('H*', '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a'));
$bobPrivate = EC::loadFormat('Curve25519Private', pack('H*', '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb'));
$alicePrivate = EC::loadFormat('MontgomeryPrivate', pack('H*', '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a'));
$bobPrivate = EC::loadFormat('MontgomeryPrivate', pack('H*', '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb'));
$alicePublic = $alicePrivate->getPublicKey();
$bobPublic = $bobPrivate->getPublicKey();
$this->assertSame(
'8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a',
bin2hex($alicePublic->toString('Curve25519Public'))
bin2hex($alicePublic->toString('MontgomeryPublic'))
);
$this->assertSame(
'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f',
bin2hex($bobPublic->toString('Curve25519Public'))
bin2hex($bobPublic->toString('MontgomeryPublic'))
);
$expected = pack('H*', '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742');
@ -226,4 +226,41 @@ Q3ADAIcv9LEmTBnSAOsCs1K9ExAmSv/T2/4+9dW28UYb+p/uV477d1wf+nCWS6VU
$this->assertSame($expected, DH::computeSecret($alicePrivate, $bobPublic));
$this->assertSame($expected, DH::computeSecret($bobPrivate, $alicePublic));
}
public function testCurve448()
{
// utilizing test vector from https://tools.ietf.org/html/rfc7748#section-6.2
$alicePrivate = EC::loadFormat('MontgomeryPrivate', pack('H*',
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28d' .
'd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b'
));
$bobPrivate = EC::loadFormat('MontgomeryPrivate', pack('H*',
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d' .
'6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d'
));
$alicePublic = $alicePrivate->getPublicKey();
$bobPublic = $bobPrivate->getPublicKey();
$this->assertSame(
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c' .
'22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0',
bin2hex($alicePublic->toString('MontgomeryPublic'))
);
$this->assertSame(
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b430' .
'27d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609',
bin2hex($bobPublic->toString('MontgomeryPublic'))
);
$expected = pack('H*',
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282b' .
'b60c0b56fd2464c335543936521c24403085d59a449a5037514a879d'
);
$this->assertSame($expected, DH::computeSecret($alicePrivate, $bobPublic));
$this->assertSame($expected, DH::computeSecret($bobPrivate, $alicePublic));
}
}