forked from GNUsocial/gnu-social
		
	
		
			
	
	
		
			210 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			210 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|   | <?php | ||
|  | /** | ||
|  |  * PKCS#8 Formatted RSA Key Handler
 | ||
|  |  * | ||
|  |  * PHP version 5 | ||
|  |  * | ||
|  |  * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) | ||
|  |  * | ||
|  |  * Has the following header: | ||
|  |  * | ||
|  |  * -----BEGIN PUBLIC KEY----- | ||
|  |  * | ||
|  |  * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 | ||
|  |  * is specific to private keys it's basically creating a DER-encoded wrapper | ||
|  |  * for keys. This just extends that same concept to public keys (much like ssh-keygen) | ||
|  |  * | ||
|  |  * @category  Crypt | ||
|  |  * @package   RSA | ||
|  |  * @author    Jim Wigginton <terrafrost@php.net> | ||
|  |  * @copyright 2015 Jim Wigginton | ||
|  |  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License | ||
|  |  * @link      http://phpseclib.sourceforge.net | ||
|  |  */ | ||
|  | 
 | ||
|  | namespace phpseclib\Crypt\RSA; | ||
|  | 
 | ||
|  | use ParagonIE\ConstantTime\Base64; | ||
|  | use phpseclib\Crypt\DES; | ||
|  | use phpseclib\Crypt\Random; | ||
|  | use phpseclib\Math\BigInteger; | ||
|  | 
 | ||
|  | /** | ||
|  |  * PKCS#8 Formatted RSA Key Handler
 | ||
|  |  * | ||
|  |  * @package RSA | ||
|  |  * @author  Jim Wigginton <terrafrost@php.net> | ||
|  |  * @access  public | ||
|  |  */ | ||
|  | class PKCS8 extends PKCS | ||
|  | { | ||
|  |     /** | ||
|  |      * Convert a private key to the appropriate format. | ||
|  |      * | ||
|  |      * @access public | ||
|  |      * @param \phpseclib\Math\BigInteger $n | ||
|  |      * @param \phpseclib\Math\BigInteger $e | ||
|  |      * @param \phpseclib\Math\BigInteger $d | ||
|  |      * @param array $primes | ||
|  |      * @param array $exponents | ||
|  |      * @param array $coefficients | ||
|  |      * @param string $password optional | ||
|  |      * @return string | ||
|  |      */ | ||
|  |     static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') | ||
|  |     { | ||
|  |         $num_primes = count($primes); | ||
|  |         $raw = array( | ||
|  |             'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
 | ||
|  |             'modulus' => $n->toBytes(true), | ||
|  |             'publicExponent' => $e->toBytes(true), | ||
|  |             'privateExponent' => $d->toBytes(true), | ||
|  |             'prime1' => $primes[1]->toBytes(true), | ||
|  |             'prime2' => $primes[2]->toBytes(true), | ||
|  |             'exponent1' => $exponents[1]->toBytes(true), | ||
|  |             'exponent2' => $exponents[2]->toBytes(true), | ||
|  |             'coefficient' => $coefficients[2]->toBytes(true) | ||
|  |         ); | ||
|  | 
 | ||
|  |         $components = array(); | ||
|  |         foreach ($raw as $name => $value) { | ||
|  |             $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value); | ||
|  |         } | ||
|  | 
 | ||
|  |         $RSAPrivateKey = implode('', $components); | ||
|  | 
 | ||
|  |         if ($num_primes > 2) { | ||
|  |             $OtherPrimeInfos = ''; | ||
|  |             for ($i = 3; $i <= $num_primes; $i++) { | ||
|  |                 // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
 | ||
|  |                 //
 | ||
|  |                 // OtherPrimeInfo ::= SEQUENCE {
 | ||
|  |                 //     prime             INTEGER,  -- ri
 | ||
|  |                 //     exponent          INTEGER,  -- di
 | ||
|  |                 //     coefficient       INTEGER   -- ti
 | ||
|  |                 // }
 | ||
|  |                 $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true)); | ||
|  |                 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true)); | ||
|  |                 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true)); | ||
|  |                 $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo); | ||
|  |             } | ||
|  |             $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos); | ||
|  |         } | ||
|  | 
 | ||
|  |         $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); | ||
|  | 
 | ||
|  |         $rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
 | ||
|  |         $RSAPrivateKey = pack( | ||
|  |             'Ca*a*Ca*a*', | ||
|  |             self::ASN1_INTEGER, | ||
|  |             "\01\00", | ||
|  |             $rsaOID, | ||
|  |             4, | ||
|  |             self::_encodeLength(strlen($RSAPrivateKey)), | ||
|  |             $RSAPrivateKey | ||
|  |         ); | ||
|  |         $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); | ||
|  |         if (!empty($password) || is_string($password)) { | ||
|  |             $salt = Random::string(8); | ||
|  |             $iterationCount = 2048; | ||
|  | 
 | ||
|  |             $crypto = new DES(DES::MODE_CBC); | ||
|  |             $crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount); | ||
|  |             $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); | ||
|  | 
 | ||
|  |             $parameters = pack( | ||
|  |                 'Ca*a*Ca*N', | ||
|  |                 self::ASN1_OCTETSTRING, | ||
|  |                 self::_encodeLength(strlen($salt)), | ||
|  |                 $salt, | ||
|  |                 self::ASN1_INTEGER, | ||
|  |                 self::_encodeLength(4), | ||
|  |                 $iterationCount | ||
|  |             ); | ||
|  |             $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; | ||
|  | 
 | ||
|  |             $encryptionAlgorithm = pack( | ||
|  |                 'Ca*a*Ca*a*', | ||
|  |                 self::ASN1_OBJECT, | ||
|  |                 self::_encodeLength(strlen($pbeWithMD5AndDES_CBC)), | ||
|  |                 $pbeWithMD5AndDES_CBC, | ||
|  |                 self::ASN1_SEQUENCE, | ||
|  |                 self::_encodeLength(strlen($parameters)), | ||
|  |                 $parameters | ||
|  |             ); | ||
|  | 
 | ||
|  |             $RSAPrivateKey = pack( | ||
|  |                 'Ca*a*Ca*a*', | ||
|  |                 self::ASN1_SEQUENCE, | ||
|  |                 self::_encodeLength(strlen($encryptionAlgorithm)), | ||
|  |                 $encryptionAlgorithm, | ||
|  |                 self::ASN1_OCTETSTRING, | ||
|  |                 self::_encodeLength(strlen($RSAPrivateKey)), | ||
|  |                 $RSAPrivateKey | ||
|  |             ); | ||
|  | 
 | ||
|  |             $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); | ||
|  | 
 | ||
|  |             $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . | ||
|  |                  chunk_split(Base64::encode($RSAPrivateKey), 64) . | ||
|  |                  '-----END ENCRYPTED PRIVATE KEY-----'; | ||
|  |         } else { | ||
|  |             $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" . | ||
|  |                  chunk_split(Base64::encode($RSAPrivateKey), 64) . | ||
|  |                  '-----END PRIVATE KEY-----'; | ||
|  |         } | ||
|  | 
 | ||
|  |         return $RSAPrivateKey; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Convert a public key to the appropriate format | ||
|  |      * | ||
|  |      * @access public | ||
|  |      * @param \phpseclib\Math\BigInteger $n | ||
|  |      * @param \phpseclib\Math\BigInteger $e | ||
|  |      * @return string | ||
|  |      */ | ||
|  |     static function savePublicKey(BigInteger $n, BigInteger $e) | ||
|  |     { | ||
|  |         $modulus = $n->toBytes(true); | ||
|  |         $publicExponent = $e->toBytes(true); | ||
|  | 
 | ||
|  |         // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
 | ||
|  |         // RSAPublicKey ::= SEQUENCE {
 | ||
|  |         //     modulus           INTEGER,  -- n
 | ||
|  |         //     publicExponent    INTEGER   -- e
 | ||
|  |         // }
 | ||
|  |         $components = array( | ||
|  |             'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus), | ||
|  |             'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent) | ||
|  |         ); | ||
|  | 
 | ||
|  |         $RSAPublicKey = pack( | ||
|  |             'Ca*a*a*', | ||
|  |             self::ASN1_SEQUENCE, | ||
|  |             self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), | ||
|  |             $components['modulus'], | ||
|  |             $components['publicExponent'] | ||
|  |         ); | ||
|  | 
 | ||
|  |         // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
 | ||
|  |         $rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
 | ||
|  |         $RSAPublicKey = chr(0) . $RSAPublicKey; | ||
|  |         $RSAPublicKey = chr(3) . self::_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey; | ||
|  | 
 | ||
|  |         $RSAPublicKey = pack( | ||
|  |             'Ca*a*', | ||
|  |             self::ASN1_SEQUENCE, | ||
|  |             self::_encodeLength(strlen($rsaOID . $RSAPublicKey)), | ||
|  |             $rsaOID . $RSAPublicKey | ||
|  |         ); | ||
|  | 
 | ||
|  |         $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . | ||
|  |                         chunk_split(Base64::encode($RSAPublicKey), 64) . | ||
|  |                         '-----END PUBLIC KEY-----'; | ||
|  | 
 | ||
|  |         return $RSAPublicKey; | ||
|  |     } | ||
|  | } |