1<?php
2
3/**
4 * PKCS#1 Formatted DSA Key Handler
5 *
6 * PHP version 5
7 *
8 * Used by File/X509.php
9 *
10 * Processes keys with the following headers:
11 *
12 * -----BEGIN DSA PRIVATE KEY-----
13 * -----BEGIN DSA PUBLIC KEY-----
14 * -----BEGIN DSA PARAMETERS-----
15 *
16 * Analogous to ssh-keygen's pem format (as specified by -m)
17 *
18 * Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA.
19 * The DSA private key format seems to have been adapted from the RSA private key format so
20 * we're just re-using that as the name.
21 *
22 * @category  Crypt
23 * @package   DSA
24 * @author    Jim Wigginton <terrafrost@php.net>
25 * @copyright 2015 Jim Wigginton
26 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
27 * @link      http://phpseclib.sourceforge.net
28 */
29
30namespace phpseclib3\Crypt\DSA\Formats\Keys;
31
32use ParagonIE\ConstantTime\Base64;
33use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
34use phpseclib3\File\ASN1;
35use phpseclib3\File\ASN1\Maps;
36use phpseclib3\Math\BigInteger;
37
38/**
39 * PKCS#1 Formatted DSA Key Handler
40 *
41 * @package RSA
42 * @author  Jim Wigginton <terrafrost@php.net>
43 * @access  public
44 */
45abstract class PKCS1 extends Progenitor
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        $key = parent::load($key, $password);
58
59        $decoded = ASN1::decodeBER($key);
60        if (empty($decoded)) {
61            throw new \RuntimeException('Unable to decode BER');
62        }
63
64        $key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
65        if (is_array($key)) {
66            return $key;
67        }
68
69        $key = ASN1::asn1map($decoded[0], Maps\DSAPrivateKey::MAP);
70        if (is_array($key)) {
71            return $key;
72        }
73
74        $key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
75        if (is_array($key)) {
76            return $key;
77        }
78
79        throw new \RuntimeException('Unable to perform ASN1 mapping');
80    }
81
82    /**
83     * Convert DSA parameters to the appropriate format
84     *
85     * @access public
86     * @param \phpseclib3\Math\BigInteger $p
87     * @param \phpseclib3\Math\BigInteger $q
88     * @param \phpseclib3\Math\BigInteger $g
89     * @return string
90     */
91    public static function saveParameters(BigInteger $p, BigInteger $q, BigInteger $g)
92    {
93        $key = [
94            'p' => $p,
95            'q' => $q,
96            'g' => $g
97        ];
98
99        $key = ASN1::encodeDER($key, Maps\DSAParams::MAP);
100
101        return "-----BEGIN DSA PARAMETERS-----\r\n" .
102               chunk_split(Base64::encode($key), 64) .
103               "-----END DSA PARAMETERS-----\r\n";
104    }
105
106    /**
107     * Convert a private key to the appropriate format.
108     *
109     * @access public
110     * @param \phpseclib3\Math\BigInteger $p
111     * @param \phpseclib3\Math\BigInteger $q
112     * @param \phpseclib3\Math\BigInteger $g
113     * @param \phpseclib3\Math\BigInteger $y
114     * @param \phpseclib3\Math\BigInteger $x
115     * @param string $password optional
116     * @param array $options optional
117     * @return string
118     */
119    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
120    {
121        $key = [
122            'version' => 0,
123            'p' => $p,
124            'q' => $q,
125            'g' => $g,
126            'y' => $y,
127            'x' => $x
128        ];
129
130        $key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP);
131
132        return self::wrapPrivateKey($key, 'DSA', $password, $options);
133    }
134
135    /**
136     * Convert a public key to the appropriate format
137     *
138     * @access public
139     * @param \phpseclib3\Math\BigInteger $p
140     * @param \phpseclib3\Math\BigInteger $q
141     * @param \phpseclib3\Math\BigInteger $g
142     * @param \phpseclib3\Math\BigInteger $y
143     * @return string
144     */
145    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
146    {
147        $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
148
149        return self::wrapPublicKey($key, 'DSA');
150    }
151}
152