PluginProbe
ManageWP Worker / 3.9.28
ManageWP Worker v3.9.28
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / lib / PHPSecLib / Crypt / TripleDES.php

TripleDES.php in ManageWP Worker 3.9.28, at lib/PHPSecLib/Crypt/TripleDES.php

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