1<?php
2
3/**
4 * Montgomery Private Key Handler
5 *
6 * "Naked" Curve25519 private keys can pretty much be any sequence of random 32x bytes so unless
7 * we have a "hidden" key handler pretty much every 32 byte string will be loaded as a curve25519
8 * private key even if it probably isn't one by PublicKeyLoader.
9 *
10 * "Naked" Curve25519 public keys also a string of 32 bytes so distinguishing between a "naked"
11 * curve25519 private key and a public key is nigh impossible, hence separate plugins for each
12 *
13 * PHP version 5
14 *
15 * @category  Crypt
16 * @package   EC
17 * @author    Jim Wigginton <terrafrost@php.net>
18 * @copyright 2015 Jim Wigginton
19 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
20 * @link      http://phpseclib.sourceforge.net
21 */
22
23namespace phpseclib3\Crypt\EC\Formats\Keys;
24
25use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
26use phpseclib3\Crypt\EC\Curves\Curve25519;
27use phpseclib3\Crypt\EC\Curves\Curve448;
28use phpseclib3\Exception\UnsupportedFormatException;
29use phpseclib3\Math\BigInteger;
30
31/**
32 * Montgomery Curve Private Key Handler
33 *
34 * @package EC
35 * @author  Jim Wigginton <terrafrost@php.net>
36 * @access  public
37 */
38abstract class MontgomeryPrivate
39{
40    /**
41     * Is invisible flag
42     *
43     * @access private
44     */
45    const IS_INVISIBLE = true;
46
47    /**
48     * Break a public or private key down into its constituent components
49     *
50     * @access public
51     * @param string $key
52     * @param string $password optional
53     * @return array
54     */
55    public static function load($key, $password = '')
56    {
57        switch (strlen($key)) {
58            case 32:
59                $curve = new Curve25519();
60                break;
61            case 56:
62                $curve = new Curve448();
63                break;
64            default:
65                throw new \LengthException('The only supported lengths are 32 and 56');
66        }
67
68        $components = ['curve' => $curve];
69        $components['dA'] = new BigInteger($key, 256);
70        $curve->rangeCheck($components['dA']);
71        // note that EC::getEncodedCoordinates does some additional "magic" (it does strrev on the result)
72        $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
73
74        return $components;
75    }
76
77    /**
78     * Convert an EC public key to the appropriate format
79     *
80     * @access public
81     * @param \phpseclib3\Crypt\EC\BaseCurves\Montgomery $curve
82     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
83     * @return string
84     */
85    public static function savePublicKey(MontgomeryCurve $curve, array $publicKey)
86    {
87        return strrev($publicKey[0]->toBytes());
88    }
89
90    /**
91     * Convert a private key to the appropriate format.
92     *
93     * @access public
94     * @param \phpseclib3\Math\BigInteger $privateKey
95     * @param \phpseclib3\Crypt\EC\BaseCurves\Montgomery $curve
96     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
97     * @param string $password optional
98     * @return string
99     */
100    public static function savePrivateKey(BigInteger $privateKey, MontgomeryCurve $curve, array $publicKey, $password = '')
101    {
102        if (!empty($password) && is_string($password)) {
103            throw new UnsupportedFormatException('MontgomeryPrivate private keys do not support encryption');
104        }
105
106        return $privateKey->toBytes();
107    }
108}
109