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