[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * OpenSSH Formatted EC Key Handler 5 * 6 * PHP version 5 7 * 8 * Place in $HOME/.ssh/authorized_keys 9 * 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 16 namespace phpseclib3\Crypt\EC\Formats\Keys; 17 18 use phpseclib3\Common\Functions\Strings; 19 use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor; 20 use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; 21 use phpseclib3\Crypt\EC\Curves\Ed25519; 22 use phpseclib3\Exception\UnsupportedCurveException; 23 use phpseclib3\Math\BigInteger; 24 25 /** 26 * OpenSSH Formatted EC Key Handler 27 * 28 * @author Jim Wigginton <terrafrost@php.net> 29 */ 30 abstract class OpenSSH extends Progenitor 31 { 32 use Common; 33 34 /** 35 * Supported Key Types 36 * 37 * @var array 38 */ 39 protected static $types = [ 40 'ecdsa-sha2-nistp256', 41 'ecdsa-sha2-nistp384', 42 'ecdsa-sha2-nistp521', 43 'ssh-ed25519' 44 ]; 45 46 /** 47 * Break a public or private key down into its constituent components 48 * 49 * @param string $key 50 * @param string $password optional 51 * @return array 52 */ 53 public static function load($key, $password = '') 54 { 55 $parsed = parent::load($key, $password); 56 57 if (isset($parsed['paddedKey'])) { 58 $paddedKey = $parsed['paddedKey']; 59 list($type) = Strings::unpackSSH2('s', $paddedKey); 60 if ($type != $parsed['type']) { 61 throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])"); 62 } 63 if ($type == 'ssh-ed25519') { 64 list(, $key, $comment) = Strings::unpackSSH2('sss', $paddedKey); 65 $key = libsodium::load($key); 66 $key['comment'] = $comment; 67 return $key; 68 } 69 list($curveName, $publicKey, $privateKey, $comment) = Strings::unpackSSH2('ssis', $paddedKey); 70 $curve = self::loadCurveByParam(['namedCurve' => $curveName]); 71 $curve->rangeCheck($privateKey); 72 return [ 73 'curve' => $curve, 74 'dA' => $privateKey, 75 'QA' => self::extractPoint("\0$publicKey", $curve), 76 'comment' => $comment 77 ]; 78 } 79 80 if ($parsed['type'] == 'ssh-ed25519') { 81 if (Strings::shift($parsed['publicKey'], 4) != "\0\0\0\x20") { 82 throw new \RuntimeException('Length of ssh-ed25519 key should be 32'); 83 } 84 85 $curve = new Ed25519(); 86 $qa = self::extractPoint($parsed['publicKey'], $curve); 87 } else { 88 list($curveName, $publicKey) = Strings::unpackSSH2('ss', $parsed['publicKey']); 89 $curveName = '\phpseclib3\Crypt\EC\Curves\\' . $curveName; 90 $curve = new $curveName(); 91 92 $qa = self::extractPoint("\0" . $publicKey, $curve); 93 } 94 95 return [ 96 'curve' => $curve, 97 'QA' => $qa, 98 'comment' => $parsed['comment'] 99 ]; 100 } 101 102 /** 103 * Returns the alias that corresponds to a curve 104 * 105 * @return string 106 */ 107 private static function getAlias(BaseCurve $curve) 108 { 109 self::initialize_static_variables(); 110 111 $reflect = new \ReflectionClass($curve); 112 $name = $reflect->getShortName(); 113 114 $oid = self::$curveOIDs[$name]; 115 $aliases = array_filter(self::$curveOIDs, function ($v) use ($oid) { 116 return $v == $oid; 117 }); 118 $aliases = array_keys($aliases); 119 120 for ($i = 0; $i < count($aliases); $i++) { 121 if (in_array('ecdsa-sha2-' . $aliases[$i], self::$types)) { 122 $alias = $aliases[$i]; 123 break; 124 } 125 } 126 127 if (!isset($alias)) { 128 throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports'); 129 } 130 131 return $alias; 132 } 133 134 /** 135 * Convert an EC public key to the appropriate format 136 * 137 * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve 138 * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey 139 * @param array $options optional 140 * @return string 141 */ 142 public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) 143 { 144 $comment = isset($options['comment']) ? $options['comment'] : self::$comment; 145 146 if ($curve instanceof Ed25519) { 147 $key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey)); 148 149 if (isset($options['binary']) ? $options['binary'] : self::$binary) { 150 return $key; 151 } 152 153 $key = 'ssh-ed25519 ' . base64_encode($key) . ' ' . $comment; 154 return $key; 155 } 156 157 $alias = self::getAlias($curve); 158 159 $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); 160 $key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points); 161 162 if (isset($options['binary']) ? $options['binary'] : self::$binary) { 163 return $key; 164 } 165 166 $key = 'ecdsa-sha2-' . $alias . ' ' . base64_encode($key) . ' ' . $comment; 167 168 return $key; 169 } 170 171 /** 172 * Convert a private key to the appropriate format. 173 * 174 * @param \phpseclib3\Math\BigInteger $privateKey 175 * @param \phpseclib3\Crypt\EC\Curves\Ed25519 $curve 176 * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey 177 * @param string $secret optional 178 * @param string $password optional 179 * @param array $options optional 180 * @return string 181 */ 182 public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = []) 183 { 184 if ($curve instanceof Ed25519) { 185 if (!isset($secret)) { 186 throw new \RuntimeException('Private Key does not have a secret set'); 187 } 188 if (strlen($secret) != 32) { 189 throw new \RuntimeException('Private Key secret is not of the correct length'); 190 } 191 192 $pubKey = $curve->encodePoint($publicKey); 193 194 $publicKey = Strings::packSSH2('ss', 'ssh-ed25519', $pubKey); 195 $privateKey = Strings::packSSH2('sss', 'ssh-ed25519', $pubKey, $secret . $pubKey); 196 197 return self::wrapPrivateKey($publicKey, $privateKey, $password, $options); 198 } 199 200 $alias = self::getAlias($curve); 201 202 $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); 203 $publicKey = self::savePublicKey($curve, $publicKey, ['binary' => true]); 204 205 $privateKey = Strings::packSSH2('sssi', 'ecdsa-sha2-' . $alias, $alias, $points, $privateKey); 206 207 return self::wrapPrivateKey($publicKey, $privateKey, $password, $options); 208 } 209 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body