Skip to content

Commit

Permalink
Merge pull request #2003 from LeonMelis/3.0
Browse files Browse the repository at this point in the history
Fix support for Ed448 private keys in PKCS#8 format
  • Loading branch information
terrafrost committed May 25, 2024
2 parents da7b239 + 514b907 commit 541887c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 13 deletions.
46 changes: 33 additions & 13 deletions phpseclib/Crypt/EC/Formats/Keys/PKCS8.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,21 @@ private static function loadEdDSA(array $key)
$components = [];

if (isset($key['privateKey'])) {
$components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448();

// 0x04 == octet string
// 0x20 == length (32 bytes)
if (substr($key['privateKey'], 0, 2) != "\x04\x20") {
throw new \RuntimeException('The first two bytes of the private key field should be 0x0420');
if ($key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519') {
$components['curve'] = new Ed25519();
// 0x04 == octet string
// 0x20 == length (32 bytes)
if (substr($key['privateKey'], 0, 2) != "\x04\x20") {
throw new \RuntimeException('The first two bytes of the Ed25519 private key field should be 0x0420');
}
} else {
// Assume Ed448
$components['curve'] = new Ed448();
// 0x04 == octet string
// 0x39 == length (57 bytes)
if (substr($key['privateKey'], 0, 2) != "\x04\x39") {
throw new \RuntimeException('The first two bytes of the Ed448 private key field should be 0x0439');
}
}
$arr = $components['curve']->extractSecret(substr($key['privateKey'], 2));
$components['dA'] = $arr['dA'];
Expand Down Expand Up @@ -207,13 +216,24 @@ public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve,
}

if ($curve instanceof TwistedEdwardsCurve) {
return self::wrapPrivateKey(
"\x04\x20" . $secret,
[],
null,
$password,
$curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448'
);
if ($curve instanceof Ed25519) {
return self::wrapPrivateKey(
"\x04\x20" . $secret,
[],
null,
$password,
'id-Ed25519'
);
} else {
// Assume Ed448
return self::wrapPrivateKey(
"\x04\x39" . $secret,
[],
null,
$password,
'id-Ed448'
);
}
}

$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
Expand Down
27 changes: 27 additions & 0 deletions tests/Unit/Crypt/EC/KeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,33 @@ public function testEd25519PrivateKey()
$this->assertSameNL('Ed25519', $key->getPublicKey()->getCurve());
}

// Generate with:
// openssl genpkey -algorithm ed448 | openssl ec -pubout
public function testEd448PublicKey()
{
$expected = '-----BEGIN PUBLIC KEY-----
MEMwBQYDK2VxAzoAsA7zbld48IfDhm7Qd6FYrvnljtjhPRRqZi04NWyj8VXrWe1x
BMLQFJEE0JDmKayUWpUWsRXwmb6A
-----END PUBLIC KEY-----';
$key = PublicKeyLoader::load($expected);
$this->assertSameNL('Ed448', $key->getCurve());
$this->assertSameNL($expected, $key->toString('PKCS8'));
}

// Generate with:
// openssl genpkey -algorithm ed448
public function testEd448PrivateKey()
{
$expected = '-----BEGIN PRIVATE KEY-----
MEcCAQAwBQYDK2VxBDsEOettXaJYob4hJNKJNOD+FfMvdesLKNp0KwochI6AKmAb
tWhtkn99WOjd1PsGMh9zz2Vhdg3MwasOMQ==
-----END PRIVATE KEY-----';
$key = PublicKeyLoader::load($expected);
$this->assertSameNL($expected, $key->toString('PKCS8'));
$this->assertSameNL('Ed448', $key->getCurve());
$this->assertSameNL('Ed448', $key->getPublicKey()->getCurve());
}

public function testPuTTYnistp256()
{
$key = PublicKeyLoader::load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
Expand Down

0 comments on commit 541887c

Please sign in to comment.