1<?php 2 3/** 4 * OpenSSH Formatted DSA Key Handler 5 * 6 * PHP version 5 7 * 8 * Place in $HOME/.ssh/authorized_keys 9 * 10 * @category Crypt 11 * @package DSA 12 * @author Jim Wigginton <terrafrost@php.net> 13 * @copyright 2015 Jim Wigginton 14 * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 * @link http://phpseclib.sourceforge.net 16 */ 17 18namespace phpseclib3\Crypt\DSA\Formats\Keys; 19 20use phpseclib3\Common\Functions\Strings; 21use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor; 22use phpseclib3\Math\BigInteger; 23 24/** 25 * OpenSSH Formatted DSA Key Handler 26 * 27 * @package DSA 28 * @author Jim Wigginton <terrafrost@php.net> 29 * @access public 30 */ 31abstract class OpenSSH extends Progenitor 32{ 33 /** 34 * Supported Key Types 35 * 36 * @var array 37 */ 38 protected static $types = ['ssh-dss']; 39 40 /** 41 * Break a public or private key down into its constituent components 42 * 43 * @access public 44 * @param string $key 45 * @param string $password optional 46 * @return array 47 */ 48 public static function load($key, $password = '') 49 { 50 $parsed = parent::load($key, $password); 51 52 if (isset($parsed['paddedKey'])) { 53 list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']); 54 if ($type != $parsed['type']) { 55 throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])"); 56 } 57 58 list($p, $q, $g, $y, $x, $comment) = Strings::unpackSSH2('i5s', $parsed['paddedKey']); 59 60 return compact('p', 'q', 'g', 'y', 'x', 'comment'); 61 } 62 63 list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $parsed['publicKey']); 64 65 $comment = $parsed['comment']; 66 67 return compact('p', 'q', 'g', 'y', 'comment'); 68 } 69 70 /** 71 * Convert a public key to the appropriate format 72 * 73 * @access public 74 * @param \phpseclib3\Math\BigInteger $p 75 * @param \phpseclib3\Math\BigInteger $q 76 * @param \phpseclib3\Math\BigInteger $g 77 * @param \phpseclib3\Math\BigInteger $y 78 * @param array $options optional 79 * @return string 80 */ 81 public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = []) 82 { 83 if ($q->getLength() != 160) { 84 throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); 85 } 86 87 // from <http://tools.ietf.org/html/rfc4253#page-15>: 88 // string "ssh-dss" 89 // mpint p 90 // mpint q 91 // mpint g 92 // mpint y 93 $DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y); 94 95 if (isset($options['binary']) ? $options['binary'] : self::$binary) { 96 return $DSAPublicKey; 97 } 98 99 $comment = isset($options['comment']) ? $options['comment'] : self::$comment; 100 $DSAPublicKey = 'ssh-dss ' . base64_encode($DSAPublicKey) . ' ' . $comment; 101 102 return $DSAPublicKey; 103 } 104 105 /** 106 * Convert a private key to the appropriate format. 107 * 108 * @access public 109 * @param \phpseclib3\Math\BigInteger $p 110 * @param \phpseclib3\Math\BigInteger $q 111 * @param \phpseclib3\Math\BigInteger $g 112 * @param \phpseclib3\Math\BigInteger $y 113 * @param \phpseclib3\Math\BigInteger $x 114 * @param string $password optional 115 * @param array $options optional 116 * @return string 117 */ 118 public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = []) 119 { 120 $publicKey = self::savePublicKey($p, $q, $g, $y, ['binary' => true]); 121 $privateKey = Strings::packSSH2('si5', 'ssh-dss', $p, $q, $g, $y, $x); 122 123 return self::wrapPrivateKey($publicKey, $privateKey, $password, $options); 124 } 125} 126