[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * PKCS#8 Formatted EC 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 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 15 * is specific to private keys it's basically creating a DER-encoded wrapper 16 * for keys. This just extends that same concept to public keys (much like ssh-keygen) 17 * 18 * @author Jim Wigginton <terrafrost@php.net> 19 * @copyright 2015 Jim Wigginton 20 * @license http://www.opensource.org/licenses/mit-license.html MIT License 21 * @link http://phpseclib.sourceforge.net 22 */ 23 24 namespace phpseclib3\Crypt\EC\Formats\Keys; 25 26 use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; 27 use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; 28 use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; 29 use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; 30 use phpseclib3\Crypt\EC\Curves\Ed25519; 31 use phpseclib3\Crypt\EC\Curves\Ed448; 32 use phpseclib3\Exception\UnsupportedCurveException; 33 use phpseclib3\File\ASN1; 34 use phpseclib3\File\ASN1\Maps; 35 use phpseclib3\Math\BigInteger; 36 37 /** 38 * PKCS#8 Formatted EC Key Handler 39 * 40 * @author Jim Wigginton <terrafrost@php.net> 41 */ 42 abstract class PKCS8 extends Progenitor 43 { 44 use Common; 45 46 /** 47 * OID Name 48 * 49 * @var array 50 */ 51 const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448']; 52 53 /** 54 * OID Value 55 * 56 * @var string 57 */ 58 const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113']; 59 60 /** 61 * Break a public or private key down into its constituent components 62 * 63 * @param string $key 64 * @param string $password optional 65 * @return array 66 */ 67 public static function load($key, $password = '') 68 { 69 // initialize_static_variables() is defined in both the trait and the parent class 70 // when it's defined in two places it's the traits one that's called 71 // the parent one is needed, as well, but the parent one is called by other methods 72 // in the parent class as needed and in the context of the parent it's the parent 73 // one that's called 74 self::initialize_static_variables(); 75 76 $key = parent::load($key, $password); 77 78 $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; 79 80 switch ($key[$type . 'Algorithm']['algorithm']) { 81 case 'id-Ed25519': 82 case 'id-Ed448': 83 return self::loadEdDSA($key); 84 } 85 86 $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); 87 if (!$decoded) { 88 throw new \RuntimeException('Unable to decode BER'); 89 } 90 $params = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP); 91 if (!$params) { 92 throw new \RuntimeException('Unable to decode the parameters using Maps\ECParameters'); 93 } 94 95 $components = []; 96 $components['curve'] = self::loadCurveByParam($params); 97 98 if ($type == 'publicKey') { 99 $components['QA'] = self::extractPoint("\0" . $key['publicKey'], $components['curve']); 100 101 return $components; 102 } 103 104 $decoded = ASN1::decodeBER($key['privateKey']); 105 if (!$decoded) { 106 throw new \RuntimeException('Unable to decode BER'); 107 } 108 $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP); 109 if (isset($key['parameters']) && $params != $key['parameters']) { 110 throw new \RuntimeException('The PKCS8 parameter field does not match the private key parameter field'); 111 } 112 113 $components['dA'] = new BigInteger($key['privateKey'], 256); 114 $components['curve']->rangeCheck($components['dA']); 115 $components['QA'] = isset($key['publicKey']) ? 116 self::extractPoint($key['publicKey'], $components['curve']) : 117 $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']); 118 119 return $components; 120 } 121 122 /** 123 * Break a public or private EdDSA key down into its constituent components 124 * 125 * @return array 126 */ 127 private static function loadEdDSA(array $key) 128 { 129 $components = []; 130 131 if (isset($key['privateKey'])) { 132 $components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448(); 133 134 // 0x04 == octet string 135 // 0x20 == length (32 bytes) 136 if (substr($key['privateKey'], 0, 2) != "\x04\x20") { 137 throw new \RuntimeException('The first two bytes of the private key field should be 0x0420'); 138 } 139 $arr = $components['curve']->extractSecret(substr($key['privateKey'], 2)); 140 $components['dA'] = $arr['dA']; 141 $components['secret'] = $arr['secret']; 142 } 143 144 if (isset($key['publicKey'])) { 145 if (!isset($components['curve'])) { 146 $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448(); 147 } 148 149 $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']); 150 } 151 152 if (isset($key['privateKey']) && !isset($components['QA'])) { 153 $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']); 154 } 155 156 return $components; 157 } 158 159 /** 160 * Convert an EC public key to the appropriate format 161 * 162 * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve 163 * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey 164 * @param array $options optional 165 * @return string 166 */ 167 public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) 168 { 169 self::initialize_static_variables(); 170 171 if ($curve instanceof MontgomeryCurve) { 172 throw new UnsupportedCurveException('Montgomery Curves are not supported'); 173 } 174 175 if ($curve instanceof TwistedEdwardsCurve) { 176 return self::wrapPublicKey( 177 $curve->encodePoint($publicKey), 178 null, 179 $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448' 180 ); 181 } 182 183 $params = new ASN1\Element(self::encodeParameters($curve, false, $options)); 184 185 $key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); 186 187 return self::wrapPublicKey($key, $params, 'id-ecPublicKey'); 188 } 189 190 /** 191 * Convert a private key to the appropriate format. 192 * 193 * @param \phpseclib3\Math\BigInteger $privateKey 194 * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve 195 * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey 196 * @param string $secret optional 197 * @param string $password optional 198 * @param array $options optional 199 * @return string 200 */ 201 public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = []) 202 { 203 self::initialize_static_variables(); 204 205 if ($curve instanceof MontgomeryCurve) { 206 throw new UnsupportedCurveException('Montgomery Curves are not supported'); 207 } 208 209 if ($curve instanceof TwistedEdwardsCurve) { 210 return self::wrapPrivateKey( 211 "\x04\x20" . $secret, 212 [], 213 null, 214 $password, 215 $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448' 216 ); 217 } 218 219 $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); 220 221 $params = new ASN1\Element(self::encodeParameters($curve, false, $options)); 222 223 $key = [ 224 'version' => 'ecPrivkeyVer1', 225 'privateKey' => $privateKey->toBytes(), 226 //'parameters' => $params, 227 'publicKey' => "\0" . $publicKey 228 ]; 229 230 $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); 231 232 return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', '', $options); 233 } 234 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body