Subversion Repositories oidplus

Rev

Rev 846 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
827 daniel-mar 1
<?php
2
 
3
/**
4
 * PKCS#1 Formatted RSA 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 RSA PRIVATE KEY-----
13
 * -----BEGIN RSA PUBLIC KEY-----
14
 *
15
 * Analogous to ssh-keygen's pem format (as specified by -m)
16
 *
874 daniel-mar 17
 * @category  Crypt
18
 * @package   RSA
827 daniel-mar 19
 * @author    Jim Wigginton <terrafrost@php.net>
20
 * @copyright 2015 Jim Wigginton
21
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
22
 * @link      http://phpseclib.sourceforge.net
23
 */
24
 
25
namespace phpseclib3\Crypt\RSA\Formats\Keys;
26
 
27
use phpseclib3\Common\Functions\Strings;
28
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
29
use phpseclib3\File\ASN1;
30
use phpseclib3\File\ASN1\Maps;
31
use phpseclib3\Math\BigInteger;
32
 
33
/**
34
 * PKCS#1 Formatted RSA Key Handler
35
 *
874 daniel-mar 36
 * @package RSA
827 daniel-mar 37
 * @author  Jim Wigginton <terrafrost@php.net>
874 daniel-mar 38
 * @access  public
827 daniel-mar 39
 */
40
abstract class PKCS1 extends Progenitor
41
{
42
    /**
43
     * Break a public or private key down into its constituent components
44
     *
874 daniel-mar 45
     * @access public
827 daniel-mar 46
     * @param string $key
47
     * @param string $password optional
48
     * @return array
49
     */
50
    public static function load($key, $password = '')
51
    {
52
        if (!Strings::is_stringable($key)) {
53
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
54
        }
55
 
56
        if (strpos($key, 'PUBLIC') !== false) {
57
            $components = ['isPublicKey' => true];
58
        } elseif (strpos($key, 'PRIVATE') !== false) {
59
            $components = ['isPublicKey' => false];
60
        } else {
61
            $components = [];
62
        }
63
 
64
        $key = parent::load($key, $password);
65
 
66
        $decoded = ASN1::decodeBER($key);
67
        if (empty($decoded)) {
68
            throw new \RuntimeException('Unable to decode BER');
69
        }
70
 
71
        $key = ASN1::asn1map($decoded[0], Maps\RSAPrivateKey::MAP);
72
        if (is_array($key)) {
73
            $components += [
74
                'modulus' => $key['modulus'],
75
                'publicExponent' => $key['publicExponent'],
76
                'privateExponent' => $key['privateExponent'],
77
                'primes' => [1 => $key['prime1'], $key['prime2']],
78
                'exponents' => [1 => $key['exponent1'], $key['exponent2']],
79
                'coefficients' => [2 => $key['coefficient']]
80
            ];
81
            if ($key['version'] == 'multi') {
82
                foreach ($key['otherPrimeInfos'] as $primeInfo) {
83
                    $components['primes'][] = $primeInfo['prime'];
84
                    $components['exponents'][] = $primeInfo['exponent'];
85
                    $components['coefficients'][] = $primeInfo['coefficient'];
86
                }
87
            }
88
            if (!isset($components['isPublicKey'])) {
89
                $components['isPublicKey'] = false;
90
            }
91
            return $components;
92
        }
93
 
94
        $key = ASN1::asn1map($decoded[0], Maps\RSAPublicKey::MAP);
95
 
96
        if (!is_array($key)) {
97
            throw new \RuntimeException('Unable to perform ASN1 mapping');
98
        }
99
 
100
        if (!isset($components['isPublicKey'])) {
101
            $components['isPublicKey'] = true;
102
        }
103
 
104
        return $components + $key;
105
    }
106
 
107
    /**
108
     * Convert a private key to the appropriate format.
109
     *
874 daniel-mar 110
     * @access public
827 daniel-mar 111
     * @param \phpseclib3\Math\BigInteger $n
112
     * @param \phpseclib3\Math\BigInteger $e
113
     * @param \phpseclib3\Math\BigInteger $d
114
     * @param array $primes
115
     * @param array $exponents
116
     * @param array $coefficients
117
     * @param string $password optional
118
     * @param array $options optional
119
     * @return string
120
     */
121
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
122
    {
123
        $num_primes = count($primes);
124
        $key = [
125
            'version' => $num_primes == 2 ? 'two-prime' : 'multi',
126
            'modulus' => $n,
127
            'publicExponent' => $e,
128
            'privateExponent' => $d,
129
            'prime1' => $primes[1],
130
            'prime2' => $primes[2],
131
            'exponent1' => $exponents[1],
132
            'exponent2' => $exponents[2],
133
            'coefficient' => $coefficients[2]
134
        ];
135
        for ($i = 3; $i <= $num_primes; $i++) {
136
            $key['otherPrimeInfos'][] = [
137
                'prime' => $primes[$i],
138
                'exponent' => $exponents[$i],
139
                'coefficient' => $coefficients[$i]
140
            ];
141
        }
142
 
143
        $key = ASN1::encodeDER($key, Maps\RSAPrivateKey::MAP);
144
 
145
        return self::wrapPrivateKey($key, 'RSA', $password, $options);
146
    }
147
 
148
    /**
149
     * Convert a public key to the appropriate format
150
     *
874 daniel-mar 151
     * @access public
827 daniel-mar 152
     * @param \phpseclib3\Math\BigInteger $n
153
     * @param \phpseclib3\Math\BigInteger $e
154
     * @return string
155
     */
156
    public static function savePublicKey(BigInteger $n, BigInteger $e)
157
    {
158
        $key = [
159
            'modulus' => $n,
160
            'publicExponent' => $e
161
        ];
162
 
163
        $key = ASN1::encodeDER($key, Maps\RSAPublicKey::MAP);
164
 
165
        return self::wrapPublicKey($key, 'RSA');
166
    }
167
}