[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Miccrosoft BLOB Formatted RSA Key Handler 5 * 6 * More info: 7 * 8 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx 9 * 10 * PHP version 5 11 * 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 18 namespace phpseclib3\Crypt\RSA\Formats\Keys; 19 20 use phpseclib3\Common\Functions\Strings; 21 use phpseclib3\Exception\UnsupportedFormatException; 22 use phpseclib3\Math\BigInteger; 23 24 /** 25 * Microsoft BLOB Formatted RSA Key Handler 26 * 27 * @author Jim Wigginton <terrafrost@php.net> 28 */ 29 abstract class MSBLOB 30 { 31 /** 32 * Public/Private Key Pair 33 * 34 */ 35 const PRIVATEKEYBLOB = 0x7; 36 /** 37 * Public Key 38 * 39 */ 40 const PUBLICKEYBLOB = 0x6; 41 /** 42 * Public Key 43 * 44 */ 45 const PUBLICKEYBLOBEX = 0xA; 46 /** 47 * RSA public key exchange algorithm 48 * 49 */ 50 const CALG_RSA_KEYX = 0x0000A400; 51 /** 52 * RSA public key exchange algorithm 53 * 54 */ 55 const CALG_RSA_SIGN = 0x00002400; 56 /** 57 * Public Key 58 * 59 */ 60 const RSA1 = 0x31415352; 61 /** 62 * Private Key 63 * 64 */ 65 const RSA2 = 0x32415352; 66 67 /** 68 * Break a public or private key down into its constituent components 69 * 70 * @param string $key 71 * @param string $password optional 72 * @return array 73 */ 74 public static function load($key, $password = '') 75 { 76 if (!Strings::is_stringable($key)) { 77 throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); 78 } 79 80 $key = Strings::base64_decode($key); 81 82 if (!is_string($key)) { 83 throw new \UnexpectedValueException('Base64 decoding produced an error'); 84 } 85 if (strlen($key) < 20) { 86 throw new \UnexpectedValueException('Key appears to be malformed'); 87 } 88 89 // PUBLICKEYSTRUC publickeystruc 90 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx 91 extract(unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8))); 92 /** 93 * @var string $type 94 * @var string $version 95 * @var integer $reserved 96 * @var integer $algo 97 */ 98 switch (ord($type)) { 99 case self::PUBLICKEYBLOB: 100 case self::PUBLICKEYBLOBEX: 101 $publickey = true; 102 break; 103 case self::PRIVATEKEYBLOB: 104 $publickey = false; 105 break; 106 default: 107 throw new \UnexpectedValueException('Key appears to be malformed'); 108 } 109 110 $components = ['isPublicKey' => $publickey]; 111 112 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx 113 switch ($algo) { 114 case self::CALG_RSA_KEYX: 115 case self::CALG_RSA_SIGN: 116 break; 117 default: 118 throw new \UnexpectedValueException('Key appears to be malformed'); 119 } 120 121 // RSAPUBKEY rsapubkey 122 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx 123 // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit 124 extract(unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12))); 125 /** 126 * @var integer $magic 127 * @var integer $bitlen 128 * @var string $pubexp 129 */ 130 switch ($magic) { 131 case self::RSA2: 132 $components['isPublicKey'] = false; 133 // fall-through 134 case self::RSA1: 135 break; 136 default: 137 throw new \UnexpectedValueException('Key appears to be malformed'); 138 } 139 140 $baseLength = $bitlen / 16; 141 if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) { 142 throw new \UnexpectedValueException('Key appears to be malformed'); 143 } 144 145 $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256); 146 // BYTE modulus[rsapubkey.bitlen/8] 147 $components['modulus'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256); 148 149 if ($publickey) { 150 return $components; 151 } 152 153 $components['isPublicKey'] = false; 154 155 // BYTE prime1[rsapubkey.bitlen/16] 156 $components['primes'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; 157 // BYTE prime2[rsapubkey.bitlen/16] 158 $components['primes'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256); 159 // BYTE exponent1[rsapubkey.bitlen/16] 160 $components['exponents'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; 161 // BYTE exponent2[rsapubkey.bitlen/16] 162 $components['exponents'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256); 163 // BYTE coefficient[rsapubkey.bitlen/16] 164 $components['coefficients'] = [2 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; 165 if (isset($components['privateExponent'])) { 166 $components['publicExponent'] = $components['privateExponent']; 167 } 168 // BYTE privateExponent[rsapubkey.bitlen/8] 169 $components['privateExponent'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256); 170 171 return $components; 172 } 173 174 /** 175 * Convert a private key to the appropriate format. 176 * 177 * @param \phpseclib3\Math\BigInteger $n 178 * @param \phpseclib3\Math\BigInteger $e 179 * @param \phpseclib3\Math\BigInteger $d 180 * @param array $primes 181 * @param array $exponents 182 * @param array $coefficients 183 * @param string $password optional 184 * @return string 185 */ 186 public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '') 187 { 188 if (count($primes) != 2) { 189 throw new \InvalidArgumentException('MSBLOB does not support multi-prime RSA keys'); 190 } 191 192 if (!empty($password) && is_string($password)) { 193 throw new UnsupportedFormatException('MSBLOB private keys do not support encryption'); 194 } 195 196 $n = strrev($n->toBytes()); 197 $e = str_pad(strrev($e->toBytes()), 4, "\0"); 198 $key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX); 199 $key .= pack('VVa*', self::RSA2, 8 * strlen($n), $e); 200 $key .= $n; 201 $key .= strrev($primes[1]->toBytes()); 202 $key .= strrev($primes[2]->toBytes()); 203 $key .= strrev($exponents[1]->toBytes()); 204 $key .= strrev($exponents[2]->toBytes()); 205 $key .= strrev($coefficients[2]->toBytes()); 206 $key .= strrev($d->toBytes()); 207 208 return Strings::base64_encode($key); 209 } 210 211 /** 212 * Convert a public key to the appropriate format 213 * 214 * @param \phpseclib3\Math\BigInteger $n 215 * @param \phpseclib3\Math\BigInteger $e 216 * @return string 217 */ 218 public static function savePublicKey(BigInteger $n, BigInteger $e) 219 { 220 $n = strrev($n->toBytes()); 221 $e = str_pad(strrev($e->toBytes()), 4, "\0"); 222 $key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX); 223 $key .= pack('VVa*', self::RSA1, 8 * strlen($n), $e); 224 $key .= $n; 225 226 return Strings::base64_encode($key); 227 } 228 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body