PageRenderTime 64ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/fuel/core/vendor/phpseclib/Crypt/RSA.php

https://bitbucket.org/sriedel/iccrm-wip
PHP | 2332 lines | 1152 code | 241 blank | 939 comment | 178 complexity | 6d378683a2b96c9f862a01b660c702a6 MD5 | raw file
Possible License(s): MIT

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. namespace PHPSecLib;
  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. * @version $Id: RSA.php,v 1.19 2010/09/12 21:58:54 terrafrost Exp $
  69. * @link http://phpseclib.sourceforge.net
  70. */
  71. /**#@+
  72. * Crypt random global function
  73. *
  74. * @see Crypt/Random.php
  75. */
  76. require_once (__DIR__.DS.'../Crypt/Random.php');
  77. /**#@+
  78. * @access public
  79. * @see Crypt_RSA::encrypt()
  80. * @see Crypt_RSA::decrypt()
  81. */
  82. /**
  83. * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
  84. * (OAEP) for encryption / decryption.
  85. *
  86. * Uses sha1 by default.
  87. *
  88. * @see Crypt_RSA::setHash()
  89. * @see Crypt_RSA::setMGFHash()
  90. */
  91. define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
  92. /**
  93. * Use PKCS#1 padding.
  94. *
  95. * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
  96. * compatability with protocols (like SSH-1) written before OAEP's introduction.
  97. */
  98. define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
  99. /**#@-*/
  100. /**#@+
  101. * @access public
  102. * @see Crypt_RSA::sign()
  103. * @see Crypt_RSA::verify()
  104. * @see Crypt_RSA::setHash()
  105. */
  106. /**
  107. * Use the Probabilistic Signature Scheme for signing
  108. *
  109. * Uses sha1 by default.
  110. *
  111. * @see Crypt_RSA::setSaltLength()
  112. * @see Crypt_RSA::setMGFHash()
  113. */
  114. define('CRYPT_RSA_SIGNATURE_PSS', 1);
  115. /**
  116. * Use the PKCS#1 scheme by default.
  117. *
  118. * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
  119. * compatability with protocols (like SSH-2) written before PSS's introduction.
  120. */
  121. define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
  122. /**#@-*/
  123. /**#@+
  124. * @access private
  125. * @see Crypt_RSA::createKey()
  126. */
  127. /**
  128. * ASN1 Integer
  129. */
  130. define('CRYPT_RSA_ASN1_INTEGER', 2);
  131. /**
  132. * ASN1 Sequence (with the constucted bit set)
  133. */
  134. define('CRYPT_RSA_ASN1_SEQUENCE', 48);
  135. /**#@-*/
  136. /**#@+
  137. * @access private
  138. * @see Crypt_RSA::Crypt_RSA()
  139. */
  140. /**
  141. * To use the pure-PHP implementation
  142. */
  143. define('CRYPT_RSA_MODE_INTERNAL', 1);
  144. /**
  145. * To use the OpenSSL library
  146. *
  147. * (if enabled; otherwise, the internal implementation will be used)
  148. */
  149. define('CRYPT_RSA_MODE_OPENSSL', 2);
  150. /**#@-*/
  151. /**#@+
  152. * @access public
  153. * @see Crypt_RSA::createKey()
  154. * @see Crypt_RSA::setPrivateKeyFormat()
  155. */
  156. /**
  157. * PKCS#1 formatted private key
  158. *
  159. * Used by OpenSSH
  160. */
  161. define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
  162. /**
  163. * PuTTY formatted private key
  164. */
  165. define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
  166. /**
  167. * XML formatted private key
  168. */
  169. define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
  170. /**#@-*/
  171. /**#@+
  172. * @access public
  173. * @see Crypt_RSA::createKey()
  174. * @see Crypt_RSA::setPublicKeyFormat()
  175. */
  176. /**
  177. * Raw public key
  178. *
  179. * An array containing two Math_BigInteger objects.
  180. *
  181. * The exponent can be indexed with any of the following:
  182. *
  183. * 0, e, exponent, publicExponent
  184. *
  185. * The modulus can be indexed with any of the following:
  186. *
  187. * 1, n, modulo, modulus
  188. */
  189. define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
  190. /**
  191. * PKCS#1 formatted public key
  192. */
  193. define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
  194. /**
  195. * XML formatted public key
  196. */
  197. define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
  198. /**
  199. * OpenSSH formatted public key
  200. *
  201. * Place in $HOME/.ssh/authorized_keys
  202. */
  203. define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
  204. /**#@-*/
  205. /**
  206. * Pure-PHP PKCS#1 compliant implementation of RSA.
  207. *
  208. * @author Jim Wigginton <terrafrost@php.net>
  209. * @version 0.1.0
  210. * @access public
  211. * @package Crypt_RSA
  212. */
  213. class Crypt_RSA {
  214. /**
  215. * Precomputed Zero
  216. *
  217. * @var Array
  218. * @access private
  219. */
  220. var $zero;
  221. /**
  222. * Precomputed One
  223. *
  224. * @var Array
  225. * @access private
  226. */
  227. var $one;
  228. /**
  229. * Private Key Format
  230. *
  231. * @var Integer
  232. * @access private
  233. */
  234. var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
  235. /**
  236. * Public Key Format
  237. *
  238. * @var Integer
  239. * @access public
  240. */
  241. var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
  242. /**
  243. * Modulus (ie. n)
  244. *
  245. * @var Math_BigInteger
  246. * @access private
  247. */
  248. var $modulus;
  249. /**
  250. * Modulus length
  251. *
  252. * @var Math_BigInteger
  253. * @access private
  254. */
  255. var $k;
  256. /**
  257. * Exponent (ie. e or d)
  258. *
  259. * @var Math_BigInteger
  260. * @access private
  261. */
  262. var $exponent;
  263. /**
  264. * Primes for Chinese Remainder Theorem (ie. p and q)
  265. *
  266. * @var Array
  267. * @access private
  268. */
  269. var $primes;
  270. /**
  271. * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
  272. *
  273. * @var Array
  274. * @access private
  275. */
  276. var $exponents;
  277. /**
  278. * Coefficients for Chinese Remainder Theorem (ie. qInv)
  279. *
  280. * @var Array
  281. * @access private
  282. */
  283. var $coefficients;
  284. /**
  285. * Hash name
  286. *
  287. * @var String
  288. * @access private
  289. */
  290. var $hashName;
  291. /**
  292. * Hash function
  293. *
  294. * @var Crypt_Hash
  295. * @access private
  296. */
  297. var $hash;
  298. /**
  299. * Length of hash function output
  300. *
  301. * @var Integer
  302. * @access private
  303. */
  304. var $hLen;
  305. /**
  306. * Length of salt
  307. *
  308. * @var Integer
  309. * @access private
  310. */
  311. var $sLen;
  312. /**
  313. * Hash function for the Mask Generation Function
  314. *
  315. * @var Crypt_Hash
  316. * @access private
  317. */
  318. var $mgfHash;
  319. /**
  320. * Length of MGF hash function output
  321. *
  322. * @var Integer
  323. * @access private
  324. */
  325. var $mgfHLen;
  326. /**
  327. * Encryption mode
  328. *
  329. * @var Integer
  330. * @access private
  331. */
  332. var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
  333. /**
  334. * Signature mode
  335. *
  336. * @var Integer
  337. * @access private
  338. */
  339. var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
  340. /**
  341. * Public Exponent
  342. *
  343. * @var Mixed
  344. * @access private
  345. */
  346. var $publicExponent = false;
  347. /**
  348. * Password
  349. *
  350. * @var String
  351. * @access private
  352. */
  353. var $password = '';
  354. /**
  355. * Components
  356. *
  357. * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
  358. * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
  359. *
  360. * @see Crypt_RSA::_start_element_handler()
  361. * @var Array
  362. * @access private
  363. */
  364. var $components = array();
  365. /**
  366. * Current String
  367. *
  368. * For use with parsing XML formatted keys.
  369. *
  370. * @see Crypt_RSA::_character_handler()
  371. * @see Crypt_RSA::_stop_element_handler()
  372. * @var Mixed
  373. * @access private
  374. */
  375. var $current;
  376. /**
  377. * The constructor
  378. *
  379. * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
  380. * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
  381. * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
  382. *
  383. * @return Crypt_RSA
  384. * @access public
  385. */
  386. function __construct()
  387. {
  388. if ( !defined('CRYPT_RSA_MODE') ) {
  389. switch (true) {
  390. //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
  391. // define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
  392. // break;
  393. default:
  394. define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
  395. }
  396. }
  397. $this->zero = new Math_BigInteger();
  398. $this->one = new Math_BigInteger(1);
  399. $this->hash = new Crypt_Hash('sha1');
  400. $this->hLen = $this->hash->getLength();
  401. $this->hashName = 'sha1';
  402. $this->mgfHash = new Crypt_Hash('sha1');
  403. $this->mgfHLen = $this->mgfHash->getLength();
  404. }
  405. /**
  406. * Create public / private key pair
  407. *
  408. * Returns an array with the following three elements:
  409. * - 'privatekey': The private key.
  410. * - 'publickey': The public key.
  411. * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
  412. * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
  413. *
  414. * @access public
  415. * @param optional Integer $bits
  416. * @param optional Integer $timeout
  417. * @param optional Math_BigInteger $p
  418. */
  419. function createKey($bits = 1024, $timeout = false, $partial = array())
  420. {
  421. if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
  422. $rsa = openssl_pkey_new(array('private_key_bits' => $bits));
  423. openssl_pkey_export($rsa, $privatekey);
  424. $publickey = openssl_pkey_get_details($rsa);
  425. $publickey = $publickey['key'];
  426. if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) {
  427. $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
  428. $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
  429. }
  430. return array(
  431. 'privatekey' => $privatekey,
  432. 'publickey' => $publickey,
  433. 'partialkey' => false
  434. );
  435. }
  436. static $e;
  437. if (!isset($e)) {
  438. if (!defined('CRYPT_RSA_EXPONENT')) {
  439. // http://en.wikipedia.org/wiki/65537_%28number%29
  440. define('CRYPT_RSA_EXPONENT', '65537');
  441. }
  442. if (!defined('CRYPT_RSA_COMMENT')) {
  443. define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key');
  444. }
  445. // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
  446. // than 256 bits.
  447. if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
  448. define('CRYPT_RSA_SMALLEST_PRIME', 4096);
  449. }
  450. $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
  451. }
  452. extract($this->_generateMinMax($bits));
  453. $absoluteMin = $min;
  454. $temp = $bits >> 1;
  455. if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
  456. $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
  457. $temp = CRYPT_RSA_SMALLEST_PRIME;
  458. } else {
  459. $num_primes = 2;
  460. }
  461. extract($this->_generateMinMax($temp + $bits % $temp));
  462. $finalMax = $max;
  463. extract($this->_generateMinMax($temp));
  464. $generator = new Math_BigInteger();
  465. $generator->setRandomGenerator('crypt_random');
  466. $n = $this->one->copy();
  467. if (!empty($partial)) {
  468. extract(unserialize($partial));
  469. } else {
  470. $exponents = $coefficients = $primes = array();
  471. $lcm = array(
  472. 'top' => $this->one->copy(),
  473. 'bottom' => false
  474. );
  475. }
  476. $start = time();
  477. $i0 = count($primes) + 1;
  478. do {
  479. for ($i = $i0; $i <= $num_primes; $i++) {
  480. if ($timeout !== false) {
  481. $timeout-= time() - $start;
  482. $start = time();
  483. if ($timeout <= 0) {
  484. return array(
  485. 'privatekey' => '',
  486. 'publickey' => '',
  487. 'partialkey' => serialize(array(
  488. 'primes' => $primes,
  489. 'coefficients' => $coefficients,
  490. 'lcm' => $lcm,
  491. 'exponents' => $exponents
  492. ))
  493. );
  494. }
  495. }
  496. if ($i == $num_primes) {
  497. list($min, $temp) = $absoluteMin->divide($n);
  498. if (!$temp->equals($this->zero)) {
  499. $min = $min->add($this->one); // ie. ceil()
  500. }
  501. $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
  502. } else {
  503. $primes[$i] = $generator->randomPrime($min, $max, $timeout);
  504. }
  505. if ($primes[$i] === false) { // if we've reached the timeout
  506. if (count($primes) > 1) {
  507. $partialkey = '';
  508. } else {
  509. array_pop($primes);
  510. $partialkey = serialize(array(
  511. 'primes' => $primes,
  512. 'coefficients' => $coefficients,
  513. 'lcm' => $lcm,
  514. 'exponents' => $exponents
  515. ));
  516. }
  517. return array(
  518. 'privatekey' => '',
  519. 'publickey' => '',
  520. 'partialkey' => $partialkey
  521. );
  522. }
  523. // the first coefficient is calculated differently from the rest
  524. // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
  525. if ($i > 2) {
  526. $coefficients[$i] = $n->modInverse($primes[$i]);
  527. }
  528. $n = $n->multiply($primes[$i]);
  529. $temp = $primes[$i]->subtract($this->one);
  530. // textbook RSA implementations use Euler's totient function instead of the least common multiple.
  531. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
  532. $lcm['top'] = $lcm['top']->multiply($temp);
  533. $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
  534. $exponents[$i] = $e->modInverse($temp);
  535. }
  536. list($lcm) = $lcm['top']->divide($lcm['bottom']);
  537. $gcd = $lcm->gcd($e);
  538. $i0 = 1;
  539. } while (!$gcd->equals($this->one));
  540. $d = $e->modInverse($lcm);
  541. $coefficients[2] = $primes[2]->modInverse($primes[1]);
  542. // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
  543. // RSAPrivateKey ::= SEQUENCE {
  544. // version Version,
  545. // modulus INTEGER, -- n
  546. // publicExponent INTEGER, -- e
  547. // privateExponent INTEGER, -- d
  548. // prime1 INTEGER, -- p
  549. // prime2 INTEGER, -- q
  550. // exponent1 INTEGER, -- d mod (p-1)
  551. // exponent2 INTEGER, -- d mod (q-1)
  552. // coefficient INTEGER, -- (inverse of q) mod p
  553. // otherPrimeInfos OtherPrimeInfos OPTIONAL
  554. // }
  555. return array(
  556. 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
  557. 'publickey' => $this->_convertPublicKey($n, $e),
  558. 'partialkey' => false
  559. );
  560. }
  561. /**
  562. * Convert a private key to the appropriate format.
  563. *
  564. * @access private
  565. * @see setPrivateKeyFormat()
  566. * @param String $RSAPrivateKey
  567. * @return String
  568. */
  569. function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
  570. {
  571. $num_primes = count($primes);
  572. $raw = array(
  573. 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
  574. 'modulus' => $n->toBytes(true),
  575. 'publicExponent' => $e->toBytes(true),
  576. 'privateExponent' => $d->toBytes(true),
  577. 'prime1' => $primes[1]->toBytes(true),
  578. 'prime2' => $primes[2]->toBytes(true),
  579. 'exponent1' => $exponents[1]->toBytes(true),
  580. 'exponent2' => $exponents[2]->toBytes(true),
  581. 'coefficient' => $coefficients[2]->toBytes(true)
  582. );
  583. // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
  584. // call _convertPublicKey() instead.
  585. switch ($this->privateKeyFormat) {
  586. default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
  587. $components = array();
  588. foreach ($raw as $name => $value) {
  589. $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
  590. }
  591. $RSAPrivateKey = implode('', $components);
  592. if ($num_primes > 2) {
  593. $OtherPrimeInfos = '';
  594. for ($i = 3; $i <= $num_primes; $i++) {
  595. // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
  596. //
  597. // OtherPrimeInfo ::= SEQUENCE {
  598. // prime INTEGER, -- ri
  599. // exponent INTEGER, -- di
  600. // coefficient INTEGER -- ti
  601. // }
  602. $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
  603. $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
  604. $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
  605. $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
  606. }
  607. $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
  608. }
  609. $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
  610. if (!empty($this->password)) {
  611. $iv = $this->_random(8);
  612. $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
  613. $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
  614. $des = new Crypt_TripleDES();
  615. $des->setKey($symkey);
  616. $des->setIV($iv);
  617. $iv = strtoupper(bin2hex($iv));
  618. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  619. "Proc-Type: 4,ENCRYPTED\r\n" .
  620. "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
  621. "\r\n" .
  622. chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) .
  623. '-----END RSA PRIVATE KEY-----';
  624. } else {
  625. $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
  626. chunk_split(base64_encode($RSAPrivateKey)) .
  627. '-----END RSA PRIVATE KEY-----';
  628. }
  629. return $RSAPrivateKey;
  630. }
  631. }
  632. /**
  633. * Convert a public key to the appropriate format
  634. *
  635. * @access private
  636. * @see setPublicKeyFormat()
  637. * @param String $RSAPrivateKey
  638. * @return String
  639. */
  640. function _convertPublicKey($n, $e)
  641. {
  642. $modulus = $n->toBytes(true);
  643. $publicExponent = $e->toBytes(true);
  644. switch ($this->publicKeyFormat) {
  645. case CRYPT_RSA_PUBLIC_FORMAT_RAW:
  646. return array('e' => $e->copy(), 'n' => $n->copy());
  647. case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
  648. // from <http://tools.ietf.org/html/rfc4253#page-15>:
  649. // string "ssh-rsa"
  650. // mpint e
  651. // mpint n
  652. $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
  653. $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
  654. return $RSAPublicKey;
  655. default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1
  656. // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
  657. // RSAPublicKey ::= SEQUENCE {
  658. // modulus INTEGER, -- n
  659. // publicExponent INTEGER -- e
  660. // }
  661. $components = array(
  662. 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
  663. 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
  664. );
  665. $RSAPublicKey = pack('Ca*a*a*',
  666. CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
  667. $components['modulus'], $components['publicExponent']
  668. );
  669. $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
  670. chunk_split(base64_encode($RSAPublicKey)) .
  671. '-----END PUBLIC KEY-----';
  672. return $RSAPublicKey;
  673. }
  674. }
  675. /**
  676. * Break a public or private key down into its constituant components
  677. *
  678. * @access private
  679. * @see _convertPublicKey()
  680. * @see _convertPrivateKey()
  681. * @param String $key
  682. * @param Integer $type
  683. * @return Array
  684. */
  685. function _parseKey($key, $type)
  686. {
  687. switch ($type) {
  688. case CRYPT_RSA_PUBLIC_FORMAT_RAW:
  689. if (!is_array($key)) {
  690. return false;
  691. }
  692. $components = array();
  693. switch (true) {
  694. case isset($key['e']):
  695. $components['publicExponent'] = $key['e']->copy();
  696. break;
  697. case isset($key['exponent']):
  698. $components['publicExponent'] = $key['exponent']->copy();
  699. break;
  700. case isset($key['publicExponent']):
  701. $components['publicExponent'] = $key['publicExponent']->copy();
  702. break;
  703. case isset($key[0]):
  704. $components['publicExponent'] = $key[0]->copy();
  705. }
  706. switch (true) {
  707. case isset($key['n']):
  708. $components['modulus'] = $key['n']->copy();
  709. break;
  710. case isset($key['modulo']):
  711. $components['modulus'] = $key['modulo']->copy();
  712. break;
  713. case isset($key['modulus']):
  714. $components['modulus'] = $key['modulus']->copy();
  715. break;
  716. case isset($key[1]):
  717. $components['modulus'] = $key[1]->copy();
  718. }
  719. return $components;
  720. case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
  721. case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
  722. /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
  723. "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
  724. protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
  725. two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
  726. http://tools.ietf.org/html/rfc1421#section-4.6.1.1
  727. http://tools.ietf.org/html/rfc1421#section-4.6.1.3
  728. DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
  729. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
  730. function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
  731. own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
  732. implementation are part of the standard, as well.
  733. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
  734. if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
  735. $iv = pack('H*', trim($matches[2]));
  736. $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
  737. $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
  738. $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
  739. $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
  740. if ($ciphertext === false) {
  741. $ciphertext = $key;
  742. }
  743. switch ($matches[1]) {
  744. case 'AES-128-CBC':
  745. $symkey = substr($symkey, 0, 16);
  746. $crypto = new Crypt_AES();
  747. break;
  748. case 'DES-EDE3-CFB':
  749. $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
  750. break;
  751. case 'DES-EDE3-CBC':
  752. $crypto = new Crypt_TripleDES();
  753. break;
  754. case 'DES-CBC':
  755. $crypto = new Crypt_DES();
  756. break;
  757. default:
  758. return false;
  759. }
  760. $crypto->setKey($symkey);
  761. $crypto->setIV($iv);
  762. $decoded = $crypto->decrypt($ciphertext);
  763. } else {
  764. $decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
  765. $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
  766. }
  767. if ($decoded !== false) {
  768. $key = $decoded;
  769. }
  770. $components = array();
  771. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  772. return false;
  773. }
  774. if ($this->_decodeLength($key) != strlen($key)) {
  775. return false;
  776. }
  777. $tag = ord($this->_string_shift($key));
  778. if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
  779. /* intended for keys for which OpenSSL's asn1parse returns the following:
  780. 0:d=0 hl=4 l= 290 cons: SEQUENCE
  781. 4:d=1 hl=2 l= 13 cons: SEQUENCE
  782. 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
  783. 17:d=2 hl=2 l= 0 prim: NULL
  784. 19:d=1 hl=4 l= 271 prim: BIT STRING */
  785. $this->_string_shift($key, $this->_decodeLength($key));
  786. $this->_string_shift($key); // skip over the BIT STRING tag
  787. $this->_decodeLength($key); // skip over the BIT STRING length
  788. // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
  789. // unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
  790. // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
  791. $this->_string_shift($key);
  792. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  793. return false;
  794. }
  795. if ($this->_decodeLength($key) != strlen($key)) {
  796. return false;
  797. }
  798. $tag = ord($this->_string_shift($key));
  799. }
  800. if ($tag != CRYPT_RSA_ASN1_INTEGER) {
  801. return false;
  802. }
  803. $length = $this->_decodeLength($key);
  804. $temp = $this->_string_shift($key, $length);
  805. if (strlen($temp) != 1 || ord($temp) > 2) {
  806. $components['modulus'] = new Math_BigInteger($temp, -256);
  807. $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
  808. $length = $this->_decodeLength($key);
  809. $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  810. return $components;
  811. }
  812. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
  813. return false;
  814. }
  815. $length = $this->_decodeLength($key);
  816. $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  817. $this->_string_shift($key);
  818. $length = $this->_decodeLength($key);
  819. $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  820. $this->_string_shift($key);
  821. $length = $this->_decodeLength($key);
  822. $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  823. $this->_string_shift($key);
  824. $length = $this->_decodeLength($key);
  825. $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
  826. $this->_string_shift($key);
  827. $length = $this->_decodeLength($key);
  828. $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  829. $this->_string_shift($key);
  830. $length = $this->_decodeLength($key);
  831. $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
  832. $this->_string_shift($key);
  833. $length = $this->_decodeLength($key);
  834. $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  835. $this->_string_shift($key);
  836. $length = $this->_decodeLength($key);
  837. $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
  838. if (!empty($key)) {
  839. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  840. return false;
  841. }
  842. $this->_decodeLength($key);
  843. while (!empty($key)) {
  844. if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
  845. return false;
  846. }
  847. $this->_decodeLength($key);
  848. $key = substr($key, 1);
  849. $length = $this->_decodeLength($key);
  850. $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  851. $this->_string_shift($key);
  852. $length = $this->_decodeLength($key);
  853. $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  854. $this->_string_shift($key);
  855. $length = $this->_decodeLength($key);
  856. $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
  857. }
  858. }
  859. return $components;
  860. case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
  861. $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key));
  862. if ($key === false) {
  863. return false;
  864. }
  865. $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
  866. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  867. $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
  868. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  869. $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
  870. if ($cleanup && strlen($key)) {
  871. extract(unpack('Nlength', $this->_string_shift($key, 4)));
  872. return array(
  873. 'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
  874. 'publicExponent' => $modulus
  875. );
  876. } else {
  877. return array(
  878. 'modulus' => $modulus,
  879. 'publicExponent' => $publicExponent
  880. );
  881. }
  882. // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
  883. // http://en.wikipedia.org/wiki/XML_Signature
  884. case CRYPT_RSA_PRIVATE_FORMAT_XML:
  885. case CRYPT_RSA_PUBLIC_FORMAT_XML:
  886. $this->components = array();
  887. $xml = xml_parser_create('UTF-8');
  888. xml_set_object($xml, $this);
  889. xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
  890. xml_set_character_data_handler($xml, '_data_handler');
  891. if (!xml_parse($xml, $key)) {
  892. return false;
  893. }
  894. return $this->components;
  895. // from PuTTY's SSHPUBK.C
  896. case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
  897. $components = array();
  898. $key = preg_split('#\r\n|\r|\n#', $key);
  899. $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
  900. if ($type != 'ssh-rsa') {
  901. return false;
  902. }
  903. $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
  904. $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
  905. $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
  906. $public = substr($public, 11);
  907. extract(unpack('Nlength', $this->_string_shift($public, 4)));
  908. $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
  909. extract(unpack('Nlength', $this->_string_shift($public, 4)));
  910. $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
  911. $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
  912. $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
  913. switch ($encryption) {
  914. case 'aes256-cbc':
  915. $symkey = '';
  916. $sequence = 0;
  917. while (strlen($symkey) < 32) {
  918. $temp = pack('Na*', $sequence++, $this->password);
  919. $symkey.= pack('H*', sha1($temp));
  920. }
  921. $symkey = substr($symkey, 0, 32);
  922. $crypto = new Crypt_AES();
  923. }
  924. if ($encryption != 'none') {
  925. $crypto->setKey($symkey);
  926. $crypto->disablePadding();
  927. $private = $crypto->decrypt($private);
  928. if ($private === false) {
  929. return false;
  930. }
  931. }
  932. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  933. $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
  934. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  935. $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
  936. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  937. $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
  938. $temp = $components['primes'][1]->subtract($this->one);
  939. $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
  940. $temp = $components['primes'][2]->subtract($this->one);
  941. $components['exponents'][] = $components['publicExponent']->modInverse($temp);
  942. extract(unpack('Nlength', $this->_string_shift($private, 4)));
  943. $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
  944. return $components;
  945. }
  946. }
  947. /**
  948. * Start Element Handler
  949. *
  950. * Called by xml_set_element_handler()
  951. *
  952. * @access private
  953. * @param Resource $parser
  954. * @param String $name
  955. * @param Array $attribs
  956. */
  957. function _start_element_handler($parser, $name, $attribs)
  958. {
  959. //$name = strtoupper($name);
  960. switch ($name) {
  961. case 'MODULUS':
  962. $this->current = &$this->components['modulus'];
  963. break;
  964. case 'EXPONENT':
  965. $this->current = &$this->components['publicExponent'];
  966. break;
  967. case 'P':
  968. $this->current = &$this->components['primes'][1];
  969. break;
  970. case 'Q':
  971. $this->current = &$this->components['primes'][2];
  972. break;
  973. case 'DP':
  974. $this->current = &$this->components['exponents'][1];
  975. break;
  976. case 'DQ':
  977. $this->current = &$this->components['exponents'][2];
  978. break;
  979. case 'INVERSEQ':
  980. $this->current = &$this->components['coefficients'][2];
  981. break;
  982. case 'D':
  983. $this->current = &$this->components['privateExponent'];
  984. break;
  985. default:
  986. unset($this->current);
  987. }
  988. $this->current = '';
  989. }
  990. /**
  991. * Stop Element Handler
  992. *
  993. * Called by xml_set_element_handler()
  994. *
  995. * @access private
  996. * @param Resource $parser
  997. * @param String $name
  998. */
  999. function _stop_element_handler($parser, $name)
  1000. {
  1001. //$name = strtoupper($name);
  1002. if ($name == 'RSAKEYVALUE') {
  1003. return;
  1004. }
  1005. $this->current = new Math_BigInteger(base64_decode($this->current), 256);
  1006. }
  1007. /**
  1008. * Data Handler
  1009. *
  1010. * Called by xml_set_character_data_handler()
  1011. *
  1012. * @access private
  1013. * @param Resource $parser
  1014. * @param String $data
  1015. */
  1016. function _data_handler($parser, $data)
  1017. {
  1018. if (!isset($this->current) || is_object($this->current)) {
  1019. return;
  1020. }
  1021. $this->current.= trim($data);
  1022. }
  1023. /**
  1024. * Loads a public or private key
  1025. *
  1026. * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
  1027. *
  1028. * @access public
  1029. * @param String $key
  1030. * @param Integer $type optional
  1031. */
  1032. function loadKey($key, $type = false)
  1033. {
  1034. if ($type === false) {
  1035. $types = array(
  1036. CRYPT_RSA_PUBLIC_FORMAT_RAW,
  1037. CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
  1038. CRYPT_RSA_PRIVATE_FORMAT_XML,
  1039. CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
  1040. CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
  1041. );
  1042. foreach ($types as $type) {
  1043. $components = $this->_parseKey($key, $type);
  1044. if ($components !== false) {
  1045. break;
  1046. }
  1047. }
  1048. } else {
  1049. $components = $this->_parseKey($key, $type);
  1050. }
  1051. if ($components === false) {
  1052. return false;
  1053. }
  1054. $this->modulus = $components['modulus'];
  1055. $this->k = strlen($this->modulus->toBytes());
  1056. $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
  1057. if (isset($components['primes'])) {
  1058. $this->primes = $components['primes'];
  1059. $this->exponents = $components['exponents'];
  1060. $this->coefficients = $components['coefficients'];
  1061. $this->publicExponent = $components['publicExponent'];
  1062. } else {
  1063. $this->primes = array();
  1064. $this->exponents = array();
  1065. $this->coefficients = array();
  1066. $this->publicExponent = false;
  1067. }
  1068. return true;
  1069. }
  1070. /**
  1071. * Sets the password
  1072. *
  1073. * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
  1074. * Or rather, pass in $password such that empty($password) is true.
  1075. *
  1076. * @see createKey()
  1077. * @see loadKey()
  1078. * @access public
  1079. * @param String $password
  1080. */
  1081. function setPassword($password)
  1082. {
  1083. $this->password = $password;
  1084. }
  1085. /**
  1086. * Defines the public key
  1087. *
  1088. * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
  1089. * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
  1090. * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
  1091. * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
  1092. * exponent this won't work unless you manually add the public exponent.
  1093. *
  1094. * Do note that when a new key is loaded the index will be cleared.
  1095. *
  1096. * Returns true on success, false on failure
  1097. *
  1098. * @see getPublicKey()
  1099. * @access public
  1100. * @param String $key
  1101. * @param Integer $type optional
  1102. * @return Boolean
  1103. */
  1104. function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
  1105. {
  1106. $components = $this->_parseKey($key, $type);
  1107. if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
  1108. user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE);
  1109. return false;
  1110. }
  1111. $this->publicExponent = $components['publicExponent'];
  1112. return true;
  1113. }
  1114. /**
  1115. * Returns the public key
  1116. *
  1117. * The public key is only returned under two circumstances - if the private key had the public key embedded within it
  1118. * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
  1119. * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
  1120. *
  1121. * @see getPublicKey()
  1122. * @access public
  1123. * @param String $key
  1124. * @param Integer $type optional
  1125. */
  1126. function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
  1127. {
  1128. if (empty($this->modulus) || empty($this->publicExponent)) {
  1129. return false;
  1130. }
  1131. $oldFormat = $this->publicKeyFormat;
  1132. $this->publicKeyFormat = $type;
  1133. $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
  1134. $this->publicKeyFormat = $oldFormat;
  1135. return $temp;
  1136. }
  1137. /**
  1138. * Generates the smallest and largest numbers requiring $bits bits
  1139. *
  1140. * @access private
  1141. * @param Integer $bits
  1142. * @return Array
  1143. */
  1144. function _generateMinMax($bits)
  1145. {
  1146. $bytes = $bits >> 3;
  1147. $min = str_repeat(chr(0), $bytes);
  1148. $max = str_repeat(chr(0xFF), $bytes);
  1149. $msb = $bits & 7;
  1150. if ($msb) {
  1151. $min = chr(1 << ($msb - 1)) . $min;
  1152. $max = chr((1 << $msb) - 1) . $max;
  1153. } else {
  1154. $min[0] = chr(0x80);
  1155. }
  1156. return array(
  1157. 'min' => new Math_BigInteger($min, 256),
  1158. 'max' => new Math_BigInteger($max, 256)
  1159. );
  1160. }
  1161. /**
  1162. * DER-decode the length
  1163. *
  1164. * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
  1165. * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information.
  1166. *
  1167. * @access private
  1168. * @param String $string
  1169. * @return Integer
  1170. */
  1171. function _decodeLength(&$string)
  1172. {
  1173. $length = ord($this->_string_shift($string));
  1174. if ( $length & 0x80 ) { // definite length, long form
  1175. $length&= 0x7F;
  1176. $temp = $this->_string_shift($string, $length);
  1177. list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
  1178. }
  1179. return $length;
  1180. }
  1181. /**
  1182. * DER-encode the length
  1183. *
  1184. * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
  1185. * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information.
  1186. *
  1187. * @access private
  1188. * @param Integer $length
  1189. * @return String
  1190. */
  1191. function _encodeLength($length)
  1192. {
  1193. if ($length <= 0x7F) {
  1194. return chr($length);
  1195. }
  1196. $temp = ltrim(pack('N', $length), chr(0));
  1197. return pack('Ca*', 0x80 | strlen($temp), $temp);
  1198. }
  1199. /**
  1200. * String Shift
  1201. *
  1202. * Inspired by array_shift
  1203. *
  1204. * @param String $string
  1205. * @param optional Integer $index
  1206. * @return String
  1207. * @access private
  1208. */
  1209. function _string_shift(&$string, $index = 1)
  1210. {
  1211. $substr = substr($string, 0, $index);
  1212. $string = substr($string, $index);
  1213. return $substr;
  1214. }
  1215. /**
  1216. * Determines the private key format
  1217. *
  1218. * @see createKey()
  1219. * @access public
  1220. * @param Integer $format
  1221. */
  1222. function setPrivateKeyFormat($format)
  1223. {
  1224. $this->privateKeyFormat = $format;
  1225. }
  1226. /**
  1227. * Determines the public key format
  1228. *
  1229. * @see createKey()
  1230. * @access public
  1231. * @param Integer $format
  1232. */
  1233. function setPublicKeyFormat($format)
  1234. {
  1235. $this->publicKeyFormat = $format;
  1236. }
  1237. /**
  1238. * Determines which hashing function should be used
  1239. *
  1240. * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
  1241. * decryption. If $hash isn't supported, sha1 is used.
  1242. *
  1243. * @access public
  1244. * @param String $hash
  1245. */
  1246. function setHash($hash)
  1247. {
  1248. // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
  1249. switch ($hash) {
  1250. case 'md2':
  1251. case 'md5':
  1252. case 'sha1':
  1253. case 'sha256':
  1254. case 'sha384':
  1255. case 'sha512':
  1256. $this->hash = new Crypt_Hash($hash);
  1257. $this->hashName = $hash;
  1258. break;
  1259. default:
  1260. $this->hash = new Crypt_Hash('sha1');
  1261. $this->hashName = 'sha1';
  1262. }
  1263. $this->hLen = $this->hash->getLength();
  1264. }
  1265. /**
  1266. * Determines which hashing function should be used for the mask generation function
  1267. *
  1268. * The mask generation function is used …

Large files files are truncated, but you can click here to view the full file