PageRenderTime 38ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php

https://github.com/sezuan/core
PHP | 1080 lines | 655 code | 71 blank | 354 comment | 130 complexity | e3836460d9f77b0fe045ebb11e75c80b MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Pure-PHP implementation of Triple DES.
  5. *
  6. * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * Here's a short example of how to use this library:
  11. * <code>
  12. * <?php
  13. * include('Crypt/TripleDES.php');
  14. *
  15. * $des = new Crypt_TripleDES();
  16. *
  17. * $des->setKey('abcdefghijklmnopqrstuvwx');
  18. *
  19. * $size = 10 * 1024;
  20. * $plaintext = '';
  21. * for ($i = 0; $i < $size; $i++) {
  22. * $plaintext.= 'a';
  23. * }
  24. *
  25. * echo $des->decrypt($des->encrypt($plaintext));
  26. * ?>
  27. * </code>
  28. *
  29. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  30. * of this software and associated documentation files (the "Software"), to deal
  31. * in the Software without restriction, including without limitation the rights
  32. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  33. * copies of the Software, and to permit persons to whom the Software is
  34. * furnished to do so, subject to the following conditions:
  35. *
  36. * The above copyright notice and this permission notice shall be included in
  37. * all copies or substantial portions of the Software.
  38. *
  39. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  40. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  41. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  42. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  43. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  44. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  45. * THE SOFTWARE.
  46. *
  47. * @category Crypt
  48. * @package Crypt_TripleDES
  49. * @author Jim Wigginton <terrafrost@php.net>
  50. * @copyright MMVII Jim Wigginton
  51. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  52. * @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $
  53. * @link http://phpseclib.sourceforge.net
  54. */
  55. /**
  56. * Include Crypt_DES
  57. */
  58. if (!class_exists('Crypt_DES')) {
  59. require_once('DES.php');
  60. }
  61. /**
  62. * Encrypt / decrypt using inner chaining
  63. *
  64. * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
  65. */
  66. define('CRYPT_DES_MODE_3CBC', -2);
  67. /**
  68. * Encrypt / decrypt using outer chaining
  69. *
  70. * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
  71. */
  72. define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
  73. /**
  74. * Pure-PHP implementation of Triple DES.
  75. *
  76. * @author Jim Wigginton <terrafrost@php.net>
  77. * @version 0.1.0
  78. * @access public
  79. * @package Crypt_TerraDES
  80. */
  81. class Crypt_TripleDES {
  82. /**
  83. * The Three Keys
  84. *
  85. * @see Crypt_TripleDES::setKey()
  86. * @var String
  87. * @access private
  88. */
  89. var $key = "\0\0\0\0\0\0\0\0";
  90. /**
  91. * The Encryption Mode
  92. *
  93. * @see Crypt_TripleDES::Crypt_TripleDES()
  94. * @var Integer
  95. * @access private
  96. */
  97. var $mode = CRYPT_DES_MODE_CBC;
  98. /**
  99. * Continuous Buffer status
  100. *
  101. * @see Crypt_TripleDES::enableContinuousBuffer()
  102. * @var Boolean
  103. * @access private
  104. */
  105. var $continuousBuffer = false;
  106. /**
  107. * Padding status
  108. *
  109. * @see Crypt_TripleDES::enablePadding()
  110. * @var Boolean
  111. * @access private
  112. */
  113. var $padding = true;
  114. /**
  115. * The Initialization Vector
  116. *
  117. * @see Crypt_TripleDES::setIV()
  118. * @var String
  119. * @access private
  120. */
  121. var $iv = "\0\0\0\0\0\0\0\0";
  122. /**
  123. * A "sliding" Initialization Vector
  124. *
  125. * @see Crypt_TripleDES::enableContinuousBuffer()
  126. * @var String
  127. * @access private
  128. */
  129. var $encryptIV = "\0\0\0\0\0\0\0\0";
  130. /**
  131. * A "sliding" Initialization Vector
  132. *
  133. * @see Crypt_TripleDES::enableContinuousBuffer()
  134. * @var String
  135. * @access private
  136. */
  137. var $decryptIV = "\0\0\0\0\0\0\0\0";
  138. /**
  139. * The Crypt_DES objects
  140. *
  141. * @var Array
  142. * @access private
  143. */
  144. var $des;
  145. /**
  146. * mcrypt resource for encryption
  147. *
  148. * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
  149. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
  150. *
  151. * @see Crypt_TripleDES::encrypt()
  152. * @var String
  153. * @access private
  154. */
  155. var $enmcrypt;
  156. /**
  157. * mcrypt resource for decryption
  158. *
  159. * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
  160. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
  161. *
  162. * @see Crypt_TripleDES::decrypt()
  163. * @var String
  164. * @access private
  165. */
  166. var $demcrypt;
  167. /**
  168. * Does the enmcrypt resource need to be (re)initialized?
  169. *
  170. * @see Crypt_TripleDES::setKey()
  171. * @see Crypt_TripleDES::setIV()
  172. * @var Boolean
  173. * @access private
  174. */
  175. var $enchanged = true;
  176. /**
  177. * Does the demcrypt resource need to be (re)initialized?
  178. *
  179. * @see Crypt_TripleDES::setKey()
  180. * @see Crypt_TripleDES::setIV()
  181. * @var Boolean
  182. * @access private
  183. */
  184. var $dechanged = true;
  185. /**
  186. * Is the mode one that is paddable?
  187. *
  188. * @see Crypt_TripleDES::Crypt_TripleDES()
  189. * @var Boolean
  190. * @access private
  191. */
  192. var $paddable = false;
  193. /**
  194. * Encryption buffer for CTR, OFB and CFB modes
  195. *
  196. * @see Crypt_TripleDES::encrypt()
  197. * @var Array
  198. * @access private
  199. */
  200. var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
  201. /**
  202. * Decryption buffer for CTR, OFB and CFB modes
  203. *
  204. * @see Crypt_TripleDES::decrypt()
  205. * @var Array
  206. * @access private
  207. */
  208. var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
  209. /**
  210. * mcrypt resource for CFB mode
  211. *
  212. * @see Crypt_TripleDES::encrypt()
  213. * @see Crypt_TripleDES::decrypt()
  214. * @var String
  215. * @access private
  216. */
  217. var $ecb;
  218. /**
  219. * Default Constructor.
  220. *
  221. * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
  222. * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
  223. *
  224. * @param optional Integer $mode
  225. * @return Crypt_TripleDES
  226. * @access public
  227. */
  228. function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
  229. {
  230. if ( !defined('CRYPT_DES_MODE') ) {
  231. switch (true) {
  232. case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
  233. define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
  234. break;
  235. default:
  236. define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
  237. }
  238. }
  239. if ( $mode == CRYPT_DES_MODE_3CBC ) {
  240. $this->mode = CRYPT_DES_MODE_3CBC;
  241. $this->des = array(
  242. new Crypt_DES(CRYPT_DES_MODE_CBC),
  243. new Crypt_DES(CRYPT_DES_MODE_CBC),
  244. new Crypt_DES(CRYPT_DES_MODE_CBC)
  245. );
  246. $this->paddable = true;
  247. // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
  248. $this->des[0]->disablePadding();
  249. $this->des[1]->disablePadding();
  250. $this->des[2]->disablePadding();
  251. return;
  252. }
  253. switch ( CRYPT_DES_MODE ) {
  254. case CRYPT_DES_MODE_MCRYPT:
  255. switch ($mode) {
  256. case CRYPT_DES_MODE_ECB:
  257. $this->paddable = true;
  258. $this->mode = MCRYPT_MODE_ECB;
  259. break;
  260. case CRYPT_DES_MODE_CTR:
  261. $this->mode = 'ctr';
  262. break;
  263. case CRYPT_DES_MODE_CFB:
  264. $this->mode = 'ncfb';
  265. $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
  266. break;
  267. case CRYPT_DES_MODE_OFB:
  268. $this->mode = MCRYPT_MODE_NOFB;
  269. break;
  270. case CRYPT_DES_MODE_CBC:
  271. default:
  272. $this->paddable = true;
  273. $this->mode = MCRYPT_MODE_CBC;
  274. }
  275. $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
  276. $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
  277. break;
  278. default:
  279. $this->des = array(
  280. new Crypt_DES(CRYPT_DES_MODE_ECB),
  281. new Crypt_DES(CRYPT_DES_MODE_ECB),
  282. new Crypt_DES(CRYPT_DES_MODE_ECB)
  283. );
  284. // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
  285. $this->des[0]->disablePadding();
  286. $this->des[1]->disablePadding();
  287. $this->des[2]->disablePadding();
  288. switch ($mode) {
  289. case CRYPT_DES_MODE_ECB:
  290. case CRYPT_DES_MODE_CBC:
  291. $this->paddable = true;
  292. $this->mode = $mode;
  293. break;
  294. case CRYPT_DES_MODE_CTR:
  295. case CRYPT_DES_MODE_CFB:
  296. case CRYPT_DES_MODE_OFB:
  297. $this->mode = $mode;
  298. break;
  299. default:
  300. $this->paddable = true;
  301. $this->mode = CRYPT_DES_MODE_CBC;
  302. }
  303. }
  304. }
  305. /**
  306. * Sets the key.
  307. *
  308. * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
  309. * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
  310. *
  311. * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
  312. *
  313. * If the key is not explicitly set, it'll be assumed to be all zero's.
  314. *
  315. * @access public
  316. * @param String $key
  317. */
  318. function setKey($key)
  319. {
  320. $length = strlen($key);
  321. if ($length > 8) {
  322. $key = str_pad($key, 24, chr(0));
  323. // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
  324. // http://php.net/function.mcrypt-encrypt#47973
  325. //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
  326. } else {
  327. $key = str_pad($key, 8, chr(0));
  328. }
  329. $this->key = $key;
  330. switch (true) {
  331. case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
  332. case $this->mode == CRYPT_DES_MODE_3CBC:
  333. $this->des[0]->setKey(substr($key, 0, 8));
  334. $this->des[1]->setKey(substr($key, 8, 8));
  335. $this->des[2]->setKey(substr($key, 16, 8));
  336. }
  337. $this->enchanged = $this->dechanged = true;
  338. }
  339. /**
  340. * Sets the password.
  341. *
  342. * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
  343. * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
  344. * $hash, $salt, $method
  345. *
  346. * @param String $password
  347. * @param optional String $method
  348. * @access public
  349. */
  350. function setPassword($password, $method = 'pbkdf2')
  351. {
  352. $key = '';
  353. switch ($method) {
  354. default: // 'pbkdf2'
  355. list(, , $hash, $salt, $count) = func_get_args();
  356. if (!isset($hash)) {
  357. $hash = 'sha1';
  358. }
  359. // WPA and WPA2 use the SSID as the salt
  360. if (!isset($salt)) {
  361. $salt = 'phpseclib';
  362. }
  363. // RFC2898#section-4.2 uses 1,000 iterations by default
  364. // WPA and WPA2 use 4,096.
  365. if (!isset($count)) {
  366. $count = 1000;
  367. }
  368. if (!class_exists('Crypt_Hash')) {
  369. require_once('Crypt/Hash.php');
  370. }
  371. $i = 1;
  372. while (strlen($key) < 24) { // $dkLen == 24
  373. $hmac = new Crypt_Hash();
  374. $hmac->setHash($hash);
  375. $hmac->setKey($password);
  376. $f = $u = $hmac->hash($salt . pack('N', $i++));
  377. for ($j = 2; $j <= $count; $j++) {
  378. $u = $hmac->hash($u);
  379. $f^= $u;
  380. }
  381. $key.= $f;
  382. }
  383. }
  384. $this->setKey($key);
  385. }
  386. /**
  387. * Sets the initialization vector. (optional)
  388. *
  389. * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
  390. * to be all zero's.
  391. *
  392. * @access public
  393. * @param String $iv
  394. */
  395. function setIV($iv)
  396. {
  397. $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
  398. if ($this->mode == CRYPT_DES_MODE_3CBC) {
  399. $this->des[0]->setIV($iv);
  400. $this->des[1]->setIV($iv);
  401. $this->des[2]->setIV($iv);
  402. }
  403. $this->enchanged = $this->dechanged = true;
  404. }
  405. /**
  406. * Generate CTR XOR encryption key
  407. *
  408. * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
  409. * plaintext / ciphertext in CTR mode.
  410. *
  411. * @see Crypt_TripleDES::decrypt()
  412. * @see Crypt_TripleDES::encrypt()
  413. * @access private
  414. * @param String $iv
  415. */
  416. function _generate_xor(&$iv)
  417. {
  418. $xor = $iv;
  419. for ($j = 4; $j <= 8; $j+=4) {
  420. $temp = substr($iv, -$j, 4);
  421. switch ($temp) {
  422. case "\xFF\xFF\xFF\xFF":
  423. $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
  424. break;
  425. case "\x7F\xFF\xFF\xFF":
  426. $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
  427. break 2;
  428. default:
  429. extract(unpack('Ncount', $temp));
  430. $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
  431. break 2;
  432. }
  433. }
  434. return $xor;
  435. }
  436. /**
  437. * Encrypts a message.
  438. *
  439. * @access public
  440. * @param String $plaintext
  441. */
  442. function encrypt($plaintext)
  443. {
  444. if ($this->paddable) {
  445. $plaintext = $this->_pad($plaintext);
  446. }
  447. // if the key is smaller then 8, do what we'd normally do
  448. if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
  449. $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
  450. return $ciphertext;
  451. }
  452. if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
  453. if ($this->enchanged) {
  454. mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
  455. if ($this->mode == 'ncfb') {
  456. mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
  457. }
  458. $this->enchanged = false;
  459. }
  460. if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
  461. $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
  462. } else {
  463. $iv = &$this->encryptIV;
  464. $pos = &$this->enbuffer['pos'];
  465. $len = strlen($plaintext);
  466. $ciphertext = '';
  467. $i = 0;
  468. if ($pos) {
  469. $orig_pos = $pos;
  470. $max = 8 - $pos;
  471. if ($len >= $max) {
  472. $i = $max;
  473. $len-= $max;
  474. $pos = 0;
  475. } else {
  476. $i = $len;
  477. $pos+= $len;
  478. $len = 0;
  479. }
  480. $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
  481. $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
  482. $this->enbuffer['enmcrypt_init'] = true;
  483. }
  484. if ($len >= 8) {
  485. if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) {
  486. if ($this->enbuffer['enmcrypt_init'] === true) {
  487. mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
  488. $this->enbuffer['enmcrypt_init'] = false;
  489. }
  490. $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
  491. $iv = substr($ciphertext, -8);
  492. $i = strlen($ciphertext);
  493. $len%= 8;
  494. } else {
  495. while ($len >= 8) {
  496. $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
  497. $ciphertext.= $iv;
  498. $len-= 8;
  499. $i+= 8;
  500. }
  501. }
  502. }
  503. if ($len) {
  504. $iv = mcrypt_generic($this->ecb, $iv);
  505. $block = $iv ^ substr($plaintext, $i);
  506. $iv = substr_replace($iv, $block, 0, $len);
  507. $ciphertext.= $block;
  508. $pos = $len;
  509. }
  510. return $ciphertext;
  511. }
  512. if (!$this->continuousBuffer) {
  513. mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
  514. }
  515. return $ciphertext;
  516. }
  517. if (strlen($this->key) <= 8) {
  518. $this->des[0]->mode = $this->mode;
  519. return $this->des[0]->encrypt($plaintext);
  520. }
  521. $des = $this->des;
  522. $buffer = &$this->enbuffer;
  523. $continuousBuffer = $this->continuousBuffer;
  524. $ciphertext = '';
  525. switch ($this->mode) {
  526. case CRYPT_DES_MODE_ECB:
  527. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  528. $block = substr($plaintext, $i, 8);
  529. // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
  530. // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
  531. // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
  532. // encryption and decryption take more time, per this:
  533. //
  534. // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
  535. $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
  536. $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
  537. $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
  538. $ciphertext.= $block;
  539. }
  540. break;
  541. case CRYPT_DES_MODE_CBC:
  542. $xor = $this->encryptIV;
  543. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  544. $block = substr($plaintext, $i, 8) ^ $xor;
  545. $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
  546. $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
  547. $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
  548. $xor = $block;
  549. $ciphertext.= $block;
  550. }
  551. if ($this->continuousBuffer) {
  552. $this->encryptIV = $xor;
  553. }
  554. break;
  555. case CRYPT_DES_MODE_CTR:
  556. $xor = $this->encryptIV;
  557. if (strlen($buffer['encrypted'])) {
  558. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  559. $block = substr($plaintext, $i, 8);
  560. $key = $this->_generate_xor($xor);
  561. $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
  562. $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
  563. $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
  564. $buffer['encrypted'].= $key;
  565. $key = $this->_string_shift($buffer['encrypted'], 8);
  566. $ciphertext.= $block ^ $key;
  567. }
  568. } else {
  569. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  570. $block = substr($plaintext, $i, 8);
  571. $key = $this->_generate_xor($xor);
  572. $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
  573. $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
  574. $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
  575. $ciphertext.= $block ^ $key;
  576. }
  577. }
  578. if ($this->continuousBuffer) {
  579. $this->encryptIV = $xor;
  580. if ($start = strlen($plaintext) & 7) {
  581. $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
  582. }
  583. }
  584. break;
  585. case CRYPT_DES_MODE_CFB:
  586. if (strlen($buffer['xor'])) {
  587. $ciphertext = $plaintext ^ $buffer['xor'];
  588. $iv = $buffer['encrypted'] . $ciphertext;
  589. $start = strlen($ciphertext);
  590. $buffer['encrypted'].= $ciphertext;
  591. $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
  592. } else {
  593. $ciphertext = '';
  594. $iv = $this->encryptIV;
  595. $start = 0;
  596. }
  597. for ($i = $start; $i < strlen($plaintext); $i+=8) {
  598. $block = substr($plaintext, $i, 8);
  599. $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
  600. $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
  601. $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
  602. $iv = $block ^ $xor;
  603. if ($continuousBuffer && strlen($iv) != 8) {
  604. $buffer = array(
  605. 'encrypted' => $iv,
  606. 'xor' => substr($xor, strlen($iv))
  607. );
  608. }
  609. $ciphertext.= $iv;
  610. }
  611. if ($this->continuousBuffer) {
  612. $this->encryptIV = $iv;
  613. }
  614. break;
  615. case CRYPT_DES_MODE_OFB:
  616. $xor = $this->encryptIV;
  617. if (strlen($buffer['xor'])) {
  618. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  619. $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  620. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  621. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  622. $buffer['xor'].= $xor;
  623. $key = $this->_string_shift($buffer['xor'], 8);
  624. $ciphertext.= substr($plaintext, $i, 8) ^ $key;
  625. }
  626. } else {
  627. for ($i = 0; $i < strlen($plaintext); $i+=8) {
  628. $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  629. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  630. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  631. $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
  632. }
  633. $key = $xor;
  634. }
  635. if ($this->continuousBuffer) {
  636. $this->encryptIV = $xor;
  637. if ($start = strlen($plaintext) & 7) {
  638. $buffer['xor'] = substr($key, $start) . $buffer['xor'];
  639. }
  640. }
  641. }
  642. return $ciphertext;
  643. }
  644. /**
  645. * Decrypts a message.
  646. *
  647. * @access public
  648. * @param String $ciphertext
  649. */
  650. function decrypt($ciphertext)
  651. {
  652. if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
  653. $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
  654. return $this->_unpad($plaintext);
  655. }
  656. if ($this->paddable) {
  657. // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
  658. // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
  659. $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
  660. }
  661. if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
  662. if ($this->dechanged) {
  663. mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
  664. if ($this->mode == 'ncfb') {
  665. mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
  666. }
  667. $this->dechanged = false;
  668. }
  669. if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
  670. $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
  671. } else {
  672. $iv = &$this->decryptIV;
  673. $pos = &$this->debuffer['pos'];
  674. $len = strlen($ciphertext);
  675. $plaintext = '';
  676. $i = 0;
  677. if ($pos) {
  678. $orig_pos = $pos;
  679. $max = 8 - $pos;
  680. if ($len >= $max) {
  681. $i = $max;
  682. $len-= $max;
  683. $pos = 0;
  684. } else {
  685. $i = $len;
  686. $pos+= $len;
  687. $len = 0;
  688. }
  689. $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
  690. $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
  691. }
  692. if ($len >= 8) {
  693. $cb = substr($ciphertext, $i, $len - $len % 8);
  694. $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
  695. $iv = substr($cb, -8);
  696. $len%= 8;
  697. }
  698. if ($len) {
  699. $iv = mcrypt_generic($this->ecb, $iv);
  700. $cb = substr($ciphertext, -$len);
  701. $plaintext.= $iv ^ $cb;
  702. $iv = substr_replace($iv, $cb, 0, $len);
  703. $pos = $len;
  704. }
  705. return $plaintext;
  706. }
  707. if (!$this->continuousBuffer) {
  708. mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
  709. }
  710. return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
  711. }
  712. if (strlen($this->key) <= 8) {
  713. $this->des[0]->mode = $this->mode;
  714. $plaintext = $this->des[0]->decrypt($ciphertext);
  715. return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
  716. }
  717. $des = $this->des;
  718. $buffer = &$this->debuffer;
  719. $continuousBuffer = $this->continuousBuffer;
  720. $plaintext = '';
  721. switch ($this->mode) {
  722. case CRYPT_DES_MODE_ECB:
  723. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  724. $block = substr($ciphertext, $i, 8);
  725. $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
  726. $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
  727. $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
  728. $plaintext.= $block;
  729. }
  730. break;
  731. case CRYPT_DES_MODE_CBC:
  732. $xor = $this->decryptIV;
  733. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  734. $orig = $block = substr($ciphertext, $i, 8);
  735. $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
  736. $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
  737. $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
  738. $plaintext.= $block ^ $xor;
  739. $xor = $orig;
  740. }
  741. if ($this->continuousBuffer) {
  742. $this->decryptIV = $xor;
  743. }
  744. break;
  745. case CRYPT_DES_MODE_CTR:
  746. $xor = $this->decryptIV;
  747. if (strlen($buffer['ciphertext'])) {
  748. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  749. $block = substr($ciphertext, $i, 8);
  750. $key = $this->_generate_xor($xor);
  751. $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
  752. $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
  753. $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
  754. $buffer['ciphertext'].= $key;
  755. $key = $this->_string_shift($buffer['ciphertext'], 8);
  756. $plaintext.= $block ^ $key;
  757. }
  758. } else {
  759. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  760. $block = substr($ciphertext, $i, 8);
  761. $key = $this->_generate_xor($xor);
  762. $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
  763. $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
  764. $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
  765. $plaintext.= $block ^ $key;
  766. }
  767. }
  768. if ($this->continuousBuffer) {
  769. $this->decryptIV = $xor;
  770. if ($start = strlen($plaintext) & 7) {
  771. $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
  772. }
  773. }
  774. break;
  775. case CRYPT_DES_MODE_CFB:
  776. if (strlen($buffer['ciphertext'])) {
  777. $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
  778. $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
  779. if (strlen($buffer['ciphertext']) != 8) {
  780. $block = $this->decryptIV;
  781. } else {
  782. $block = $buffer['ciphertext'];
  783. $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
  784. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  785. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  786. $buffer['ciphertext'] = '';
  787. }
  788. $start = strlen($plaintext);
  789. } else {
  790. $plaintext = '';
  791. $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
  792. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  793. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  794. $start = 0;
  795. }
  796. for ($i = $start; $i < strlen($ciphertext); $i+=8) {
  797. $block = substr($ciphertext, $i, 8);
  798. $plaintext.= $block ^ $xor;
  799. if ($continuousBuffer && strlen($block) != 8) {
  800. $buffer['ciphertext'].= $block;
  801. $block = $xor;
  802. } else if (strlen($block) == 8) {
  803. $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
  804. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  805. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  806. }
  807. }
  808. if ($this->continuousBuffer) {
  809. $this->decryptIV = $block;
  810. }
  811. break;
  812. case CRYPT_DES_MODE_OFB:
  813. $xor = $this->decryptIV;
  814. if (strlen($buffer['xor'])) {
  815. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  816. $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  817. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  818. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  819. $buffer['xor'].= $xor;
  820. $key = $this->_string_shift($buffer['xor'], 8);
  821. $plaintext.= substr($ciphertext, $i, 8) ^ $key;
  822. }
  823. } else {
  824. for ($i = 0; $i < strlen($ciphertext); $i+=8) {
  825. $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  826. $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
  827. $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
  828. $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
  829. }
  830. $key = $xor;
  831. }
  832. if ($this->continuousBuffer) {
  833. $this->decryptIV = $xor;
  834. if ($start = strlen($ciphertext) & 7) {
  835. $buffer['xor'] = substr($key, $start) . $buffer['xor'];
  836. }
  837. }
  838. }
  839. return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
  840. }
  841. /**
  842. * Treat consecutive "packets" as if they are a continuous buffer.
  843. *
  844. * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
  845. * will yield different outputs:
  846. *
  847. * <code>
  848. * echo $des->encrypt(substr($plaintext, 0, 8));
  849. * echo $des->encrypt(substr($plaintext, 8, 8));
  850. * </code>
  851. * <code>
  852. * echo $des->encrypt($plaintext);
  853. * </code>
  854. *
  855. * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
  856. * another, as demonstrated with the following:
  857. *
  858. * <code>
  859. * $des->encrypt(substr($plaintext, 0, 8));
  860. * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  861. * </code>
  862. * <code>
  863. * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  864. * </code>
  865. *
  866. * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
  867. * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
  868. * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
  869. *
  870. * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
  871. * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
  872. * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
  873. * however, they are also less intuitive and more likely to cause you problems.
  874. *
  875. * @see Crypt_TripleDES::disableContinuousBuffer()
  876. * @access public
  877. */
  878. function enableContinuousBuffer()
  879. {
  880. $this->continuousBuffer = true;
  881. if ($this->mode == CRYPT_DES_MODE_3CBC) {
  882. $this->des[0]->enableContinuousBuffer();
  883. $this->des[1]->enableContinuousBuffer();
  884. $this->des[2]->enableContinuousBuffer();
  885. }
  886. }
  887. /**
  888. * Treat consecutive packets as if they are a discontinuous buffer.
  889. *
  890. * The default behavior.
  891. *
  892. * @see Crypt_TripleDES::enableContinuousBuffer()
  893. * @access public
  894. */
  895. function disableContinuousBuffer()
  896. {
  897. $this->continuousBuffer = false;
  898. $this->encryptIV = $this->iv;
  899. $this->decryptIV = $this->iv;
  900. $this->enchanged = true;
  901. $this->dechanged = true;
  902. $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
  903. $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
  904. if ($this->mode == CRYPT_DES_MODE_3CBC) {
  905. $this->des[0]->disableContinuousBuffer();
  906. $this->des[1]->disableContinuousBuffer();
  907. $this->des[2]->disableContinuousBuffer();
  908. }
  909. }
  910. /**
  911. * Pad "packets".
  912. *
  913. * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
  914. * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
  915. *
  916. * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
  917. * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
  918. * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
  919. * transmitted separately)
  920. *
  921. * @see Crypt_TripleDES::disablePadding()
  922. * @access public
  923. */
  924. function enablePadding()
  925. {
  926. $this->padding = true;
  927. }
  928. /**
  929. * Do not pad packets.
  930. *
  931. * @see Crypt_TripleDES::enablePadding()
  932. * @access public
  933. */
  934. function disablePadding()
  935. {
  936. $this->padding = false;
  937. }
  938. /**
  939. * Pads a string
  940. *
  941. * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
  942. * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
  943. *
  944. * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
  945. * and padding will, hence forth, be enabled.
  946. *
  947. * @see Crypt_TripleDES::_unpad()
  948. * @access private
  949. */
  950. function _pad($text)
  951. {
  952. $length = strlen($text);
  953. if (!$this->padding) {
  954. if (($length & 7) == 0) {
  955. return $text;
  956. } else {
  957. user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
  958. $this->padding = true;
  959. }
  960. }
  961. $pad = 8 - ($length & 7);
  962. return str_pad($text, $length + $pad, chr($pad));
  963. }
  964. /**
  965. * Unpads a string
  966. *
  967. * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
  968. * and false will be returned.
  969. *
  970. * @see Crypt_TripleDES::_pad()
  971. * @access private
  972. */
  973. function _unpad($text)
  974. {
  975. if (!$this->padding) {
  976. return $text;
  977. }
  978. $length = ord($text[strlen($text) - 1]);
  979. if (!$length || $length > 8) {
  980. return false;
  981. }
  982. return substr($text, 0, -$length);
  983. }
  984. /**
  985. * String Shift
  986. *
  987. * Inspired by array_shift
  988. *
  989. * @param String $string
  990. * @param optional Integer $index
  991. * @return String
  992. * @access private
  993. */
  994. function _string_shift(&$string, $index = 1)
  995. {
  996. $substr = substr($string, 0, $index);
  997. $string = substr($string, $index);
  998. return $substr;
  999. }
  1000. }
  1001. // vim: ts=4:sw=4:et:
  1002. // vim6: fdl=1: