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 * @category Crypt 30 * @package TripleDES 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 37namespace phpseclib3\Crypt; 38 39/** 40 * Pure-PHP implementation of Triple DES. 41 * 42 * @package TripleDES 43 * @author Jim Wigginton <terrafrost@php.net> 44 * @access public 45 */ 46class 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 67 * @access private 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 77 * @access private 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 86 * @access private 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 96 * @access private 97 */ 98 protected $key_length_max = 24; 99 100 /** 101 * Internal flag whether using self::MODE_3CBC or not 102 * 103 * @var bool 104 * @access private 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 114 * @access private 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 142 * @access public 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 185 * @access protected 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() 205 * @access public 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() 226 * @access public 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 * 250 * @access public 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() 289 * @access public 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() 316 * @access public 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() 373 * @access public 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() 392 * @access public 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() 409 * @access private 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 445 * @access public 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} 458