PKCS1.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /**
  3. * PKCS#1 Formatted RSA Key Handler
  4. *
  5. * PHP version 5
  6. *
  7. * Used by File/X509.php
  8. *
  9. * Has the following header:
  10. *
  11. * -----BEGIN RSA PUBLIC KEY-----
  12. *
  13. * Analogous to ssh-keygen's pem format (as specified by -m)
  14. *
  15. * @category Crypt
  16. * @package RSA
  17. * @author Jim Wigginton <terrafrost@php.net>
  18. * @copyright 2015 Jim Wigginton
  19. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  20. * @link http://phpseclib.sourceforge.net
  21. */
  22. namespace phpseclib\Crypt\RSA;
  23. use ParagonIE\ConstantTime\Base64;
  24. use ParagonIE\ConstantTime\Hex;
  25. use phpseclib\Crypt\AES;
  26. use phpseclib\Crypt\DES;
  27. use phpseclib\Crypt\Random;
  28. use phpseclib\Crypt\TripleDES;
  29. use phpseclib\Math\BigInteger;
  30. /**
  31. * PKCS#1 Formatted RSA Key Handler
  32. *
  33. * @package RSA
  34. * @author Jim Wigginton <terrafrost@php.net>
  35. * @access public
  36. */
  37. class PKCS1 extends PKCS
  38. {
  39. /**
  40. * Default encryption algorithm
  41. *
  42. * @var string
  43. * @access private
  44. */
  45. static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
  46. /**
  47. * Sets the default encryption algorithm
  48. *
  49. * @access public
  50. * @param string $algo
  51. */
  52. static function setEncryptionAlgorithm($algo)
  53. {
  54. self::$defaultEncryptionAlgorithm = $algo;
  55. }
  56. /**
  57. * Convert a private key to the appropriate format.
  58. *
  59. * @access public
  60. * @param \phpseclib\Math\BigInteger $n
  61. * @param \phpseclib\Math\BigInteger $e
  62. * @param \phpseclib\Math\BigInteger $d
  63. * @param array $primes
  64. * @param array $exponents
  65. * @param array $coefficients
  66. * @param string $password optional
  67. * @return string
  68. */
  69. static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
  70. {
  71. $num_primes = count($primes);
  72. $raw = array(
  73. 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
  74. 'modulus' => $n->toBytes(true),
  75. 'publicExponent' => $e->toBytes(true),
  76. 'privateExponent' => $d->toBytes(true),
  77. 'prime1' => $primes[1]->toBytes(true),
  78. 'prime2' => $primes[2]->toBytes(true),
  79. 'exponent1' => $exponents[1]->toBytes(true),
  80. 'exponent2' => $exponents[2]->toBytes(true),
  81. 'coefficient' => $coefficients[2]->toBytes(true)
  82. );
  83. $components = array();
  84. foreach ($raw as $name => $value) {
  85. $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
  86. }
  87. $RSAPrivateKey = implode('', $components);
  88. if ($num_primes > 2) {
  89. $OtherPrimeInfos = '';
  90. for ($i = 3; $i <= $num_primes; $i++) {
  91. // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
  92. //
  93. // OtherPrimeInfo ::= SEQUENCE {
  94. // prime INTEGER, -- ri
  95. // exponent INTEGER, -- di
  96. // coefficient INTEGER -- ti
  97. // }
  98. $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
  99. $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
  100. $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
  101. $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
  102. }
  103. $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
  104. }
  105. $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
  106. if (!empty($password) || is_string($password)) {
  107. $cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
  108. $iv = Random::string($cipher->getBlockLength() >> 3);
  109. $cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
  110. $cipher->setIV($iv);
  111. $iv = strtoupper(Hex::encode($iv));
  112. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  113. "Proc-Type: 4,ENCRYPTED\r\n" .
  114. "DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
  115. "\r\n" .
  116. chunk_split(Base64::encode($cipher->encrypt($RSAPrivateKey)), 64) .
  117. '-----END RSA PRIVATE KEY-----';
  118. } else {
  119. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  120. chunk_split(Base64::encode($RSAPrivateKey), 64) .
  121. '-----END RSA PRIVATE KEY-----';
  122. }
  123. return $RSAPrivateKey;
  124. }
  125. /**
  126. * Convert a public key to the appropriate format
  127. *
  128. * @access public
  129. * @param \phpseclib\Math\BigInteger $n
  130. * @param \phpseclib\Math\BigInteger $e
  131. * @return string
  132. */
  133. static function savePublicKey(BigInteger $n, BigInteger $e)
  134. {
  135. $modulus = $n->toBytes(true);
  136. $publicExponent = $e->toBytes(true);
  137. // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
  138. // RSAPublicKey ::= SEQUENCE {
  139. // modulus INTEGER, -- n
  140. // publicExponent INTEGER -- e
  141. // }
  142. $components = array(
  143. 'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
  144. 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
  145. );
  146. $RSAPublicKey = pack(
  147. 'Ca*a*a*',
  148. self::ASN1_SEQUENCE,
  149. self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
  150. $components['modulus'],
  151. $components['publicExponent']
  152. );
  153. $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
  154. chunk_split(Base64::encode($RSAPublicKey), 64) .
  155. '-----END RSA PUBLIC KEY-----';
  156. return $RSAPublicKey;
  157. }
  158. }