Guest User

Untitled

a guest
Sep 4th, 2013
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 92.23 KB | None | 0 0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5. * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * Here's an example of how to encrypt and decrypt text with this library:
  10. * <code>
  11. * <?php
  12. * include('Crypt/RSA.php');
  13. *
  14. * $rsa = new Crypt_RSA();
  15. * extract($rsa->createKey());
  16. *
  17. * $plaintext = 'terrafrost';
  18. *
  19. * $rsa->loadKey($privatekey);
  20. * $ciphertext = $rsa->encrypt($plaintext);
  21. *
  22. * $rsa->loadKey($publickey);
  23. * echo $rsa->decrypt($ciphertext);
  24. * ?>
  25. * </code>
  26. *
  27. * Here's an example of how to create signatures and verify signatures with this library:
  28. * <code>
  29. * <?php
  30. * include('Crypt/RSA.php');
  31. *
  32. * $rsa = new Crypt_RSA();
  33. * extract($rsa->createKey());
  34. *
  35. * $plaintext = 'terrafrost';
  36. *
  37. * $rsa->loadKey($privatekey);
  38. * $signature = $rsa->sign($plaintext);
  39. *
  40. * $rsa->loadKey($publickey);
  41. * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
  42. * ?>
  43. * </code>
  44. *
  45. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  46. * of this software and associated documentation files (the "Software"), to deal
  47. * in the Software without restriction, including without limitation the rights
  48. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  49. * copies of the Software, and to permit persons to whom the Software is
  50. * furnished to do so, subject to the following conditions:
  51. *
  52. * The above copyright notice and this permission notice shall be included in
  53. * all copies or substantial portions of the Software.
  54. *
  55. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  56. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  57. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  58. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  59. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  60. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  61. * THE SOFTWARE.
  62. *
  63. * @category Crypt
  64. * @package Crypt_RSA
  65. * @author Jim Wigginton <terrafrost@php.net>
  66. * @copyright MMIX Jim Wigginton
  67. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  68. * @link http://phpseclib.sourceforge.net
  69. */
  70.  
  71. /**
  72. * Include Crypt_Random
  73. */
  74. // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
  75. // will trigger a call to __autoload() if you're wanting to auto-load classes
  76. // call function_exists() a second time to stop the require_once from being called outside
  77. // of the auto loader
  78. if (!function_exists('crypt_random_string')) {
  79. require_once('Random.php');
  80. }
  81.  
  82. /**
  83. * Include Crypt_Hash
  84. */
  85. if (!class_exists('Crypt_Hash')) {
  86. require_once('Hash.php');
  87. }
  88.  
  89. /**#@+
  90. * @access public
  91. * @see Crypt_RSA::encrypt()
  92. * @see Crypt_RSA::decrypt()
  93. */
  94. /**
  95. * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
  96. * (OAEP) for encryption / decryption.
  97. *
  98. * Uses sha1 by default.
  99. *
  100. * @see Crypt_RSA::setHash()
  101. * @see Crypt_RSA::setMGFHash()
  102. */
  103. define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
  104. /**
  105. * Use PKCS#1 padding.
  106. *
  107. * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
  108. * compatability with protocols (like SSH-1) written before OAEP's introduction.
  109. */
  110. define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
  111. /**#@-*/
  112.  
  113. /**#@+
  114. * @access public
  115. * @see Crypt_RSA::sign()
  116. * @see Crypt_RSA::verify()
  117. * @see Crypt_RSA::setHash()
  118. */
  119. /**
  120. * Use the Probabilistic Signature Scheme for signing
  121. *
  122. * Uses sha1 by default.
  123. *
  124. * @see Crypt_RSA::setSaltLength()
  125. * @see Crypt_RSA::setMGFHash()
  126. */
  127. define('CRYPT_RSA_SIGNATURE_PSS', 1);
  128. /**
  129. * Use the PKCS#1 scheme by default.
  130. *
  131. * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
  132. * compatability with protocols (like SSH-2) written before PSS's introduction.
  133. */
  134. define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
  135. /**#@-*/
  136.  
  137. /**#@+
  138. * @access private
  139. * @see Crypt_RSA::createKey()
  140. */
  141. /**
  142. * ASN1 Integer
  143. */
  144. define('CRYPT_RSA_ASN1_INTEGER', 2);
  145. /**
  146. * ASN1 Bit String
  147. */
  148. define('CRYPT_RSA_ASN1_BITSTRING', 3);
  149. /**
  150. * ASN1 Sequence (with the constucted bit set)
  151. */
  152. define('CRYPT_RSA_ASN1_SEQUENCE', 48);
  153. /**#@-*/
  154.  
  155. /**#@+
  156. * @access private
  157. * @see Crypt_RSA::Crypt_RSA()
  158. */
  159. /**
  160. * To use the pure-PHP implementation
  161. */
  162. define('CRYPT_RSA_MODE_INTERNAL', 1);
  163. /**
  164. * To use the OpenSSL library
  165. *
  166. * (if enabled; otherwise, the internal implementation will be used)
  167. */
  168. define('CRYPT_RSA_MODE_OPENSSL', 2);
  169. /**#@-*/
  170.  
  171. /**
  172. * Default openSSL configuration file.
  173. */
  174. define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
  175.  
  176.  
  177. /**#@+
  178. * @access public
  179. * @see Crypt_RSA::createKey()
  180. * @see Crypt_RSA::setPrivateKeyFormat()
  181. */
  182. /**
  183. * PKCS#1 formatted private key
  184. *
  185. * Used by OpenSSH
  186. */
  187. define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
  188. /**
  189. * PuTTY formatted private key
  190. */
  191. define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
  192. /**
  193. * XML formatted private key
  194. */
  195. define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
  196. /**#@-*/
  197.  
  198. /**#@+
  199. * @access public
  200. * @see Crypt_RSA::createKey()
  201. * @see Crypt_RSA::setPublicKeyFormat()
  202. */
  203. /**
  204. * Raw public key
  205. *
  206. * An array containing two Math_BigInteger objects.
  207. *
  208. * The exponent can be indexed with any of the following:
  209. *
  210. * 0, e, exponent, publicExponent
  211. *
  212. * The modulus can be indexed with any of the following:
  213. *
  214. * 1, n, modulo, modulus
  215. */
  216. define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
  217. /**
  218. * PKCS#1 formatted public key (raw)
  219. *
  220. * Used by File/X509.php
  221. */
  222. define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
  223. /**
  224. * XML formatted public key
  225. */
  226. define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
  227. /**
  228. * OpenSSH formatted public key
  229. *
  230. * Place in $HOME/.ssh/authorized_keys
  231. */
  232. define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
  233. /**
  234. * PKCS#1 formatted public key (encapsulated)
  235. *
  236. * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
  237. */
  238. define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
  239. /**#@-*/
  240.  
  241. /**
  242. * Pure-PHP PKCS#1 compliant implementation of RSA.
  243. *
  244. * @author Jim Wigginton <terrafrost@php.net>
  245. * @version 0.1.0
  246. * @access public
  247. * @package Crypt_RSA
  248. */
  249. class Crypt_RSA {
  250. /**
  251. * Precomputed Zero
  252. *
  253. * @var Array
  254. * @access private
  255. */
  256. var $zero;
  257.  
  258. /**
  259. * Precomputed One
  260. *
  261. * @var Array
  262. * @access private
  263. */
  264. var $one;
  265.  
  266. /**
  267. * Private Key Format
  268. *
  269. * @var Integer
  270. * @access private
  271. */
  272. var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
  273.  
  274. /**
  275. * Public Key Format
  276. *
  277. * @var Integer
  278. * @access public
  279. */
  280. var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
  281.  
  282. /**
  283. * Modulus (ie. n)
  284. *
  285. * @var Math_BigInteger
  286. * @access private
  287. */
  288. var $modulus;
  289.  
  290. /**
  291. * Modulus length
  292. *
  293. * @var Math_BigInteger
  294. * @access private
  295. */
  296. var $k;
  297.  
  298. /**
  299. * Exponent (ie. e or d)
  300. *
  301. * @var Math_BigInteger
  302. * @access private
  303. */
  304. var $exponent;
  305.  
  306. /**
  307. * Primes for Chinese Remainder Theorem (ie. p and q)
  308. *
  309. * @var Array
  310. * @access private
  311. */
  312. var $primes;
  313.  
  314. /**
  315. * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
  316. *
  317. * @var Array
  318. * @access private
  319. */
  320. var $exponents;
  321.  
  322. /**
  323. * Coefficients for Chinese Remainder Theorem (ie. qInv)
  324. *
  325. * @var Array
  326. * @access private
  327. */
  328. var $coefficients;
  329.  
  330. /**
  331. * Hash name
  332. *
  333. * @var String
  334. * @access private
  335. */
  336. var $hashName;
  337.  
  338. /**
  339. * Hash function
  340. *
  341. * @var Crypt_Hash
  342. * @access private
  343. */
  344. var $hash;
  345.  
  346. /**
  347. * Length of hash function output
  348. *
  349. * @var Integer
  350. * @access private
  351. */
  352. var $hLen;
  353.  
  354. /**
  355. * Length of salt
  356. *
  357. * @var Integer
  358. * @access private
  359. */
  360. var $sLen;
  361.  
  362. /**
  363. * Hash function for the Mask Generation Function
  364. *
  365. * @var Crypt_Hash
  366. * @access private
  367. */
  368. var $mgfHash;
  369.  
  370. /**
  371. * Length of MGF hash function output
  372. *
  373. * @var Integer
  374. * @access private
  375. */
  376. var $mgfHLen;
  377.  
  378. /**
  379. * Encryption mode
  380. *
  381. * @var Integer
  382. * @access private
  383. */
  384. var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
  385.  
  386. /**
  387. * Signature mode
  388. *
  389. * @var Integer
  390. * @access private
  391. */
  392. var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
  393.  
  394. /**
  395. * Public Exponent
  396. *
  397. * @var Mixed
  398. * @access private
  399. */
  400. var $publicExponent = false;
  401.  
  402. /**
  403. * Password
  404. *
  405. * @var String
  406. * @access private
  407. */
  408. var $password = false;
  409.  
  410. /**
  411. * Components
  412. *
  413. * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
  414. * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
  415. *
  416. * @see Crypt_RSA::_start_element_handler()
  417. * @var Array
  418. * @access private
  419. */
  420. var $components = array();
  421.  
  422. /**
  423. * Current String
  424. *
  425. * For use with parsing XML formatted keys.
  426. *
  427. * @see Crypt_RSA::_character_handler()
  428. * @see Crypt_RSA::_stop_element_handler()
  429. * @var Mixed
  430. * @access private
  431. */
  432. var $current;
  433.  
  434. /**
  435. * OpenSSL configuration file name.
  436. *
  437. * Set to NULL to use system configuration file.
  438. * @see Crypt_RSA::createKey()
  439. * @var Mixed
  440. * @Access public
  441. */
  442. var $configFile;
  443.  
  444. /**
  445. * Public key comment field.
  446. *
  447. * @var String
  448. * @access private
  449. */
  450. var $comment = 'phpseclib-generated-key';
  451.  
  452. /**
  453. * The constructor
  454. *
  455. * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
  456. * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
  457. * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
  458. *
  459. * @return Crypt_RSA
  460. * @access public
  461. */
  462. function Crypt_RSA()
  463. {
  464. if (!class_exists('Math_BigInteger')) {
  465. require_once('Math/BigInteger.php');
  466. }
  467.  
  468. $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
  469.  
  470. if ( !defined('CRYPT_RSA_MODE') ) {
  471. switch (true) {
  472. case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
  473. define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
  474. break;
  475. default:
  476. define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
  477. }
  478. }
  479.  
  480. $this->zero = new Math_BigInteger();
  481. $this->one = new Math_BigInteger(1);
  482.  
  483. $this->hash = new Crypt_Hash('sha1');
  484. $this->hLen = $this->hash->getLength();
  485. $this->hashName = 'sha1';
  486. $this->mgfHash = new Crypt_Hash('sha1');
  487. $this->mgfHLen = $this->mgfHash->getLength();
  488. }
  489.  
  490. /**
  491. * Create public / private key pair
  492. *
  493. * Returns an array with the following three elements:
  494. * - 'privatekey': The private key.
  495. * - 'publickey': The public key.
  496. * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
  497. * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
  498. *
  499. * @access public
  500. * @param optional Integer $bits
  501. * @param optional Integer $timeout
  502. * @param optional Math_BigInteger $p
  503. */
  504. function createKey($bits = 1024, $timeout = false, $partial = array())
  505. {
  506. if (!defined('CRYPT_RSA_EXPONENT')) {
  507. // http://en.wikipedia.org/wiki/65537_%28number%29
  508. define('CRYPT_RSA_EXPONENT', '65537');
  509. }
  510. // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
  511. // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
  512. // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
  513. // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
  514. // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
  515. // generation when there's a chance neither gmp nor OpenSSL are installed)
  516. if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
  517. define('CRYPT_RSA_SMALLEST_PRIME', 4096);
  518. }
  519.  
  520. // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
  521. if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
  522. $config = array();
  523. if (isset($this->configFile)) {
  524. $config['config'] = $this->configFile;
  525. }
  526. $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
  527. openssl_pkey_export($rsa, $privatekey, NULL, $config);
  528. $publickey = openssl_pkey_get_details($rsa);
  529. $publickey = $publickey['key'];
  530.  
  531. $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
  532. $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
  533.  
  534. // clear the buffer of error strings stemming from a minimalistic openssl.cnf
  535. while (openssl_error_string() !== false);
  536.  
  537. return array(
  538. 'privatekey' => $privatekey,
  539. 'publickey' => $publickey,
  540. 'partialkey' => false
  541. );
  542. }
  543.  
  544. static $e;
  545. if (!isset($e)) {
  546. $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
  547. }
  548.  
  549. extract($this->_generateMinMax($bits));
  550. $absoluteMin = $min;
  551. $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
  552. if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
  553. $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
  554. $temp = CRYPT_RSA_SMALLEST_PRIME;
  555. } else {
  556. $num_primes = 2;
  557. }
  558. extract($this->_generateMinMax($temp + $bits % $temp));
  559. $finalMax = $max;
  560. extract($this->_generateMinMax($temp));
  561.  
  562. $generator = new Math_BigInteger();
  563.  
  564. $n = $this->one->copy();
  565. if (!empty($partial)) {
  566. extract(unserialize($partial));
  567. } else {
  568. $exponents = $coefficients = $primes = array();
  569. $lcm = array(
  570. 'top' => $this->one->copy(),
  571. 'bottom' => false
  572. );
  573. }
  574.  
  575. $start = time();
  576. $i0 = count($primes) + 1;
  577.  
  578. do {
  579. for ($i = $i0; $i <= $num_primes; $i++) {
  580. if ($timeout !== false) {
  581. $timeout-= time() - $start;
  582. $start = time();
  583. if ($timeout <= 0) {
  584. return array(
  585. 'privatekey' => '',
  586. 'publickey' => '',
  587. 'partialkey' => serialize(array(
  588. 'primes' => $primes,
  589. 'coefficients' => $coefficients,
  590. 'lcm' => $lcm,
  591. 'exponents' => $exponents
  592. ))
  593. );
  594. }
  595. }
  596.  
  597. if ($i == $num_primes) {
  598. list($min, $temp) = $absoluteMin->divide($n);
  599. if (!$temp->equals($this->zero)) {
  600. $min = $min->add($this->one); // ie. ceil()
  601. }
  602. $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
  603. } else {
  604. $primes[$i] = $generator->randomPrime($min, $max, $timeout);
  605. }
  606.  
  607. if ($primes[$i] === false) { // if we've reached the timeout
  608. if (count($primes) > 1) {
  609. $partialkey = '';
  610. } else {
  611. array_pop($primes);
  612. $partialkey = serialize(array(
  613. 'primes' => $primes,
  614. 'coefficients' => $coefficients,
  615. 'lcm' => $lcm,
  616. 'exponents' => $exponents
  617. ));
  618. }
  619.  
  620. return array(
  621. 'privatekey' => '',
  622. 'publickey' => '',
  623. 'partialkey' => $partialkey
  624. );
  625. }
  626.  
  627. // the first coefficient is calculated differently from the rest
  628. // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
  629. if ($i > 2) {
  630. $coefficients[$i] = $n->modInverse($primes[$i]);
  631. }
  632.  
  633. $n = $n->multiply($primes[$i]);
  634.  
  635. $temp = $primes[$i]->subtract($this->one);
  636.  
  637. // textbook RSA implementations use Euler's totient function instead of the least common multiple.
  638. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
  639. $lcm['top'] = $lcm['top']->multiply($temp);
  640. $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
  641.  
  642. $exponents[$i] = $e->modInverse($temp);
  643. }
  644.  
  645. list($lcm) = $lcm['top']->divide($lcm['bottom']);
  646. $gcd = $lcm->gcd($e);
  647. $i0 = 1;
  648. } while (!$gcd->equals($this->one));
  649.  
  650. $d = $e->modInverse($lcm);
  651.  
  652. $coefficients[2] = $primes[2]->modInverse($primes[1]);
  653.  
  654. // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
  655. // RSAPrivateKey ::= SEQUENCE {
  656. // version Version,
  657. // modulus INTEGER, -- n
  658. // publicExponent INTEGER, -- e
  659. // privateExponent INTEGER, -- d
  660. // prime1 INTEGER, -- p
  661. // prime2 INTEGER, -- q
  662. // exponent1 INTEGER, -- d mod (p-1)
  663. // exponent2 INTEGER, -- d mod (q-1)
  664. // coefficient INTEGER, -- (inverse of q) mod p
  665. // otherPrimeInfos OtherPrimeInfos OPTIONAL
  666. // }
  667.  
  668. return array(
  669. 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
  670. 'publickey' => $this->_convertPublicKey($n, $e),
  671. 'partialkey' => false
  672. );
  673. }
  674.  
  675. /**
  676. * Convert a private key to the appropriate format.
  677. *
  678. * @access private
  679. * @see setPrivateKeyFormat()
  680. * @param String $RSAPrivateKey
  681. * @return String
  682. */
  683. function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
  684. {
  685. $num_primes = count($primes);
  686. $raw = array(
  687. 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
  688. 'modulus' => $n->toBytes(true),
  689. 'publicExponent' => $e->toBytes(true),
  690. 'privateExponent' => $d->toBytes(true),
  691. 'prime1' => $primes[1]->toBytes(true),
  692. 'prime2' => $primes[2]->toBytes(true),
  693. 'exponent1' => $exponents[1]->toBytes(true),
  694. 'exponent2' => $exponents[2]->toBytes(true),
  695. 'coefficient' => $coefficients[2]->toBytes(true)
  696. );
  697.  
  698. // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
  699. // call _convertPublicKey() instead.
  700. switch ($this->privateKeyFormat) {
  701. case CRYPT_RSA_PRIVATE_FORMAT_XML:
  702. if ($num_primes != 2) {
  703. return false;
  704. }
  705. return "<RSAKeyValue>\r\n" .
  706. ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
  707. ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
  708. ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
  709. ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
  710. ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
  711. ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
  712. ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
  713. ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
  714. '</RSAKeyValue>';
  715. break;
  716. case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
  717. if ($num_primes != 2) {
  718. return false;
  719. }
  720. $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
  721. $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
  722. $key.= $encryption;
  723. $key.= "\r\nComment: " . $this->comment . "\r\n";
  724. $public = pack('Na*Na*Na*',
  725. strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
  726. );
  727. $source = pack('Na*Na*Na*Na*',
  728. strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
  729. strlen($this->comment), $this->comment, strlen($public), $public
  730. );
  731. $public = base64_encode($public);
  732. $key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n";
  733. $key.= chunk_split($public, 64);
  734. $private = pack('Na*Na*Na*Na*',
  735. strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
  736. strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
  737. );
  738. if (empty($this->password) && !is_string($this->password)) {
  739. $source.= pack('Na*', strlen($private), $private);
  740. $hashkey = 'putty-private-key-file-mac-key';
  741. } else {
  742. $private.= crypt_random_string(16 - (strlen($private) & 15));
  743. $source.= pack('Na*', strlen($private), $private);
  744. if (!class_exists('Crypt_AES')) {
  745. require_once('Crypt/AES.php');
  746. }
  747. $sequence = 0;
  748. $symkey = '';
  749. while (strlen($symkey) < 32) {
  750. $temp = pack('Na*', $sequence++, $this->password);
  751. $symkey.= pack('H*', sha1($temp));
  752. }
  753. $symkey = substr($symkey, 0, 32);
  754. $crypto = new Crypt_AES();
  755.  
  756. $crypto->setKey($symkey);
  757. $crypto->disablePadding();
  758. $private = $crypto->encrypt($private);
  759. $hashkey = 'putty-private-key-file-mac-key' . $this->password;
  760. }
  761.  
  762. $private = base64_encode($private);
  763. $key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
  764. $key.= chunk_split($private, 64);
  765. if (!class_exists('Crypt_Hash')) {
  766. require_once('Crypt/Hash.php');
  767. }
  768. $hash = new Crypt_Hash('sha1');
  769. $hash->setKey(pack('H*', sha1($hashkey)));
  770. $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
  771.  
  772. return $key;
  773. default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
  774. $components = array();
  775. foreach ($raw as $name => $value) {
  776. $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
  777. }
  778.  
  779. $RSAPrivateKey = implode('', $components);
  780.  
  781. if ($num_primes > 2) {
  782. $OtherPrimeInfos = '';
  783. for ($i = 3; $i <= $num_primes; $i++) {
  784. // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
  785. //
  786. // OtherPrimeInfo ::= SEQUENCE {
  787. // prime INTEGER, -- ri
  788. // exponent INTEGER, -- di
  789. // coefficient INTEGER -- ti
  790. // }
  791. $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
  792. $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
  793. $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
  794. $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
  795. }
  796. $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
  797. }
  798.  
  799. $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
  800.  
  801. if (!empty($this->password) || is_string($this->password)) {
  802. $iv = crypt_random_string(8);
  803. $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
  804. $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
  805. if (!class_exists('Crypt_TripleDES')) {
  806. require_once('Crypt/TripleDES.php');
  807. }
  808. $des = new Crypt_TripleDES();
  809. $des->setKey($symkey);
  810. $des->setIV($iv);
  811. $iv = strtoupper(bin2hex($iv));
  812. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  813. "Proc-Type: 4,ENCRYPTED\r\n" .
  814. "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
  815. "\r\n" .
  816. chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
  817. '-----END RSA PRIVATE KEY-----';
  818. } else {
  819. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  820. chunk_split(base64_encode($RSAPrivateKey), 64) .
  821. '-----END RSA PRIVATE KEY-----';
  822. }
  823.  
  824. return $RSAPrivateKey;
  825. }
  826. }
  827.  
  828. /**
  829. * Convert a public key to the appropriate format
  830. *
  831. * @access private
  832. * @see setPublicKeyFormat()
  833. * @param String $RSAPrivateKey
  834. * @return String
  835. */
  836. function _convertPublicKey($n, $e)
  837. {
  838. $modulus = $n->toBytes(true);
  839. $publicExponent = $e->toBytes(true);
  840.  
  841. switch ($this->publicKeyFormat) {
  842. case CRYPT_RSA_PUBLIC_FORMAT_RAW:
  843. return array('e' => $e->copy(), 'n' => $n->copy());
  844. case CRYPT_RSA_PUBLIC_FORMAT_XML:
  845. return "<RSAKeyValue>\r\n" .
  846. ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
  847. ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
  848. '</RSAKeyValue>';
  849. break;
  850. case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
  851. // from <http://tools.ietf.org/html/rfc4253#page-15>:
  852. // string "ssh-rsa"
  853. // mpint e
  854. // mpint n
  855. $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
  856. $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
  857.  
  858. return $RSAPublicKey;
  859. default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
  860. // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
  861. // RSAPublicKey ::= SEQUENCE {
  862. // modulus INTEGER, -- n
  863. // publicExponent INTEGER -- e
  864. // }
  865. $components = array(
  866. 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
  867. 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
  868. );
  869.  
  870. $RSAPublicKey = pack('Ca*a*a*',
  871. CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
  872. $components['modulus'], $components['publicExponent']
  873. );
  874.  
  875. if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
  876. // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
  877. $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
  878. $RSAPublicKey = chr(0) . $RSAPublicKey;
  879. $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
  880.  
  881. $RSAPublicKey = pack('Ca*a*',
  882. CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
  883. );
  884. }
  885.  
  886. $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
  887. chunk_split(base64_encode($RSAPublicKey), 64) .
  888. '-----END PUBLIC KEY-----';
  889.  
  890. return $RSAPublicKey;
  891. }
  892. }
  893.  
  894. /**
  895. * Break a public or private key down into its constituant components
  896. *
  897. * @access private
  898. * @see _convertPublicKey()
  899. * @see _convertPrivateKey()
  900. * @param String $key
  901. * @param Integer $type
  902. * @return Array
  903. */
  904. function _parseKey($key, $type)
  905. {
  906. if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
  907. return false;
  908. }
  909.  
  910. switch ($type) {
  911. case CRYPT_RSA_PUBLIC_FORMAT_RAW:
  912. if (!is_array($key)) {
  913. return false;
  914. }
  915. $components = array();
  916. switch (true) {
  917. case isset($key['e']):
  918. $components['publicExponent'] = $key['e']->copy();
  919. break;
  920. case isset($key['exponent']):
  921. $components['publicExponent'] = $key['exponent']->copy();
  922. break;
  923. case isset($key['publicExponent']):
  924. $components['publicExponent'] = $key['publicExponent']->copy();
  925. break;
  926. case isset($key[0]):
  927. $components['publicExponent'] = $key[0]->copy();
  928. }
  929. switch (true) {
  930. case isset($key['n']):
  931. $components['modulus'] = $key['n']->copy();
  932. break;
  933. case isset($key['modulo']):
  934. $components['modulus'] = $key['modulo']->copy();
  935. break;
  936. case isset($key['modulus']):
  937. $components['modulus'] = $key['modulus']->copy();
  938. break;
  939. case isset($key[1]):
  940. $components['modulus'] = $key[1]->copy();
  941. }
  942. return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
  943. case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
  944. case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
  945. /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
  946. "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
  947. protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
  948. two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
  949.  
  950. http://tools.ietf.org/html/rfc1421#section-4.6.1.1
  951. http://tools.ietf.org/html/rfc1421#section-4.6.1.3
  952.  
  953. DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
  954. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
  955. function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
  956. own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
  957. implementation are part of the standard, as well.
  958.  
  959. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
  960. if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
  961. $iv = pack('H*', trim($matches[2]));
  962. $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
  963. $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
  964. $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
  965. $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
  966. if ($ciphertext === false) {
  967. $ciphertext = $key;
  968. }
  969. switch ($matches[1]) {
  970. case 'AES-256-CBC':
  971. if (!class_exists('Crypt_AES')) {
  972. require_once('Crypt/AES.php');
  973. }
  974. $crypto = new Crypt_AES();
  975. break;
  976. case 'AES-128-CBC':
  977. if (!class_exists('Crypt_AES')) {
  978. require_once('Crypt/AES.php');
  979. }
  980. $symkey = substr($symkey, 0, 16);
  981. $crypto = new Crypt_AES();
  982. break;
  983. case 'DES-EDE3-CFB':
  984. if (!class_exists('Crypt_TripleDES')) {
  985. require_once('Crypt/TripleDES.php');
  986. }
  987. $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
  988. break;
  989. case 'DES-EDE3-CBC':
  990. if (!class_exists('Crypt_TripleDES')) {
  991. require_once('Crypt/TripleDES.php');
  992. }
  993. $symkey = substr($symkey, 0, 24);
  994. $crypto = new Crypt_TripleDES();
  995. break;
  996. case 'DES-CBC':
  997. if (!class_exists('Crypt_DES')) {
  998. require_once('Crypt/DES.php');
  999. }
  1000. $crypto = new Crypt_DES();
  1001. break;
  1002. default:
  1003. return false;
  1004. }
  1005. $crypto->setKey($symkey);
  1006. $crypto->setIV($iv);
  1007. $decoded = $crypto->decrypt($ciphertext);
  1008. } else {
  1009. $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
  1010. $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
  1011. }
  1012.  
  1013. if ($decoded !== false) {
  1014. $key = $decoded;
  1015. }
  1016.  
  1017. $components = array();
  1018.  
  1019. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  1020. return false;
  1021. }
  1022. if ($this->_decodeLength($key) != strlen($key)) {
  1023. return false;
  1024. }
  1025.  
  1026. $tag = ord($this->_string_shift($key));
  1027. /* intended for keys for which OpenSSL's asn1parse returns the following:
  1028.  
  1029. 0:d=0 hl=4 l= 631 cons: SEQUENCE
  1030. 4:d=1 hl=2 l= 1 prim: INTEGER :00
  1031. 7:d=1 hl=2 l= 13 cons: SEQUENCE
  1032. 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
  1033. 20:d=2 hl=2 l= 0 prim: NULL
  1034. 22:d=1 hl=4 l= 609 prim: OCTET STRING */
  1035.  
  1036. if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
  1037. $this->_string_shift($key, 3);
  1038. $tag = CRYPT_RSA_ASN1_SEQUENCE;
  1039. }
  1040.  
  1041. if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
  1042. /* intended for keys for which OpenSSL's asn1parse returns the following:
  1043.  
  1044. 0:d=0 hl=4 l= 290 cons: SEQUENCE
  1045. 4:d=1 hl=2 l= 13 cons: SEQUENCE
  1046. 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
  1047. 17:d=2 hl=2 l= 0 prim: NULL
  1048. 19:d=1 hl=4 l= 271 prim: BIT STRING */
  1049. $this->_string_shift($key, $this->_decodeLength($key));
  1050. $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
  1051. $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
  1052. // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
  1053. // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
  1054. // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
  1055. if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
  1056. $this->_string_shift($key);
  1057. }
  1058. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  1059. return false;
  1060. }
  1061. if ($this->_decodeLength($key) != strlen($key)) {
  1062. return false;
  1063. }
  1064. $tag = ord($this->_string_shift($key));
  1065. }
  1066. if ($tag != CRYPT_RSA_ASN1_INTEGER) {
  1067. return false;
  1068. }
  1069.  
  1070. $length = $this->_decodeLength($key);
  1071. $temp = $this->_string_shift($key, $length);
  1072. if (strlen($temp) != 1 || ord($temp) > 2) {
  1073. $components['modulus'] = new Math_BigInteger($temp, 256);
  1074. $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
  1075. $length = $this->_decodeLength($key);
  1076. $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1077.  
  1078. return $components;
  1079. }
  1080. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
  1081. return false;
  1082. }
  1083. $length = $this->_decodeLength($key);
  1084. $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1085. $this->_string_shift($key);
  1086. $length = $this->_decodeLength($key);
  1087. $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1088. $this->_string_shift($key);
  1089. $length = $this->_decodeLength($key);
  1090. $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1091. $this->_string_shift($key);
  1092. $length = $this->_decodeLength($key);
  1093. $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
  1094. $this->_string_shift($key);
  1095. $length = $this->_decodeLength($key);
  1096. $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1097. $this->_string_shift($key);
  1098. $length = $this->_decodeLength($key);
  1099. $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
  1100. $this->_string_shift($key);
  1101. $length = $this->_decodeLength($key);
  1102. $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1103. $this->_string_shift($key);
  1104. $length = $this->_decodeLength($key);
  1105. $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
  1106.  
  1107. if (!empty($key)) {
  1108. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  1109. return false;
  1110. }
  1111. $this->_decodeLength($key);
  1112. while (!empty($key)) {
  1113. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  1114. return false;
  1115. }
  1116. $this->_decodeLength($key);
  1117. $key = substr($key, 1);
  1118. $length = $this->_decodeLength($key);
  1119. $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1120. $this->_string_shift($key);
  1121. $length = $this->_decodeLength($key);
  1122. $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1123. $this->_string_shift($key);
  1124. $length = $this->_decodeLength($key);
  1125. $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
  1126. }
  1127. }
  1128.  
  1129. return $components;
  1130. case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
  1131. $parts = explode(' ', $key, 3);
  1132.  
  1133. $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
  1134. if ($key === false) {
  1135. return false;
  1136. }
  1137.  
  1138. $comment = isset($parts[2]) ? $parts[2] : false;
  1139.  
  1140. $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
  1141.  
  1142. if (strlen($key) <= 4) {
  1143. return false;
  1144. }
  1145. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  1146. $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
  1147. if (strlen($key) <= 4) {
  1148. return false;
  1149. }
  1150. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  1151. $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
  1152.  
  1153. if ($cleanup && strlen($key)) {
  1154. if (strlen($key) <= 4) {
  1155. return false;
  1156. }
  1157. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  1158. $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
  1159. return strlen($key) ? false : array(
  1160. 'modulus' => $realModulus,
  1161. 'publicExponent' => $modulus,
  1162. 'comment' => $comment
  1163. );
  1164. } else {
  1165. return strlen($key) ? false : array(
  1166. 'modulus' => $modulus,
  1167. 'publicExponent' => $publicExponent,
  1168. 'comment' => $comment
  1169. );
  1170. }
  1171. // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
  1172. // http://en.wikipedia.org/wiki/XML_Signature
  1173. case CRYPT_RSA_PRIVATE_FORMAT_XML:
  1174. case CRYPT_RSA_PUBLIC_FORMAT_XML:
  1175. $this->components = array();
  1176.  
  1177. $xml = xml_parser_create('UTF-8');
  1178. xml_set_object($xml, $this);
  1179. xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
  1180. xml_set_character_data_handler($xml, '_data_handler');
  1181. // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
  1182. if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
  1183. return false;
  1184. }
  1185.  
  1186. return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
  1187. // from PuTTY's SSHPUBK.C
  1188. case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
  1189. $components = array();
  1190. $key = preg_split('#\r\n|\r|\n#', $key);
  1191. $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
  1192. if ($type != 'ssh-rsa') {
  1193. return false;
  1194. }
  1195. $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
  1196. $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
  1197.  
  1198. $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
  1199. $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
  1200. $public = substr($public, 11);
  1201. extract(unpack('Nlength', $this->_string_shift($public, 4)));
  1202. $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
  1203. extract(unpack('Nlength', $this->_string_shift($public, 4)));
  1204. $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
  1205.  
  1206. $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
  1207. $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
  1208.  
  1209. switch ($encryption) {
  1210. case 'aes256-cbc':
  1211. if (!class_exists('Crypt_AES')) {
  1212. require_once('Crypt/AES.php');
  1213. }
  1214. $symkey = '';
  1215. $sequence = 0;
  1216. while (strlen($symkey) < 32) {
  1217. $temp = pack('Na*', $sequence++, $this->password);
  1218. $symkey.= pack('H*', sha1($temp));
  1219. }
  1220. $symkey = substr($symkey, 0, 32);
  1221. $crypto = new Crypt_AES();
  1222. }
  1223.  
  1224. if ($encryption != 'none') {
  1225. $crypto->setKey($symkey);
  1226. $crypto->disablePadding();
  1227. $private = $crypto->decrypt($private);
  1228. if ($private === false) {
  1229. return false;
  1230. }
  1231. }
  1232.  
  1233. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  1234. if (strlen($private) < $length) {
  1235. return false;
  1236. }
  1237. $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
  1238. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  1239. if (strlen($private) < $length) {
  1240. return false;
  1241. }
  1242. $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
  1243. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  1244. if (strlen($private) < $length) {
  1245. return false;
  1246. }
  1247. $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
  1248.  
  1249. $temp = $components['primes'][1]->subtract($this->one);
  1250. $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
  1251. $temp = $components['primes'][2]->subtract($this->one);
  1252. $components['exponents'][] = $components['publicExponent']->modInverse($temp);
  1253.  
  1254. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  1255. if (strlen($private) < $length) {
  1256. return false;
  1257. }
  1258. $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
  1259.  
  1260. return $components;
  1261. }
  1262. }
  1263.  
  1264. /**
  1265. * Returns the key size
  1266. *
  1267. * More specifically, this returns the size of the modulo in bits.
  1268. *
  1269. * @access public
  1270. * @return Integer
  1271. */
  1272. function getSize()
  1273. {
  1274. return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
  1275. }
  1276.  
  1277. /**
  1278. * Start Element Handler
  1279. *
  1280. * Called by xml_set_element_handler()
  1281. *
  1282. * @access private
  1283. * @param Resource $parser
  1284. * @param String $name
  1285. * @param Array $attribs
  1286. */
  1287. function _start_element_handler($parser, $name, $attribs)
  1288. {
  1289. //$name = strtoupper($name);
  1290. switch ($name) {
  1291. case 'MODULUS':
  1292. $this->current = &$this->components['modulus'];
  1293. break;
  1294. case 'EXPONENT':
  1295. $this->current = &$this->components['publicExponent'];
  1296. break;
  1297. case 'P':
  1298. $this->current = &$this->components['primes'][1];
  1299. break;
  1300. case 'Q':
  1301. $this->current = &$this->components['primes'][2];
  1302. break;
  1303. case 'DP':
  1304. $this->current = &$this->components['exponents'][1];
  1305. break;
  1306. case 'DQ':
  1307. $this->current = &$this->components['exponents'][2];
  1308. break;
  1309. case 'INVERSEQ':
  1310. $this->current = &$this->components['coefficients'][2];
  1311. break;
  1312. case 'D':
  1313. $this->current = &$this->components['privateExponent'];
  1314. break;
  1315. default:
  1316. unset($this->current);
  1317. }
  1318. $this->current = '';
  1319. }
  1320.  
  1321. /**
  1322. * Stop Element Handler
  1323. *
  1324. * Called by xml_set_element_handler()
  1325. *
  1326. * @access private
  1327. * @param Resource $parser
  1328. * @param String $name
  1329. */
  1330. function _stop_element_handler($parser, $name)
  1331. {
  1332. //$name = strtoupper($name);
  1333. if ($name == 'RSAKEYVALUE') {
  1334. return;
  1335. }
  1336. $this->current = new Math_BigInteger(base64_decode($this->current), 256);
  1337. }
  1338.  
  1339. /**
  1340. * Data Handler
  1341. *
  1342. * Called by xml_set_character_data_handler()
  1343. *
  1344. * @access private
  1345. * @param Resource $parser
  1346. * @param String $data
  1347. */
  1348. function _data_handler($parser, $data)
  1349. {
  1350. if (!isset($this->current) || is_object($this->current)) {
  1351. return;
  1352. }
  1353. $this->current.= trim($data);
  1354. }
  1355.  
  1356. /**
  1357. * Loads a public or private key
  1358. *
  1359. * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
  1360. *
  1361. * @access public
  1362. * @param String $key
  1363. * @param Integer $type optional
  1364. */
  1365. function loadKey($key, $type = false)
  1366. {
  1367. if ($type === false) {
  1368. $types = array(
  1369. CRYPT_RSA_PUBLIC_FORMAT_RAW,
  1370. CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
  1371. CRYPT_RSA_PRIVATE_FORMAT_XML,
  1372. CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
  1373. CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
  1374. );
  1375. foreach ($types as $type) {
  1376. $components = $this->_parseKey($key, $type);
  1377. if ($components !== false) {
  1378. break;
  1379. }
  1380. }
  1381.  
  1382. } else {
  1383. $components = $this->_parseKey($key, $type);
  1384. }
  1385.  
  1386. if ($components === false) {
  1387. return false;
  1388. }
  1389.  
  1390. if (isset($components['comment']) && $components['comment'] !== false) {
  1391. $this->comment = $components['comment'];
  1392. }
  1393. $this->modulus = $components['modulus'];
  1394. $this->k = strlen($this->modulus->toBytes());
  1395. $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
  1396. if (isset($components['primes'])) {
  1397. $this->primes = $components['primes'];
  1398. $this->exponents = $components['exponents'];
  1399. $this->coefficients = $components['coefficients'];
  1400. $this->publicExponent = $components['publicExponent'];
  1401. } else {
  1402. $this->primes = array();
  1403. $this->exponents = array();
  1404. $this->coefficients = array();
  1405. $this->publicExponent = false;
  1406. }
  1407.  
  1408. return true;
  1409. }
  1410.  
  1411. /**
  1412. * Sets the password
  1413. *
  1414. * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
  1415. * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
  1416. *
  1417. * @see createKey()
  1418. * @see loadKey()
  1419. * @access public
  1420. * @param String $password
  1421. */
  1422. function setPassword($password = false)
  1423. {
  1424. $this->password = $password;
  1425. }
  1426.  
  1427. /**
  1428. * Defines the public key
  1429. *
  1430. * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
  1431. * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
  1432. * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
  1433. * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
  1434. * exponent this won't work unless you manually add the public exponent.
  1435. *
  1436. * Do note that when a new key is loaded the index will be cleared.
  1437. *
  1438. * Returns true on success, false on failure
  1439. *
  1440. * @see getPublicKey()
  1441. * @access public
  1442. * @param String $key optional
  1443. * @param Integer $type optional
  1444. * @return Boolean
  1445. */
  1446. function setPublicKey($key = false, $type = false)
  1447. {
  1448. if ($key === false && !empty($this->modulus)) {
  1449. $this->publicExponent = $this->exponent;
  1450. return true;
  1451. }
  1452.  
  1453. if ($type === false) {
  1454. $types = array(
  1455. CRYPT_RSA_PUBLIC_FORMAT_RAW,
  1456. CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
  1457. CRYPT_RSA_PUBLIC_FORMAT_XML,
  1458. CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
  1459. );
  1460. foreach ($types as $type) {
  1461. $components = $this->_parseKey($key, $type);
  1462. if ($components !== false) {
  1463. break;
  1464. }
  1465. }
  1466. } else {
  1467. $components = $this->_parseKey($key, $type);
  1468. }
  1469.  
  1470. if ($components === false) {
  1471. return false;
  1472. }
  1473.  
  1474. if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
  1475. $this->modulus = $components['modulus'];
  1476. $this->exponent = $this->publicExponent = $components['publicExponent'];
  1477. return true;
  1478. }
  1479.  
  1480. $this->publicExponent = $components['publicExponent'];
  1481.  
  1482. return true;
  1483. }
  1484.  
  1485. /**
  1486. * Returns the public key
  1487. *
  1488. * The public key is only returned under two circumstances - if the private key had the public key embedded within it
  1489. * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
  1490. * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
  1491. *
  1492. * @see getPublicKey()
  1493. * @access public
  1494. * @param String $key
  1495. * @param Integer $type optional
  1496. */
  1497. function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
  1498. {
  1499. if (empty($this->modulus) || empty($this->publicExponent)) {
  1500. return false;
  1501. }
  1502.  
  1503. $oldFormat = $this->publicKeyFormat;
  1504. $this->publicKeyFormat = $type;
  1505. $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
  1506. $this->publicKeyFormat = $oldFormat;
  1507. return $temp;
  1508. }
  1509.  
  1510. /**
  1511. * Returns the private key
  1512. *
  1513. * The private key is only returned if the currently loaded key contains the constituent prime numbers.
  1514. *
  1515. * @see getPublicKey()
  1516. * @access public
  1517. * @param String $key
  1518. * @param Integer $type optional
  1519. */
  1520. function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
  1521. {
  1522. if (empty($this->primes)) {
  1523. return false;
  1524. }
  1525.  
  1526. $oldFormat = $this->privateKeyFormat;
  1527. $this->privateKeyFormat = $type;
  1528. $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
  1529. $this->privateKeyFormat = $oldFormat;
  1530. return $temp;
  1531. }
  1532.  
  1533. /**
  1534. * Returns a minimalistic private key
  1535. *
  1536. * Returns the private key without the prime number constituants. Structurally identical to a public key that
  1537. * hasn't been set as the public key
  1538. *
  1539. * @see getPrivateKey()
  1540. * @access private
  1541. * @param String $key
  1542. * @param Integer $type optional
  1543. */
  1544. function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
  1545. {
  1546. if (empty($this->modulus) || empty($this->exponent)) {
  1547. return false;
  1548. }
  1549.  
  1550. $oldFormat = $this->publicKeyFormat;
  1551. $this->publicKeyFormat = $mode;
  1552. $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
  1553. $this->publicKeyFormat = $oldFormat;
  1554. return $temp;
  1555. }
  1556.  
  1557. /**
  1558. * __toString() magic method
  1559. *
  1560. * @access public
  1561. */
  1562. function __toString()
  1563. {
  1564. $key = $this->getPrivateKey($this->privateKeyFormat);
  1565. if ($key !== false) {
  1566. return $key;
  1567. }
  1568. $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
  1569. return $key !== false ? $key : '';
  1570. }
  1571.  
  1572. /**
  1573. * Generates the smallest and largest numbers requiring $bits bits
  1574. *
  1575. * @access private
  1576. * @param Integer $bits
  1577. * @return Array
  1578. */
  1579. function _generateMinMax($bits)
  1580. {
  1581. $bytes = $bits >> 3;
  1582. $min = str_repeat(chr(0), $bytes);
  1583. $max = str_repeat(chr(0xFF), $bytes);
  1584. $msb = $bits & 7;
  1585. if ($msb) {
  1586. $min = chr(1 << ($msb - 1)) . $min;
  1587. $max = chr((1 << $msb) - 1) . $max;
  1588. } else {
  1589. $min[0] = chr(0x80);
  1590. }
  1591.  
  1592. return array(
  1593. 'min' => new Math_BigInteger($min, 256),
  1594. 'max' => new Math_BigInteger($max, 256)
  1595. );
  1596. }
  1597.  
  1598. /**
  1599. * DER-decode the length
  1600. *
  1601. * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
  1602. * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
  1603. *
  1604. * @access private
  1605. * @param String $string
  1606. * @return Integer
  1607. */
  1608. function _decodeLength(&$string)
  1609. {
  1610. $length = ord($this->_string_shift($string));
  1611. if ( $length & 0x80 ) { // definite length, long form
  1612. $length&= 0x7F;
  1613. $temp = $this->_string_shift($string, $length);
  1614. list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
  1615. }
  1616. return $length;
  1617. }
  1618.  
  1619. /**
  1620. * DER-encode the length
  1621. *
  1622. * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
  1623. * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
  1624. *
  1625. * @access private
  1626. * @param Integer $length
  1627. * @return String
  1628. */
  1629. function _encodeLength($length)
  1630. {
  1631. if ($length <= 0x7F) {
  1632. return chr($length);
  1633. }
  1634.  
  1635. $temp = ltrim(pack('N', $length), chr(0));
  1636. return pack('Ca*', 0x80 | strlen($temp), $temp);
  1637. }
  1638.  
  1639. /**
  1640. * String Shift
  1641. *
  1642. * Inspired by array_shift
  1643. *
  1644. * @param String $string
  1645. * @param optional Integer $index
  1646. * @return String
  1647. * @access private
  1648. */
  1649. function _string_shift(&$string, $index = 1)
  1650. {
  1651. $substr = substr($string, 0, $index);
  1652. $string = substr($string, $index);
  1653. return $substr;
  1654. }
  1655.  
  1656. /**
  1657. * Determines the private key format
  1658. *
  1659. * @see createKey()
  1660. * @access public
  1661. * @param Integer $format
  1662. */
  1663. function setPrivateKeyFormat($format)
  1664. {
  1665. $this->privateKeyFormat = $format;
  1666. }
  1667.  
  1668. /**
  1669. * Determines the public key format
  1670. *
  1671. * @see createKey()
  1672. * @access public
  1673. * @param Integer $format
  1674. */
  1675. function setPublicKeyFormat($format)
  1676. {
  1677. $this->publicKeyFormat = $format;
  1678. }
  1679.  
  1680. /**
  1681. * Determines which hashing function should be used
  1682. *
  1683. * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
  1684. * decryption. If $hash isn't supported, sha1 is used.
  1685. *
  1686. * @access public
  1687. * @param String $hash
  1688. */
  1689. function setHash($hash)
  1690. {
  1691. // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
  1692. switch ($hash) {
  1693. case 'md2':
  1694. case 'md5':
  1695. case 'sha1':
  1696. case 'sha256':
  1697. case 'sha384':
  1698. case 'sha512':
  1699. $this->hash = new Crypt_Hash($hash);
  1700. $this->hashName = $hash;
  1701. break;
  1702. default:
  1703. $this->hash = new Crypt_Hash('sha1');
  1704. $this->hashName = 'sha1';
  1705. }
  1706. $this->hLen = $this->hash->getLength();
  1707. }
  1708.  
  1709. /**
  1710. * Determines which hashing function should be used for the mask generation function
  1711. *
  1712. * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
  1713. * best if Hash and MGFHash are set to the same thing this is not a requirement.
  1714. *
  1715. * @access public
  1716. * @param String $hash
  1717. */
  1718. function setMGFHash($hash)
  1719. {
  1720. // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
  1721. switch ($hash) {
  1722. case 'md2':
  1723. case 'md5':
  1724. case 'sha1':
  1725. case 'sha256':
  1726. case 'sha384':
  1727. case 'sha512':
  1728. $this->mgfHash = new Crypt_Hash($hash);
  1729. break;
  1730. default:
  1731. $this->mgfHash = new Crypt_Hash('sha1');
  1732. }
  1733. $this->mgfHLen = $this->mgfHash->getLength();
  1734. }
  1735.  
  1736. /**
  1737. * Determines the salt length
  1738. *
  1739. * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
  1740. *
  1741. * Typical salt lengths in octets are hLen (the length of the output
  1742. * of the hash function Hash) and 0.
  1743. *
  1744. * @access public
  1745. * @param Integer $format
  1746. */
  1747. function setSaltLength($sLen)
  1748. {
  1749. $this->sLen = $sLen;
  1750. }
  1751.  
  1752. /**
  1753. * Integer-to-Octet-String primitive
  1754. *
  1755. * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
  1756. *
  1757. * @access private
  1758. * @param Math_BigInteger $x
  1759. * @param Integer $xLen
  1760. * @return String
  1761. */
  1762. function _i2osp($x, $xLen)
  1763. {
  1764. $x = $x->toBytes();
  1765. if (strlen($x) > $xLen) {
  1766. user_error('Integer too large');
  1767. return false;
  1768. }
  1769. return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
  1770. }
  1771.  
  1772. /**
  1773. * Octet-String-to-Integer primitive
  1774. *
  1775. * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
  1776. *
  1777. * @access private
  1778. * @param String $x
  1779. * @return Math_BigInteger
  1780. */
  1781. function _os2ip($x)
  1782. {
  1783. return new Math_BigInteger($x, 256);
  1784. }
  1785.  
  1786. /**
  1787. * Exponentiate with or without Chinese Remainder Theorem
  1788. *
  1789. * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
  1790. *
  1791. * @access private
  1792. * @param Math_BigInteger $x
  1793. * @return Math_BigInteger
  1794. */
  1795. function _exponentiate($x)
  1796. {
  1797. if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
  1798. return $x->modPow($this->exponent, $this->modulus);
  1799. }
  1800.  
  1801. $num_primes = count($this->primes);
  1802.  
  1803. if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
  1804. $m_i = array(
  1805. 1 => $x->modPow($this->exponents[1], $this->primes[1]),
  1806. 2 => $x->modPow($this->exponents[2], $this->primes[2])
  1807. );
  1808. $h = $m_i[1]->subtract($m_i[2]);
  1809. $h = $h->multiply($this->coefficients[2]);
  1810. list(, $h) = $h->divide($this->primes[1]);
  1811. $m = $m_i[2]->add($h->multiply($this->primes[2]));
  1812.  
  1813. $r = $this->primes[1];
  1814. for ($i = 3; $i <= $num_primes; $i++) {
  1815. $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
  1816.  
  1817. $r = $r->multiply($this->primes[$i - 1]);
  1818.  
  1819. $h = $m_i->subtract($m);
  1820. $h = $h->multiply($this->coefficients[$i]);
  1821. list(, $h) = $h->divide($this->primes[$i]);
  1822.  
  1823. $m = $m->add($r->multiply($h));
  1824. }
  1825. } else {
  1826. $smallest = $this->primes[1];
  1827. for ($i = 2; $i <= $num_primes; $i++) {
  1828. if ($smallest->compare($this->primes[$i]) > 0) {
  1829. $smallest = $this->primes[$i];
  1830. }
  1831. }
  1832.  
  1833. $one = new Math_BigInteger(1);
  1834.  
  1835. $r = $one->random($one, $smallest->subtract($one));
  1836.  
  1837. $m_i = array(
  1838. 1 => $this->_blind($x, $r, 1),
  1839. 2 => $this->_blind($x, $r, 2)
  1840. );
  1841. $h = $m_i[1]->subtract($m_i[2]);
  1842. $h = $h->multiply($this->coefficients[2]);
  1843. list(, $h) = $h->divide($this->primes[1]);
  1844. $m = $m_i[2]->add($h->multiply($this->primes[2]));
  1845.  
  1846. $r = $this->primes[1];
  1847. for ($i = 3; $i <= $num_primes; $i++) {
  1848. $m_i = $this->_blind($x, $r, $i);
  1849.  
  1850. $r = $r->multiply($this->primes[$i - 1]);
  1851.  
  1852. $h = $m_i->subtract($m);
  1853. $h = $h->multiply($this->coefficients[$i]);
  1854. list(, $h) = $h->divide($this->primes[$i]);
  1855.  
  1856. $m = $m->add($r->multiply($h));
  1857. }
  1858. }
  1859.  
  1860. return $m;
  1861. }
  1862.  
  1863. /**
  1864. * Performs RSA Blinding
  1865. *
  1866. * Protects against timing attacks by employing RSA Blinding.
  1867. * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
  1868. *
  1869. * @access private
  1870. * @param Math_BigInteger $x
  1871. * @param Math_BigInteger $r
  1872. * @param Integer $i
  1873. * @return Math_BigInteger
  1874. */
  1875. function _blind($x, $r, $i)
  1876. {
  1877. $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
  1878. $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
  1879.  
  1880. $r = $r->modInverse($this->primes[$i]);
  1881. $x = $x->multiply($r);
  1882. list(, $x) = $x->divide($this->primes[$i]);
  1883.  
  1884. return $x;
  1885. }
  1886.  
  1887. /**
  1888. * Performs blinded RSA equality testing
  1889. *
  1890. * Protects against a particular type of timing attack described.
  1891. *
  1892. * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
  1893. *
  1894. * Thanks for the heads up singpolyma!
  1895. *
  1896. * @access private
  1897. * @param String $x
  1898. * @param String $y
  1899. * @return Boolean
  1900. */
  1901. function _equals($x, $y)
  1902. {
  1903. if (strlen($x) != strlen($y)) {
  1904. return false;
  1905. }
  1906.  
  1907. $result = 0;
  1908. for ($i = 0; $i < strlen($x); $i++) {
  1909. $result |= ord($x[$i]) ^ ord($y[$i]);
  1910. }
  1911.  
  1912. return $result == 0;
  1913. }
  1914.  
  1915. /**
  1916. * RSAEP
  1917. *
  1918. * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
  1919. *
  1920. * @access private
  1921. * @param Math_BigInteger $m
  1922. * @return Math_BigInteger
  1923. */
  1924. function _rsaep($m)
  1925. {
  1926. if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
  1927. user_error('Message representative out of range');
  1928. return false;
  1929. }
  1930. return $this->_exponentiate($m);
  1931. }
  1932.  
  1933. /**
  1934. * RSADP
  1935. *
  1936. * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
  1937. *
  1938. * @access private
  1939. * @param Math_BigInteger $c
  1940. * @return Math_BigInteger
  1941. */
  1942. function _rsadp($c)
  1943. {
  1944. if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
  1945. user_error('Ciphertext representative out of range');
  1946. return false;
  1947. }
  1948. return $this->_exponentiate($c);
  1949. }
  1950.  
  1951. /**
  1952. * RSASP1
  1953. *
  1954. * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
  1955. *
  1956. * @access private
  1957. * @param Math_BigInteger $m
  1958. * @return Math_BigInteger
  1959. */
  1960. function _rsasp1($m)
  1961. {
  1962. if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
  1963. user_error('Message representative out of range');
  1964. return false;
  1965. }
  1966. return $this->_exponentiate($m);
  1967. }
  1968.  
  1969. /**
  1970. * RSAVP1
  1971. *
  1972. * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
  1973. *
  1974. * @access private
  1975. * @param Math_BigInteger $s
  1976. * @return Math_BigInteger
  1977. */
  1978. function _rsavp1($s)
  1979. {
  1980. if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
  1981. user_error('Signature representative out of range');
  1982. return false;
  1983. }
  1984. return $this->_exponentiate($s);
  1985. }
  1986.  
  1987. /**
  1988. * MGF1
  1989. *
  1990. * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
  1991. *
  1992. * @access private
  1993. * @param String $mgfSeed
  1994. * @param Integer $mgfLen
  1995. * @return String
  1996. */
  1997. function _mgf1($mgfSeed, $maskLen)
  1998. {
  1999. // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
  2000.  
  2001. $t = '';
  2002. $count = ceil($maskLen / $this->mgfHLen);
  2003. for ($i = 0; $i < $count; $i++) {
  2004. $c = pack('N', $i);
  2005. $t.= $this->mgfHash->hash($mgfSeed . $c);
  2006. }
  2007.  
  2008. return substr($t, 0, $maskLen);
  2009. }
  2010.  
  2011. /**
  2012. * RSAES-OAEP-ENCRYPT
  2013. *
  2014. * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
  2015. * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
  2016. *
  2017. * @access private
  2018. * @param String $m
  2019. * @param String $l
  2020. * @return String
  2021. */
  2022. function _rsaes_oaep_encrypt($m, $l = '')
  2023. {
  2024. $mLen = strlen($m);
  2025.  
  2026. // Length checking
  2027.  
  2028. // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
  2029. // be output.
  2030.  
  2031. if ($mLen > $this->k - 2 * $this->hLen - 2) {
  2032. user_error('Message too long');
  2033. return false;
  2034. }
  2035.  
  2036. // EME-OAEP encoding
  2037.  
  2038. $lHash = $this->hash->hash($l);
  2039. $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
  2040. $db = $lHash . $ps . chr(1) . $m;
  2041. $seed = crypt_random_string($this->hLen);
  2042. $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
  2043. $maskedDB = $db ^ $dbMask;
  2044. $seedMask = $this->_mgf1($maskedDB, $this->hLen);
  2045. $maskedSeed = $seed ^ $seedMask;
  2046. $em = chr(0) . $maskedSeed . $maskedDB;
  2047.  
  2048. // RSA encryption
  2049.  
  2050. $m = $this->_os2ip($em);
  2051. $c = $this->_rsaep($m);
  2052. $c = $this->_i2osp($c, $this->k);
  2053.  
  2054. // Output the ciphertext C
  2055.  
  2056. return $c;
  2057. }
  2058.  
  2059. /**
  2060. * RSAES-OAEP-DECRYPT
  2061. *
  2062. * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
  2063. * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
  2064. *
  2065. * Note. Care must be taken to ensure that an opponent cannot
  2066. * distinguish the different error conditions in Step 3.g, whether by
  2067. * error message or timing, or, more generally, learn partial
  2068. * information about the encoded message EM. Otherwise an opponent may
  2069. * be able to obtain useful information about the decryption of the
  2070. * ciphertext C, leading to a chosen-ciphertext attack such as the one
  2071. * observed by Manger [36].
  2072. *
  2073. * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
  2074. *
  2075. * Both the encryption and the decryption operations of RSAES-OAEP take
  2076. * the value of a label L as input. In this version of PKCS #1, L is
  2077. * the empty string; other uses of the label are outside the scope of
  2078. * this document.
  2079. *
  2080. * @access private
  2081. * @param String $c
  2082. * @param String $l
  2083. * @return String
  2084. */
  2085. function _rsaes_oaep_decrypt($c, $l = '')
  2086. {
  2087. // Length checking
  2088.  
  2089. // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
  2090. // be output.
  2091.  
  2092. if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
  2093. user_error('Decryption error');
  2094. return false;
  2095. }
  2096.  
  2097. // RSA decryption
  2098.  
  2099. $c = $this->_os2ip($c);
  2100. $m = $this->_rsadp($c);
  2101. if ($m === false) {
  2102. user_error('Decryption error');
  2103. return false;
  2104. }
  2105. $em = $this->_i2osp($m, $this->k);
  2106.  
  2107. // EME-OAEP decoding
  2108.  
  2109. $lHash = $this->hash->hash($l);
  2110. $y = ord($em[0]);
  2111. $maskedSeed = substr($em, 1, $this->hLen);
  2112. $maskedDB = substr($em, $this->hLen + 1);
  2113. $seedMask = $this->_mgf1($maskedDB, $this->hLen);
  2114. $seed = $maskedSeed ^ $seedMask;
  2115. $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
  2116. $db = $maskedDB ^ $dbMask;
  2117. $lHash2 = substr($db, 0, $this->hLen);
  2118. $m = substr($db, $this->hLen);
  2119. if ($lHash != $lHash2) {
  2120. user_error('Decryption error');
  2121. return false;
  2122. }
  2123. $m = ltrim($m, chr(0));
  2124. if (ord($m[0]) != 1) {
  2125. user_error('Decryption error');
  2126. return false;
  2127. }
  2128.  
  2129. // Output the message M
  2130.  
  2131. return substr($m, 1);
  2132. }
  2133.  
  2134. /**
  2135. * RSAES-PKCS1-V1_5-ENCRYPT
  2136. *
  2137. * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
  2138. *
  2139. * @access private
  2140. * @param String $m
  2141. * @return String
  2142. */
  2143. function _rsaes_pkcs1_v1_5_encrypt($m)
  2144. {
  2145. $mLen = strlen($m);
  2146.  
  2147. // Length checking
  2148.  
  2149. if ($mLen > $this->k - 11) {
  2150. user_error('Message too long');
  2151. return false;
  2152. }
  2153.  
  2154. // EME-PKCS1-v1_5 encoding
  2155.  
  2156. $psLen = $this->k - $mLen - 3;
  2157. $ps = '';
  2158. while (strlen($ps) != $psLen) {
  2159. $temp = crypt_random_string($psLen - strlen($ps));
  2160. $temp = str_replace("\x00", '', $temp);
  2161. $ps.= $temp;
  2162. }
  2163. $type = 2;
  2164. // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
  2165. if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
  2166. $type = 1;
  2167. // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
  2168. $ps = str_repeat("\xFF", $psLen);
  2169. }
  2170. $em = chr(0) . chr($type) . $ps . chr(0) . $m;
  2171.  
  2172. // RSA encryption
  2173. $m = $this->_os2ip($em);
  2174. $c = $this->_rsaep($m);
  2175. $c = $this->_i2osp($c, $this->k);
  2176.  
  2177. // Output the ciphertext C
  2178.  
  2179. return $c;
  2180. }
  2181.  
  2182. /**
  2183. * RSAES-PKCS1-V1_5-DECRYPT
  2184. *
  2185. * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
  2186. *
  2187. * For compatability purposes, this function departs slightly from the description given in RFC3447.
  2188. * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
  2189. * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
  2190. * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
  2191. * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
  2192. * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
  2193. *
  2194. * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
  2195. * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
  2196. * not private key encrypted ciphertext's.
  2197. *
  2198. * @access private
  2199. * @param String $c
  2200. * @return String
  2201. */
  2202. function _rsaes_pkcs1_v1_5_decrypt($c)
  2203. {
  2204. // Length checking
  2205.  
  2206. if (strlen($c) != $this->k) { // or if k < 11
  2207. user_error('Decryption error');
  2208. return false;
  2209. }
  2210.  
  2211. // RSA decryption
  2212.  
  2213. $c = $this->_os2ip($c);
  2214. $m = $this->_rsadp($c);
  2215.  
  2216. if ($m === false) {
  2217. user_error('Decryption error');
  2218. return false;
  2219. }
  2220. $em = $this->_i2osp($m, $this->k);
  2221.  
  2222. // EME-PKCS1-v1_5 decoding
  2223.  
  2224. if (ord($em[0]) != 0 || ord($em[1]) > 2) {
  2225. user_error('Decryption error');
  2226. return false;
  2227. }
  2228.  
  2229. $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
  2230. $m = substr($em, strlen($ps) + 3);
  2231.  
  2232. if (strlen($ps) < 8) {
  2233. user_error('Decryption error');
  2234. return false;
  2235. }
  2236.  
  2237. // Output M
  2238.  
  2239. return $m;
  2240. }
  2241.  
  2242. /**
  2243. * EMSA-PSS-ENCODE
  2244. *
  2245. * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
  2246. *
  2247. * @access private
  2248. * @param String $m
  2249. * @param Integer $emBits
  2250. */
  2251. function _emsa_pss_encode($m, $emBits)
  2252. {
  2253. // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
  2254. // be output.
  2255.  
  2256. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
  2257. $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
  2258.  
  2259. $mHash = $this->hash->hash($m);
  2260. if ($emLen < $this->hLen + $sLen + 2) {
  2261. user_error('Encoding error');
  2262. return false;
  2263. }
  2264.  
  2265. $salt = crypt_random_string($sLen);
  2266. $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
  2267. $h = $this->hash->hash($m2);
  2268. $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
  2269. $db = $ps . chr(1) . $salt;
  2270. $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
  2271. $maskedDB = $db ^ $dbMask;
  2272. $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
  2273. $em = $maskedDB . $h . chr(0xBC);
  2274.  
  2275. return $em;
  2276. }
  2277.  
  2278. /**
  2279. * EMSA-PSS-VERIFY
  2280. *
  2281. * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
  2282. *
  2283. * @access private
  2284. * @param String $m
  2285. * @param String $em
  2286. * @param Integer $emBits
  2287. * @return String
  2288. */
  2289. function _emsa_pss_verify($m, $em, $emBits)
  2290. {
  2291. // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
  2292. // be output.
  2293.  
  2294. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
  2295. $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
  2296.  
  2297. $mHash = $this->hash->hash($m);
  2298. if ($emLen < $this->hLen + $sLen + 2) {
  2299. return false;
  2300. }
  2301.  
  2302. if ($em[strlen($em) - 1] != chr(0xBC)) {
  2303. return false;
  2304. }
  2305.  
  2306. $maskedDB = substr($em, 0, -$this->hLen - 1);
  2307. $h = substr($em, -$this->hLen - 1, $this->hLen);
  2308. $temp = chr(0xFF << ($emBits & 7));
  2309. if ((~$maskedDB[0] & $temp) != $temp) {
  2310. return false;
  2311. }
  2312. $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
  2313. $db = $maskedDB ^ $dbMask;
  2314. $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
  2315. $temp = $emLen - $this->hLen - $sLen - 2;
  2316. if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
  2317. return false;
  2318. }
  2319. $salt = substr($db, $temp + 1); // should be $sLen long
  2320. $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
  2321. $h2 = $this->hash->hash($m2);
  2322. return $this->_equals($h, $h2);
  2323. }
  2324.  
  2325. /**
  2326. * RSASSA-PSS-SIGN
  2327. *
  2328. * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
  2329. *
  2330. * @access private
  2331. * @param String $m
  2332. * @return String
  2333. */
  2334. function _rsassa_pss_sign($m)
  2335. {
  2336. // EMSA-PSS encoding
  2337.  
  2338. $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
  2339.  
  2340. // RSA signature
  2341.  
  2342. $m = $this->_os2ip($em);
  2343. $s = $this->_rsasp1($m);
  2344. $s = $this->_i2osp($s, $this->k);
  2345.  
  2346. // Output the signature S
  2347.  
  2348. return $s;
  2349. }
  2350.  
  2351. /**
  2352. * RSASSA-PSS-VERIFY
  2353. *
  2354. * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
  2355. *
  2356. * @access private
  2357. * @param String $m
  2358. * @param String $s
  2359. * @return String
  2360. */
  2361. function _rsassa_pss_verify($m, $s)
  2362. {
  2363. // Length checking
  2364.  
  2365. if (strlen($s) != $this->k) {
  2366. user_error('Invalid signature');
  2367. return false;
  2368. }
  2369.  
  2370. // RSA verification
  2371.  
  2372. $modBits = 8 * $this->k;
  2373.  
  2374. $s2 = $this->_os2ip($s);
  2375. $m2 = $this->_rsavp1($s2);
  2376. if ($m2 === false) {
  2377. user_error('Invalid signature');
  2378. return false;
  2379. }
  2380. $em = $this->_i2osp($m2, $modBits >> 3);
  2381. if ($em === false) {
  2382. user_error('Invalid signature');
  2383. return false;
  2384. }
  2385.  
  2386. // EMSA-PSS verification
  2387.  
  2388. return $this->_emsa_pss_verify($m, $em, $modBits - 1);
  2389. }
  2390.  
  2391. /**
  2392. * EMSA-PKCS1-V1_5-ENCODE
  2393. *
  2394. * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
  2395. *
  2396. * @access private
  2397. * @param String $m
  2398. * @param Integer $emLen
  2399. * @return String
  2400. */
  2401. function _emsa_pkcs1_v1_5_encode($m, $emLen)
  2402. {
  2403. $h = $this->hash->hash($m);
  2404. if ($h === false) {
  2405. return false;
  2406. }
  2407.  
  2408. // see http://tools.ietf.org/html/rfc3447#page-43
  2409. switch ($this->hashName) {
  2410. case 'md2':
  2411. $t = pack('H*', '3020300c06082a864886f70d020205000410');
  2412. break;
  2413. case 'md5':
  2414. $t = pack('H*', '3020300c06082a864886f70d020505000410');
  2415. break;
  2416. case 'sha1':
  2417. $t = pack('H*', '3021300906052b0e03021a05000414');
  2418. break;
  2419. case 'sha256':
  2420. $t = pack('H*', '3031300d060960864801650304020105000420');
  2421. break;
  2422. case 'sha384':
  2423. $t = pack('H*', '3041300d060960864801650304020205000430');
  2424. break;
  2425. case 'sha512':
  2426. $t = pack('H*', '3051300d060960864801650304020305000440');
  2427. }
  2428. $t.= $h;
  2429. $tLen = strlen($t);
  2430.  
  2431. if ($emLen < $tLen + 11) {
  2432. user_error('Intended encoded message length too short');
  2433. return false;
  2434. }
  2435.  
  2436. $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
  2437.  
  2438. $em = "\0\1$ps\0$t";
  2439.  
  2440. return $em;
  2441. }
  2442.  
  2443. /**
  2444. * RSASSA-PKCS1-V1_5-SIGN
  2445. *
  2446. * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
  2447. *
  2448. * @access private
  2449. * @param String $m
  2450. * @return String
  2451. */
  2452. function _rsassa_pkcs1_v1_5_sign($m)
  2453. {
  2454. // EMSA-PKCS1-v1_5 encoding
  2455.  
  2456. $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
  2457. if ($em === false) {
  2458. user_error('RSA modulus too short');
  2459. return false;
  2460. }
  2461.  
  2462. // RSA signature
  2463.  
  2464. $m = $this->_os2ip($em);
  2465. $s = $this->_rsasp1($m);
  2466. $s = $this->_i2osp($s, $this->k);
  2467.  
  2468. // Output the signature S
  2469.  
  2470. return $s;
  2471. }
  2472.  
  2473. /**
  2474. * RSASSA-PKCS1-V1_5-VERIFY
  2475. *
  2476. * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
  2477. *
  2478. * @access private
  2479. * @param String $m
  2480. * @return String
  2481. */
  2482. function _rsassa_pkcs1_v1_5_verify($m, $s)
  2483. {
  2484. // Length checking
  2485.  
  2486. if (strlen($s) != $this->k) {
  2487. user_error('Invalid signature');
  2488. return false;
  2489. }
  2490.  
  2491. // RSA verification
  2492.  
  2493. $s = $this->_os2ip($s);
  2494. $m2 = $this->_rsavp1($s);
  2495. if ($m2 === false) {
  2496. user_error('Invalid signature');
  2497. return false;
  2498. }
  2499. $em = $this->_i2osp($m2, $this->k);
  2500. if ($em === false) {
  2501. user_error('Invalid signature');
  2502. return false;
  2503. }
  2504.  
  2505. // EMSA-PKCS1-v1_5 encoding
  2506.  
  2507. $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
  2508. if ($em2 === false) {
  2509. user_error('RSA modulus too short');
  2510. return false;
  2511. }
  2512.  
  2513. // Compare
  2514. return $this->_equals($em, $em2);
  2515. }
  2516.  
  2517. /**
  2518. * Set Encryption Mode
  2519. *
  2520. * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
  2521. *
  2522. * @access public
  2523. * @param Integer $mode
  2524. */
  2525. function setEncryptionMode($mode)
  2526. {
  2527. $this->encryptionMode = $mode;
  2528. }
  2529.  
  2530. /**
  2531. * Set Signature Mode
  2532. *
  2533. * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
  2534. *
  2535. * @access public
  2536. * @param Integer $mode
  2537. */
  2538. function setSignatureMode($mode)
  2539. {
  2540. $this->signatureMode = $mode;
  2541. }
  2542.  
  2543. /**
  2544. * Set public key comment.
  2545. *
  2546. * @access public
  2547. * @param String $comment
  2548. */
  2549. function setComment($comment)
  2550. {
  2551. $this->comment = $comment;
  2552. }
  2553.  
  2554. /**
  2555. * Get public key comment.
  2556. *
  2557. * @access public
  2558. * @return String
  2559. */
  2560. function getComment()
  2561. {
  2562. return $this->comment;
  2563. }
  2564.  
  2565. /**
  2566. * Encryption
  2567. *
  2568. * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
  2569. * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
  2570. * be concatenated together.
  2571. *
  2572. * @see decrypt()
  2573. * @access public
  2574. * @param String $plaintext
  2575. * @return String
  2576. */
  2577. function encrypt($plaintext)
  2578. {
  2579. switch ($this->encryptionMode) {
  2580. case CRYPT_RSA_ENCRYPTION_PKCS1:
  2581. $length = $this->k - 11;
  2582. if ($length <= 0) {
  2583. return false;
  2584. }
  2585.  
  2586. $plaintext = str_split($plaintext, $length);
  2587. $ciphertext = '';
  2588. foreach ($plaintext as $m) {
  2589. $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
  2590. }
  2591. return $ciphertext;
  2592. //case CRYPT_RSA_ENCRYPTION_OAEP:
  2593. default:
  2594. $length = $this->k - 2 * $this->hLen - 2;
  2595. if ($length <= 0) {
  2596. return false;
  2597. }
  2598.  
  2599. $plaintext = str_split($plaintext, $length);
  2600. $ciphertext = '';
  2601. foreach ($plaintext as $m) {
  2602. $ciphertext.= $this->_rsaes_oaep_encrypt($m);
  2603. }
  2604. return $ciphertext;
  2605. }
  2606. }
  2607.  
  2608. /**
  2609. * Decryption
  2610. *
  2611. * @see encrypt()
  2612. * @access public
  2613. * @param String $plaintext
  2614. * @return String
  2615. */
  2616. function decrypt($ciphertext)
  2617. {
  2618. if ($this->k <= 0) {
  2619. return false;
  2620. }
  2621.  
  2622. $ciphertext = str_split($ciphertext, $this->k);
  2623. $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
  2624.  
  2625. $plaintext = '';
  2626.  
  2627. switch ($this->encryptionMode) {
  2628. case CRYPT_RSA_ENCRYPTION_PKCS1:
  2629. $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
  2630. break;
  2631. //case CRYPT_RSA_ENCRYPTION_OAEP:
  2632. default:
  2633. $decrypt = '_rsaes_oaep_decrypt';
  2634. }
  2635.  
  2636. foreach ($ciphertext as $c) {
  2637. $temp = $this->$decrypt($c);
  2638. if ($temp === false) {
  2639. return false;
  2640. }
  2641. $plaintext.= $temp;
  2642. }
  2643.  
  2644. return $plaintext;
  2645. }
  2646.  
  2647. /**
  2648. * Create a signature
  2649. *
  2650. * @see verify()
  2651. * @access public
  2652. * @param String $message
  2653. * @return String
  2654. */
  2655. function sign($message)
  2656. {
  2657. if (empty($this->modulus) || empty($this->exponent)) {
  2658. return false;
  2659. }
  2660.  
  2661. switch ($this->signatureMode) {
  2662. case CRYPT_RSA_SIGNATURE_PKCS1:
  2663. return $this->_rsassa_pkcs1_v1_5_sign($message);
  2664. //case CRYPT_RSA_SIGNATURE_PSS:
  2665. default:
  2666. return $this->_rsassa_pss_sign($message);
  2667. }
  2668. }
  2669.  
  2670. /**
  2671. * Verifies a signature
  2672. *
  2673. * @see sign()
  2674. * @access public
  2675. * @param String $message
  2676. * @param String $signature
  2677. * @return Boolean
  2678. */
  2679. function verify($message, $signature)
  2680. {
  2681. if (empty($this->modulus) || empty($this->exponent)) {
  2682. return false;
  2683. }
  2684.  
  2685. switch ($this->signatureMode) {
  2686. case CRYPT_RSA_SIGNATURE_PKCS1:
  2687. return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
  2688. //case CRYPT_RSA_SIGNATURE_PSS:
  2689. default:
  2690. return $this->_rsassa_pss_verify($message, $signature);
  2691. }
  2692. }
  2693. }
Add Comment
Please, Sign In to add comment