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 * 17 * @category Crypt 18 * @package RSA 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 25namespace phpseclib3\Crypt\RSA\Formats\Keys; 26 27use phpseclib3\Common\Functions\Strings; 28use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor; 29use phpseclib3\File\ASN1; 30use phpseclib3\File\ASN1\Maps; 31use phpseclib3\Math\BigInteger; 32 33/** 34 * PKCS#1 Formatted RSA Key Handler 35 * 36 * @package RSA 37 * @author Jim Wigginton <terrafrost@php.net> 38 * @access public 39 */ 40abstract class PKCS1 extends Progenitor 41{ 42 /** 43 * Break a public or private key down into its constituent components 44 * 45 * @access public 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 * 110 * @access public 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 * 151 * @access public 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} 168