<?php namespace Mdanter\Ecc\Serializer\PrivateKey; use FG\ASN1\Object; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\Integer; use FG\ASN1\Universal\BitString; use FG\ASN1\Universal\OctetString; use Mdanter\Ecc\Crypto\Key\PrivateKeyInterface; use Mdanter\Ecc\Math\GmpMathInterface; use Mdanter\Ecc\Math\MathAdapterFactory; use Mdanter\Ecc\Serializer\Util\CurveOidMapper; use Mdanter\Ecc\Serializer\PublicKey\PemPublicKeySerializer; use Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer; use FG\ASN1\ExplicitlyTaggedObject; /** * PEM Private key formatter * * @link https://tools.ietf.org/html/rfc5915 */ class DerPrivateKeySerializer implements PrivateKeySerializerInterface { const VERSION = 1; /** * @var GmpMathInterface|null */ private $adapter; /** * @var DerPublicKeySerializer */ private $pubKeySerializer; /** * @param GmpMathInterface $adapter * @param PemPublicKeySerializer $pubKeySerializer */ public function __construct(GmpMathInterface $adapter = null, PemPublicKeySerializer $pubKeySerializer = null) { $this->adapter = $adapter ?: MathAdapterFactory::getAdapter(); $this->pubKeySerializer = $pubKeySerializer ?: new DerPublicKeySerializer($this->adapter); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKeySerializerInterface::serialize() */ public function serialize(PrivateKeyInterface $key) { $privateKeyInfo = new Sequence( new Integer(self::VERSION), new OctetString($this->formatKey($key)), new ExplicitlyTaggedObject(0, CurveOidMapper::getCurveOid($key->getPoint()->getCurve())), new ExplicitlyTaggedObject(1, $this->encodePubKey($key)) ); return $privateKeyInfo->getBinary(); } /** * @param PrivateKeyInterface $key * @return BitString */ private function encodePubKey(PrivateKeyInterface $key) { return new BitString( $this->pubKeySerializer->getUncompressedKey($key->getPublicKey()) ); } /** * @param PrivateKeyInterface $key * @return string */ private function formatKey(PrivateKeyInterface $key) { return gmp_strval($key->getSecret(), 16); } /** * @param string $data * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKeySerializerInterface::parse() * @throws \FG\ASN1\Exception\ParserException */ public function parse($data) { $asnObject = Object::fromBinary($data); if (! ($asnObject instanceof Sequence) || $asnObject->getNumberofChildren() !== 4) { throw new \RuntimeException('Invalid data.'); } $children = $asnObject->getChildren(); $version = $children[0]; if ($version->getContent() != 1) { throw new \RuntimeException('Invalid data: only version 1 (RFC5915) keys are supported.'); } $key = gmp_init($children[1]->getContent(), 16); $oid = $children[2]->getContent()[0]; $generator = CurveOidMapper::getGeneratorFromOid($oid); return $generator->getPrivateKeyFrom($key); } }