1<?php 2 3/** 4 * PKCS#8 Formatted DH Key Handler 5 * 6 * PHP version 5 7 * 8 * Processes keys with the following headers: 9 * 10 * -----BEGIN ENCRYPTED PRIVATE KEY----- 11 * -----BEGIN PRIVATE KEY----- 12 * -----BEGIN PUBLIC KEY----- 13 * 14 * @category Crypt 15 * @package DH 16 * @author Jim Wigginton <terrafrost@php.net> 17 * @copyright 2015 Jim Wigginton 18 * @license http://www.opensource.org/licenses/mit-license.html MIT License 19 * @link http://phpseclib.sourceforge.net 20 */ 21 22namespace phpseclib3\Crypt\DH\Formats\Keys; 23 24use phpseclib3\Common\Functions\Strings; 25use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; 26use phpseclib3\File\ASN1; 27use phpseclib3\File\ASN1\Maps; 28use phpseclib3\Math\BigInteger; 29 30/** 31 * PKCS#8 Formatted DH Key Handler 32 * 33 * @package DH 34 * @author Jim Wigginton <terrafrost@php.net> 35 * @access public 36 */ 37abstract class PKCS8 extends Progenitor 38{ 39 /** 40 * OID Name 41 * 42 * @var string 43 * @access private 44 */ 45 const OID_NAME = 'dhKeyAgreement'; 46 47 /** 48 * OID Value 49 * 50 * @var string 51 * @access private 52 */ 53 const OID_VALUE = '1.2.840.113549.1.3.1'; 54 55 /** 56 * Child OIDs loaded 57 * 58 * @var bool 59 * @access private 60 */ 61 protected static $childOIDsLoaded = false; 62 63 /** 64 * Break a public or private key down into its constituent components 65 * 66 * @access public 67 * @param string $key 68 * @param string $password optional 69 * @return array 70 */ 71 public static function load($key, $password = '') 72 { 73 if (!Strings::is_stringable($key)) { 74 throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); 75 } 76 77 $isPublic = strpos($key, 'PUBLIC') !== false; 78 79 $key = parent::load($key, $password); 80 81 $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; 82 83 switch (true) { 84 case !$isPublic && $type == 'publicKey': 85 throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); 86 case $isPublic && $type == 'privateKey': 87 throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); 88 } 89 90 $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); 91 if (empty($decoded)) { 92 throw new \RuntimeException('Unable to decode BER of parameters'); 93 } 94 $components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP); 95 if (!is_array($components)) { 96 throw new \RuntimeException('Unable to perform ASN1 mapping on parameters'); 97 } 98 99 $decoded = ASN1::decodeBER($key[$type]); 100 switch (true) { 101 case empty($decoded): 102 case !is_array($decoded): 103 case !isset($decoded[0]['content']): 104 case !$decoded[0]['content'] instanceof BigInteger: 105 throw new \RuntimeException('Unable to decode BER of parameters'); 106 } 107 $components[$type] = $decoded[0]['content']; 108 109 return $components; 110 } 111 112 /** 113 * Convert a private key to the appropriate format. 114 * 115 * @access public 116 * @param \phpseclib3\Math\BigInteger $prime 117 * @param \phpseclib3\Math\BigInteger $base 118 * @param \phpseclib3\Math\BigInteger $privateKey 119 * @param \phpseclib3\Math\BigInteger $publicKey 120 * @param string $password optional 121 * @param array $options optional 122 * @return string 123 */ 124 public static function savePrivateKey(BigInteger $prime, BigInteger $base, BigInteger $privateKey, BigInteger $publicKey, $password = '', array $options = []) 125 { 126 $params = [ 127 'prime' => $prime, 128 'base' => $base 129 ]; 130 $params = ASN1::encodeDER($params, Maps\DHParameter::MAP); 131 $params = new ASN1\Element($params); 132 $key = ASN1::encodeDER($privateKey, ['type' => ASN1::TYPE_INTEGER]); 133 return self::wrapPrivateKey($key, [], $params, $password, null, '', $options); 134 } 135 136 /** 137 * Convert a public key to the appropriate format 138 * 139 * @access public 140 * @param \phpseclib3\Math\BigInteger $prime 141 * @param \phpseclib3\Math\BigInteger $base 142 * @param \phpseclib3\Math\BigInteger $publicKey 143 * @param array $options optional 144 * @return string 145 */ 146 public static function savePublicKey(BigInteger $prime, BigInteger $base, BigInteger $publicKey, array $options = []) 147 { 148 $params = [ 149 'prime' => $prime, 150 'base' => $base 151 ]; 152 $params = ASN1::encodeDER($params, Maps\DHParameter::MAP); 153 $params = new ASN1\Element($params); 154 $key = ASN1::encodeDER($publicKey, ['type' => ASN1::TYPE_INTEGER]); 155 return self::wrapPublicKey($key, $params); 156 } 157} 158