1<?php
2
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 version 5
9 *
10 * Here's a short example of how to use this library:
11 * <code>
12 * <?php
13 *    include 'vendor/autoload.php';
14 *
15 *    $des = new \phpseclib3\Crypt\TripleDES('ctr');
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 * @author    Jim Wigginton <terrafrost@php.net>
30 * @copyright 2007 Jim Wigginton
31 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
32 * @link      http://phpseclib.sourceforge.net
33 */
34
35namespace phpseclib3\Crypt;
36
37/**
38 * Pure-PHP implementation of Triple DES.
39 *
40 * @author  Jim Wigginton <terrafrost@php.net>
41 */
42class TripleDES extends DES
43{
44    /**
45     * Encrypt / decrypt using inner chaining
46     *
47     * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3).
48     */
49    const MODE_3CBC = -2;
50
51    /**
52     * Encrypt / decrypt using outer chaining
53     *
54     * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib3\Crypt\Common\BlockCipher::MODE_CBC.
55     */
56    const MODE_CBC3 = self::MODE_CBC;
57
58    /**
59     * Key Length (in bytes)
60     *
61     * @see \phpseclib3\Crypt\TripleDES::setKeyLength()
62     * @var int
63     */
64    protected $key_length = 24;
65
66    /**
67     * The mcrypt specific name of the cipher
68     *
69     * @see \phpseclib3\Crypt\DES::cipher_name_mcrypt
70     * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
71     * @var string
72     */
73    protected $cipher_name_mcrypt = 'tripledes';
74
75    /**
76     * Optimizing value while CFB-encrypting
77     *
78     * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
79     * @var int
80     */
81    protected $cfb_init_len = 750;
82
83    /**
84     * max possible size of $key
85     *
86     * @see self::setKey()
87     * @see \phpseclib3\Crypt\DES::setKey()
88     * @var string
89     */
90    protected $key_length_max = 24;
91
92    /**
93     * Internal flag whether using self::MODE_3CBC or not
94     *
95     * @var bool
96     */
97    private $mode_3cbc;
98
99    /**
100     * The \phpseclib3\Crypt\DES objects
101     *
102     * Used only if $mode_3cbc === true
103     *
104     * @var array
105     */
106    private $des;
107
108    /**
109     * Default Constructor.
110     *
111     * Determines whether or not the mcrypt or OpenSSL extensions should be used.
112     *
113     * $mode could be:
114     *
115     * - ecb
116     *
117     * - cbc
118     *
119     * - ctr
120     *
121     * - cfb
122     *
123     * - ofb
124     *
125     * - 3cbc
126     *
127     * - cbc3 (same as cbc)
128     *
129     * @see \phpseclib3\Crypt\DES::__construct()
130     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
131     * @param string $mode
132     */
133    public function __construct($mode)
134    {
135        switch (strtolower($mode)) {
136            // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
137            // and additional flag us internally as 3CBC
138            case '3cbc':
139                parent::__construct('cbc');
140                $this->mode_3cbc = true;
141
142                // This three $des'es will do the 3CBC work (if $key > 64bits)
143                $this->des = [
144                    new DES('cbc'),
145                    new DES('cbc'),
146                    new DES('cbc'),
147                ];
148
149                // we're going to be doing the padding, ourselves, so disable it in the \phpseclib3\Crypt\DES objects
150                $this->des[0]->disablePadding();
151                $this->des[1]->disablePadding();
152                $this->des[2]->disablePadding();
153                break;
154            case 'cbc3':
155                $mode = 'cbc';
156                // fall-through
157            // If not 3CBC, we init as usual
158            default:
159                parent::__construct($mode);
160
161                if ($this->mode == self::MODE_STREAM) {
162                    throw new BadModeException('Block ciphers cannot be ran in stream mode');
163                }
164        }
165    }
166
167    /**
168     * Test for engine validity
169     *
170     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
171     *
172     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
173     * @param int $engine
174     * @return bool
175     */
176    protected function isValidEngineHelper($engine)
177    {
178        if ($engine == self::ENGINE_OPENSSL) {
179            $this->cipher_name_openssl_ecb = 'des-ede3';
180            $mode = $this->openssl_translate_mode();
181            $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
182        }
183
184        return parent::isValidEngineHelper($engine);
185    }
186
187    /**
188     * Sets the initialization vector.
189     *
190     * SetIV is not required when \phpseclib3\Crypt\Common\SymmetricKey::MODE_ECB is being used.
191     *
192     * @see \phpseclib3\Crypt\Common\SymmetricKey::setIV()
193     * @param string $iv
194     */
195    public function setIV($iv)
196    {
197        parent::setIV($iv);
198        if ($this->mode_3cbc) {
199            $this->des[0]->setIV($iv);
200            $this->des[1]->setIV($iv);
201            $this->des[2]->setIV($iv);
202        }
203    }
204
205    /**
206     * Sets the key length.
207     *
208     * Valid key lengths are 128 and 192 bits.
209     *
210     * If you want to use a 64-bit key use DES.php
211     *
212     * @see \phpseclib3\Crypt\Common\SymmetricKey:setKeyLength()
213     * @throws \LengthException if the key length is invalid
214     * @param int $length
215     */
216    public function setKeyLength($length)
217    {
218        switch ($length) {
219            case 128:
220            case 192:
221                break;
222            default:
223                throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported');
224        }
225
226        parent::setKeyLength($length);
227    }
228
229    /**
230     * Sets the key.
231     *
232     * Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys.
233     *
234     * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
235     *
236     * @see \phpseclib3\Crypt\DES::setKey()
237     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey()
238     * @throws \LengthException if the key length is invalid
239     * @param string $key
240     */
241    public function setKey($key)
242    {
243        if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
244            throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
245        }
246
247        switch (strlen($key)) {
248            case 16:
249                $key .= substr($key, 0, 8);
250                break;
251            case 24:
252                break;
253            default:
254                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
255        }
256
257        // copied from self::setKey()
258        $this->key = $key;
259        $this->key_length = strlen($key);
260        $this->changed = $this->nonIVChanged = true;
261        $this->setEngine();
262
263        if ($this->mode_3cbc) {
264            $this->des[0]->setKey(substr($key, 0, 8));
265            $this->des[1]->setKey(substr($key, 8, 8));
266            $this->des[2]->setKey(substr($key, 16, 8));
267        }
268    }
269
270    /**
271     * Encrypts a message.
272     *
273     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
274     * @param string $plaintext
275     * @return string $cipertext
276     */
277    public function encrypt($plaintext)
278    {
279        // parent::en/decrypt() is able to do all the work for all modes and keylengths,
280        // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits
281
282        // if the key is smaller then 8, do what we'd normally do
283        if ($this->mode_3cbc && strlen($this->key) > 8) {
284            return $this->des[2]->encrypt(
285                $this->des[1]->decrypt(
286                    $this->des[0]->encrypt(
287                        $this->pad($plaintext)
288                    )
289                )
290            );
291        }
292
293        return parent::encrypt($plaintext);
294    }
295
296    /**
297     * Decrypts a message.
298     *
299     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
300     * @param string $ciphertext
301     * @return string $plaintext
302     */
303    public function decrypt($ciphertext)
304    {
305        if ($this->mode_3cbc && strlen($this->key) > 8) {
306            return $this->unpad(
307                $this->des[0]->decrypt(
308                    $this->des[1]->encrypt(
309                        $this->des[2]->decrypt(
310                            str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
311                        )
312                    )
313                )
314            );
315        }
316
317        return parent::decrypt($ciphertext);
318    }
319
320    /**
321     * Treat consecutive "packets" as if they are a continuous buffer.
322     *
323     * Say you have a 16-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
324     * will yield different outputs:
325     *
326     * <code>
327     *    echo $des->encrypt(substr($plaintext, 0, 8));
328     *    echo $des->encrypt(substr($plaintext, 8, 8));
329     * </code>
330     * <code>
331     *    echo $des->encrypt($plaintext);
332     * </code>
333     *
334     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
335     * another, as demonstrated with the following:
336     *
337     * <code>
338     *    $des->encrypt(substr($plaintext, 0, 8));
339     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
340     * </code>
341     * <code>
342     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
343     * </code>
344     *
345     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
346     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
347     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
348     *
349     * Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\DES() object changes after each
350     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
351     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
352     * however, they are also less intuitive and more likely to cause you problems.
353     *
354     * @see \phpseclib3\Crypt\Common\SymmetricKey::enableContinuousBuffer()
355     * @see self::disableContinuousBuffer()
356     */
357    public function enableContinuousBuffer()
358    {
359        parent::enableContinuousBuffer();
360        if ($this->mode_3cbc) {
361            $this->des[0]->enableContinuousBuffer();
362            $this->des[1]->enableContinuousBuffer();
363            $this->des[2]->enableContinuousBuffer();
364        }
365    }
366
367    /**
368     * Treat consecutive packets as if they are a discontinuous buffer.
369     *
370     * The default behavior.
371     *
372     * @see \phpseclib3\Crypt\Common\SymmetricKey::disableContinuousBuffer()
373     * @see self::enableContinuousBuffer()
374     */
375    public function disableContinuousBuffer()
376    {
377        parent::disableContinuousBuffer();
378        if ($this->mode_3cbc) {
379            $this->des[0]->disableContinuousBuffer();
380            $this->des[1]->disableContinuousBuffer();
381            $this->des[2]->disableContinuousBuffer();
382        }
383    }
384
385    /**
386     * Creates the key schedule
387     *
388     * @see \phpseclib3\Crypt\DES::setupKey()
389     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
390     */
391    protected function setupKey()
392    {
393        switch (true) {
394            // if $key <= 64bits we configure our internal pure-php cipher engine
395            // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
396            case strlen($this->key) <= 8:
397                $this->des_rounds = 1;
398                break;
399
400            // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
401            default:
402                $this->des_rounds = 3;
403
404                // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
405                if ($this->mode_3cbc) {
406                    $this->des[0]->setupKey();
407                    $this->des[1]->setupKey();
408                    $this->des[2]->setupKey();
409
410                    // because $des[0-2] will, now, do all the work we can return here
411                    // not need unnecessary stress parent::setupKey() with our, now unused, $key.
412                    return;
413                }
414        }
415        // setup our key
416        parent::setupKey();
417    }
418
419    /**
420     * Sets the internal crypt engine
421     *
422     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
423     * @see \phpseclib3\Crypt\Common\SymmetricKey::setPreferredEngine()
424     * @param int $engine
425     */
426    public function setPreferredEngine($engine)
427    {
428        if ($this->mode_3cbc) {
429            $this->des[0]->setPreferredEngine($engine);
430            $this->des[1]->setPreferredEngine($engine);
431            $this->des[2]->setPreferredEngine($engine);
432        }
433
434        parent::setPreferredEngine($engine);
435    }
436}
437