1<?php 2 3/** 4 * PuTTY Formatted RSA Key Handler 5 * 6 * PHP version 5 7 * 8 * @category Crypt 9 * @package RSA 10 * @author Jim Wigginton <terrafrost@php.net> 11 * @copyright 2015 Jim Wigginton 12 * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 * @link http://phpseclib.sourceforge.net 14 */ 15 16namespace phpseclib3\Crypt\RSA\Formats\Keys; 17 18use phpseclib3\Common\Functions\Strings; 19use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor; 20use phpseclib3\Math\BigInteger; 21 22/** 23 * PuTTY Formatted RSA Key Handler 24 * 25 * @package RSA 26 * @author Jim Wigginton <terrafrost@php.net> 27 * @access public 28 */ 29abstract class PuTTY extends Progenitor 30{ 31 /** 32 * Public Handler 33 * 34 * @var string 35 * @access private 36 */ 37 const PUBLIC_HANDLER = 'phpseclib3\Crypt\RSA\Formats\Keys\OpenSSH'; 38 39 /** 40 * Algorithm Identifier 41 * 42 * @var array 43 * @access private 44 */ 45 protected static $types = ['ssh-rsa']; 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 static $one; 58 if (!isset($one)) { 59 $one = new BigInteger(1); 60 } 61 62 $components = parent::load($key, $password); 63 if (!isset($components['private'])) { 64 return $components; 65 } 66 extract($components); 67 unset($components['public'], $components['private']); 68 69 $isPublicKey = false; 70 71 $result = Strings::unpackSSH2('ii', $public); 72 if ($result === false) { 73 throw new \UnexpectedValueException('Key appears to be malformed'); 74 } 75 list($publicExponent, $modulus) = $result; 76 77 $result = Strings::unpackSSH2('iiii', $private); 78 if ($result === false) { 79 throw new \UnexpectedValueException('Key appears to be malformed'); 80 } 81 $primes = $coefficients = []; 82 list($privateExponent, $primes[1], $primes[2], $coefficients[2]) = $result; 83 84 $temp = $primes[1]->subtract($one); 85 $exponents = [1 => $publicExponent->modInverse($temp)]; 86 $temp = $primes[2]->subtract($one); 87 $exponents[] = $publicExponent->modInverse($temp); 88 89 return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey'); 90 } 91 92 /** 93 * Convert a private key to the appropriate format. 94 * 95 * @access public 96 * @param \phpseclib3\Math\BigInteger $n 97 * @param \phpseclib3\Math\BigInteger $e 98 * @param \phpseclib3\Math\BigInteger $d 99 * @param array $primes 100 * @param array $exponents 101 * @param array $coefficients 102 * @param string $password optional 103 * @param array $options optional 104 * @return string 105 */ 106 public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) 107 { 108 if (count($primes) != 2) { 109 throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys'); 110 } 111 112 $public = Strings::packSSH2('ii', $e, $n); 113 $private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]); 114 115 return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password, $options); 116 } 117 118 /** 119 * Convert a public key to the appropriate format 120 * 121 * @access public 122 * @param \phpseclib3\Math\BigInteger $n 123 * @param \phpseclib3\Math\BigInteger $e 124 * @return string 125 */ 126 public static function savePublicKey(BigInteger $n, BigInteger $e) 127 { 128 return self::wrapPublicKey(Strings::packSSH2('ii', $e, $n), 'ssh-rsa'); 129 } 130} 131