Browse Source

Issue 3142: mcrypt is no more (as well as phpseclib)

pull/3280/head
Michael 4 years ago
parent
commit
f6d7ee2781
36 changed files with 86 additions and 16556 deletions
  1. +1
    -1
      INSTALL.txt
  2. +0
    -1
      boot.php
  3. +2
    -3
      htconfig.php
  4. +59
    -152
      include/crypto.php
  5. +10
    -4
      include/dfrn.php
  6. +4
    -4
      include/diaspora.php
  7. +1
    -11
      include/user.php
  8. +3
    -3
      library/defuse/php-encryption-1.2.1/Crypto.php
  9. +0
    -479
      library/phpsec/Crypt/AES.php
  10. +0
    -945
      library/phpsec/Crypt/DES.php
  11. +0
    -816
      library/phpsec/Crypt/Hash.php
  12. +0
    -493
      library/phpsec/Crypt/RC4.php
  13. +0
    -2119
      library/phpsec/Crypt/RSA.php
  14. +0
    -130
      library/phpsec/Crypt/Random.php
  15. +0
    -1242
      library/phpsec/Crypt/Rijndael.php
  16. +0
    -690
      library/phpsec/Crypt/TripleDES.php
  17. +0
    -3545
      library/phpsec/Math/BigInteger.php
  18. +0
    -1461
      library/phpsec/Net/SFTP.php
  19. +0
    -1160
      library/phpsec/Net/SSH1.php
  20. +0
    -2302
      library/phpsec/Net/SSH2.php
  21. +0
    -43
      library/phpsec/PHP/Compat/Function/array_fill.php
  22. +0
    -67
      library/phpsec/PHP/Compat/Function/bcpowmod.php
  23. +0
    -59
      library/phpsec/PHP/Compat/Function/str_split.php
  24. +0
    -135
      library/phpsec/crypt.html
  25. +0
    -43
      library/phpsec/docbook.css
  26. +0
    -5
      library/phpsec/index.html
  27. +0
    -20
      library/phpsec/intro.html
  28. +0
    -157
      library/phpsec/math.html
  29. +0
    -155
      library/phpsec/misc_crypt.html
  30. +0
    -153
      library/phpsec/net.html
  31. +0
    -118
      library/phpsec/sym_crypt.html
  32. +1
    -6
      mod/admin.php
  33. +2
    -2
      mod/dfrn_confirm.php
  34. +1
    -5
      mod/dfrn_notify.php
  35. +0
    -24
      mod/install.php
  36. +2
    -3
      view/templates/htconfig.tpl

+ 1
- 1
INSTALL.txt View File

@ -37,7 +37,7 @@ local .htaccess file
- PHP *command line* access with register_argc_argv set to true in the
php.ini file [or see 'poormancron' in section 8]
- curl, gd (with at least jpeg support), mysql, mbstring, mcrypt, and openssl extensions
- curl, gd (with at least jpeg support), mysql, mbstring and openssl extensions
- some form of email server or email gateway such that PHP mail() works


+ 0
- 1
boot.php View File

@ -648,7 +648,6 @@ class App {
set_include_path(
'include' . PATH_SEPARATOR
. 'library' . PATH_SEPARATOR
. 'library/phpsec' . PATH_SEPARATOR
. 'library/langdet' . PATH_SEPARATOR
. '.' );


+ 2
- 3
htconfig.php View File

@ -65,9 +65,8 @@ $a->config['php_path'] = 'php';
$a->config['system']['huburl'] = '[internal]';
// Server-to-server private message encryption (RINO) is allowed by default.
// Encryption will only be provided if this setting is set to a non zero
// value and the PHP mcrypt extension is installed on both systems
// set to 0 to disable, 2 to enable, 1 is deprecated but wont need mcrypt
// Encryption will only be provided if this setting is set to a non zero value
// set to 0 to disable, 2 to enable, 1 is deprecated
$a->config['system']['rino_encrypt'] = 2;


+ 59
- 152
include/crypto.php View File

@ -1,94 +1,52 @@
<?php
require_once('library/ASNValue.class.php');
require_once('library/asn1.php');
require_once 'library/ASNValue.class.php';
require_once 'library/asn1.php';
// supported algorithms are 'sha256', 'sha1'
function rsa_sign($data,$key,$alg = 'sha256') {
$sig = '';
if (version_compare(PHP_VERSION, '5.3.0', '>=') || $alg === 'sha1') {
openssl_sign($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
}
else {
if(strlen($key) < 1024 || extension_loaded('gmp')) {
require_once('library/phpsec/Crypt/RSA.php');
$rsa = new CRYPT_RSA();
$rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
$rsa->setHash($alg);
$rsa->loadKey($key);
$sig = $rsa->sign($data);
}
else {
logger('rsa_sign: insecure algorithm used. Please upgrade PHP to 5.3');
openssl_private_encrypt(hex2bin('3031300d060960864801650304020105000420') . hash('sha256',$data,true), $sig, $key);
}
}
function rsa_sign($data, $key, $alg = 'sha256') {
openssl_sign($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
return $sig;
}
function rsa_verify($data,$sig,$key,$alg = 'sha256') {
if (version_compare(PHP_VERSION, '5.3.0', '>=') || $alg === 'sha1') {
$verify = openssl_verify($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
}
else {
if(strlen($key) <= 300 || extension_loaded('gmp')) {
require_once('library/phpsec/Crypt/RSA.php');
$rsa = new CRYPT_RSA();
$rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
$rsa->setHash($alg);
$rsa->loadKey($key);
$verify = $rsa->verify($data,$sig);
}
else {
// fallback sha256 verify for PHP < 5.3 and large key lengths
$rawsig = '';
openssl_public_decrypt($sig,$rawsig,$key);
$verify = (($rawsig && substr($rawsig,-32) === hash('sha256',$data,true)) ? true : false);
}
}
return $verify;
function rsa_verify($data, $sig, $key, $alg = 'sha256') {
return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
}
function DerToPem($Der, $Private=false)
{
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 65);
$body = implode("\n", $lines);
//Get title:
$title = $Private? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
return $result;
function DerToPem($Der, $Private = false) {
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 65);
$body = implode("\n", $lines);
//Get title:
$title = $Private ? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
return $result;
}
function DerToRsa($Der)
{
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 64);
$body = implode("\n", $lines);
//Get title:
$title = 'RSA PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
return $result;
function DerToRsa($Der) {
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 64);
$body = implode("\n", $lines);
//Get title:
$title = 'RSA PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
return $result;
}
function pkcs8_encode($Modulus,$PublicExponent) {
function pkcs8_encode($Modulus, $PublicExponent) {
//Encode key sequence
$modulus = new ASNValue(ASNValue::TAG_INTEGER);
$modulus->SetIntBuffer($Modulus);
@ -111,8 +69,7 @@ function pkcs8_encode($Modulus,$PublicExponent) {
return $PublicDER;
}
function pkcs1_encode($Modulus,$PublicExponent) {
function pkcs1_encode($Modulus, $PublicExponent) {
//Encode key sequence
$modulus = new ASNValue(ASNValue::TAG_INTEGER);
$modulus->SetIntBuffer($Modulus);
@ -126,22 +83,20 @@ function pkcs1_encode($Modulus,$PublicExponent) {
return $bitStringValue;
}
function metopem($m,$e) {
$der = pkcs8_encode($m,$e);
$key = DerToPem($der,false);
function metopem($m, $e) {
$der = pkcs8_encode($m, $e);
$key = DerToPem($der, false);
return $key;
}
}
function pubrsatome($key,&$m,&$e) {
require_once('library/asn1.php');
require_once('include/salmon.php');
$lines = explode("\n",$key);
$lines = explode("\n", $key);
unset($lines[0]);
unset($lines[count($lines)]);
$x = base64_decode(implode('',$lines));
$x = base64_decode(implode('', $lines));
$r = ASN_BASE::parseASNString($x);
@ -151,21 +106,21 @@ function pubrsatome($key,&$m,&$e) {
function rsatopem($key) {
pubrsatome($key,$m,$e);
return(metopem($m,$e));
pubrsatome($key, $m, $e);
return metopem($m, $e);
}
function pemtorsa($key) {
pemtome($key,$m,$e);
return(metorsa($m,$e));
pemtome($key, $m, $e);
return metorsa($m, $e);
}
function pemtome($key,&$m,&$e) {
function pemtome($key, &$m, &$e) {
require_once('include/salmon.php');
$lines = explode("\n",$key);
$lines = explode("\n", $key);
unset($lines[0]);
unset($lines[count($lines)]);
$x = base64_decode(implode('',$lines));
$x = base64_decode(implode('', $lines));
$r = ASN_BASE::parseASNString($x);
@ -173,82 +128,36 @@ function pemtome($key,&$m,&$e) {
$e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
}
function metorsa($m,$e) {
$der = pkcs1_encode($m,$e);
function metorsa($m, $e) {
$der = pkcs1_encode($m, $e);
$key = DerToRsa($der);
return $key;
}
function salmon_key($pubkey) {
pemtome($pubkey,$m,$e);
return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ;
}
if(! function_exists('aes_decrypt')) {
// DEPRECATED IN 3.4.1
function aes_decrypt($val,$ky)
{
$key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
for($a=0;$a<strlen($ky);$a++)
$key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a]));
$mode = MCRYPT_MODE_ECB;
$enc = MCRYPT_RIJNDAEL_128;
$dec = @mcrypt_decrypt($enc, $key, $val, $mode, @mcrypt_create_iv( @mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM ) );
return rtrim($dec,(( ord(substr($dec,strlen($dec)-1,1))>=0 and ord(substr($dec, strlen($dec)-1,1))<=16)? chr(ord( substr($dec,strlen($dec)-1,1))):null));
}}
if(! function_exists('aes_encrypt')) {
// DEPRECATED IN 3.4.1
function aes_encrypt($val,$ky)
{
$key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
for($a=0;$a<strlen($ky);$a++)
$key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a]));
$mode=MCRYPT_MODE_ECB;
$enc=MCRYPT_RIJNDAEL_128;
$val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16)));
return mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM));
}}
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
function salmon_key($pubkey) {
pemtome($pubkey, $m, $e);
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true) ;
}
function pkcs5_unpad($text)
{
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) return false;
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
return substr($text, 0, -1 * $pad);
}
function new_keypair($bits) {
$openssl_options = array(
'digest_alg' => 'sha1',
'private_key_bits' => $bits,
'encrypt_key' => false
'encrypt_key' => false
);
$conf = get_config('system','openssl_conf_file');
if($conf)
$conf = get_config('system', 'openssl_conf_file');
if ($conf) {
$openssl_options['config'] = $conf;
}
$result = openssl_pkey_new($openssl_options);
if(empty($result)) {
if (empty($result)) {
logger('new_keypair: failed');
return false;
}
// Get private key
$response = array('prvkey' => '', 'pubkey' => '');
openssl_pkey_export($result, $response['prvkey']);
@ -258,6 +167,4 @@ function new_keypair($bits) {
$response['pubkey'] = $pkey["key"];
return $response;
}

+ 10
- 4
include/dfrn.php View File

@ -864,6 +864,14 @@ class dfrn {
return $entry;
}
private static function aes_encrypt($data, $key) {
return openssl_encrypt($data, 'aes-128-ecb', $key, OPENSSL_RAW_DATA);
}
public static function aes_decrypt($encrypted, $key) {
return openssl_decrypt($encrypted, 'aes-128-ecb', $key, OPENSSL_RAW_DATA);
}
/**
* @brief Delivers the atom content to the contacts
*
@ -888,8 +896,6 @@ class dfrn {
$rino = get_config('system','rino_encrypt');
$rino = intval($rino);
// use RINO1 if mcrypt isn't installed and RINO2 was selected
if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1;
logger("Local rino version: ". $rino, LOGGER_DEBUG);
@ -1015,8 +1021,8 @@ class dfrn {
switch($rino_remote_version) {
case 1:
// Deprecated rino version!
$key = substr(random_string(),0,16);
$data = aes_encrypt($postvars['data'],$key);
$key = openssl_random_pseudo_bytes(16);
$data = self::aes_encrypt($postvars['data'], $key);
break;
case 2:
// RINO 2 based on php-encryption


+ 4
- 4
include/diaspora.php View File

@ -2640,14 +2640,14 @@ class Diaspora {
return false;
}
$inner_aes_key = random_string(32);
$inner_aes_key = openssl_random_pseudo_bytes(32);
$b_inner_aes_key = base64_encode($inner_aes_key);
$inner_iv = random_string(16);
$inner_iv = openssl_random_pseudo_bytes(16);
$b_inner_iv = base64_encode($inner_iv);
$outer_aes_key = random_string(32);
$outer_aes_key = openssl_random_pseudo_bytes(32);
$b_outer_aes_key = base64_encode($outer_aes_key);
$outer_iv = random_string(16);
$outer_iv = openssl_random_pseudo_bytes(16);
$b_outer_iv = base64_encode($outer_iv);
$handle = self::my_handle($user);


+ 1
- 11
include/user.php View File

@ -175,17 +175,7 @@ function create_user($arr) {
$prvkey = $keys['prvkey'];
$pubkey = $keys['pubkey'];
/**
*
* Create another keypair for signing/verifying
* salmon protocol messages. We have to use a slightly
* less robust key because this won't be using openssl
* but the phpseclib. Since it is PHP interpreted code
* it is not nearly as efficient, and the larger keys
* will take several minutes each to process.
*
*/
// Create another keypair for signing/verifying salmon protocol messages.
$sres = new_keypair(512);
$sprvkey = $sres['prvkey'];
$spubkey = $sres['pubkey'];


+ 3
- 3
library/defuse/php-encryption-1.2.1/Crypto.php View File

@ -342,9 +342,9 @@ final class Crypto
*/
private static function SecureRandom($octets)
{
self::EnsureFunctionExists("mcrypt_create_iv");
$random = mcrypt_create_iv($octets, MCRYPT_DEV_URANDOM);
if ($random === FALSE) {
self::EnsureFunctionExists("openssl_random_pseudo_bytes");
$random = openssl_random_pseudo_bytes($octets, $crypto_strong);
if ($crypto_strong === FALSE) {
throw new CannotPerformOperationException();
} else {
return $random;


+ 0
- 479
library/phpsec/Crypt/AES.php View File

@ -1,479 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of AES.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
* is called, again, at which point, it'll be recalculated.
*
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/AES.php');
*
* $aes = new Crypt_AES();
*
* $aes->setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $aes->decrypt($aes->encrypt($plaintext));
* ?>
* </code>
*
* LICENSE: This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* @category Crypt
* @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Rijndael
*/
require_once 'Rijndael.php';
/**#@+
* @access public
* @see Crypt_AES::encrypt()
* @see Crypt_AES::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_AES_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_AES_MODE_ECB', 1);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_AES_MODE_CBC', 2);
/**#@-*/
/**#@+
* @access private
* @see Crypt_AES::Crypt_AES()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_AES_MODE_INTERNAL', 1);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_AES_MODE_MCRYPT', 2);
/**#@-*/
/**
* Pure-PHP implementation of AES.
*
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
* @package Crypt_AES
*/
class Crypt_AES extends Crypt_Rijndael {
/**
* mcrypt resource for encryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String
* @access private
*/
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
*
* @param optional Integer $mode
* @return Crypt_AES
* @access public
*/
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
{
if ( !defined('CRYPT_AES_MODE') ) {
switch (true) {
case extension_loaded('mcrypt'):
// i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
// but since that can be changed after the object has been created, there doesn't seem to be
// a lot of point...
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
break;
default:
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
}
}
switch ( CRYPT_AES_MODE ) {
case CRYPT_AES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_AES_MODE_ECB:
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_AES_MODE_CTR:
// ctr doesn't have a constant associated with it even though it appears to be fairly widely
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
// include a compatibility layer. the layer has been implemented but, for now, is commented out.
$this->mode = 'ctr';
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
break;
case CRYPT_AES_MODE_CBC:
default:
$this->mode = MCRYPT_MODE_CBC;
}
break;
default:
switch ($mode) {
case CRYPT_AES_MODE_ECB:
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
break;
case CRYPT_AES_MODE_CTR:
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
break;
case CRYPT_AES_MODE_CBC:
default:
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
}
}
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
parent::Crypt_Rijndael($this->mode);
}
}
/**
* Dummy function
*
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @access public
* @param Integer $length
*/
function setBlockLength($length)
{
return;
}
/**
* Encrypts a message.
*
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
* URL:
*
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
*
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
* length.
*
* @see Crypt_AES::decrypt()
* @access public
* @param String $plaintext
*/
function encrypt($plaintext)
{
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
$this->_mcryptSetup();
/*
if ($this->mode == CRYPT_AES_MODE_CTR) {
$iv = $this->encryptIV;
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
$ciphertext = $plaintext ^ $xor;
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
return $ciphertext;
}
*/
if ($this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
}
return $ciphertext;
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
*
* @see Crypt_AES::encrypt()
* @access public
* @param String $ciphertext
*/
function decrypt($ciphertext)
{
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
$this->_mcryptSetup();
/*
if ($this->mode == CRYPT_AES_MODE_CTR) {
$iv = $this->decryptIV;
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
$plaintext = $ciphertext ^ $xor;
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
return $plaintext;
}
*/
if ($this->mode != 'ctr') {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
}
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
return parent::decrypt($ciphertext);
}
/**
* Setup mcrypt
*
* Validates all the variables.
*
* @access private
*/
function _mcryptSetup()
{
if (!$this->changed) {
return;
}
if (!$this->explicit_key_length) {
// this just copied from Crypt_Rijndael::_setup()
$length = strlen($this->key) >> 2;
if ($length > 8) {
$length = 8;
} else if ($length < 4) {
$length = 4;
}
$this->Nk = $length;
$this->key_size = $length << 2;
}
switch ($this->Nk) {
case 4: // 128
$this->key_size = 16;
break;
case 5: // 160
case 6: // 192
$this->key_size = 24;
break;
case 7: // 224
case 8: // 256
$this->key_size = 32;
}
$this->key = substr($this->key, 0, $this->key_size);
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
if (!isset($this->enmcrypt)) {
$mode = $this->mode;
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
} // else should mcrypt_generic_deinit be called?
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
$this->changed = false;
}
/**
* Encrypts a block
*
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
*
* @see Crypt_Rijndael::_encryptBlock()
* @access private
* @param String $in
* @return String
*/
function _encryptBlock($in)
{
$state = unpack('N*word', $in);
$Nr = $this->Nr;
$w = $this->w;
$t0 = $this->t0;
$t1 = $this->t1;
$t2 = $this->t2;
$t3 = $this->t3;
// addRoundKey and reindex $state
$state = array(
$state['word1'] ^ $w[0][0],
$state['word2'] ^ $w[0][1],
$state['word3'] ^ $w[0][2],
$state['word4'] ^ $w[0][3]
);
// shiftRows + subWord + mixColumns + addRoundKey
// we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
// only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
for ($round = 1; $round < $this->Nr; $round++) {
$state = array(
$t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
$t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
$t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
$t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
);
}
// subWord
$state = array(
$this->_subWord($state[0]),
$this->_subWord($state[1]),
$this->_subWord($state[2]),
$this->_subWord($state[3])
);
// shiftRows + addRoundKey
$state = array(
($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
);
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
}
/**
* Decrypts a block
*
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
*
* @see Crypt_Rijndael::_decryptBlock()
* @access private
* @param String $in
* @return String
*/
function _decryptBlock($in)
{
$state = unpack('N*word', $in);
$Nr = $this->Nr;
$dw = $this->dw;
$dt0 = $this->dt0;
$dt1 = $this->dt1;
$dt2 = $this->dt2;
$dt3 = $this->dt3;
// addRoundKey and reindex $state
$state = array(
$state['word1'] ^ $dw[$this->Nr][0],
$state['word2'] ^ $dw[$this->Nr][1],
$state['word3'] ^ $dw[$this->Nr][2],
$state['word4'] ^ $dw[$this->Nr][3]
);
// invShiftRows + invSubBytes + invMixColumns + addRoundKey
for ($round = $this->Nr - 1; $round > 0; $round--) {
$state = array(
$dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
$dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
$dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
$dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
);
}
// invShiftRows + invSubWord + addRoundKey
$state = array(
$this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
$this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
$this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
$this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
);
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
}
}
// vim: ts=4:sw=4:et:
// vim6: fdl=1:

+ 0
- 945
library/phpsec/Crypt/DES.php View File

@ -1,945 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of DES.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/DES.php');
*
* $des = new Crypt_DES();
*
* $des->setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->encrypt($plaintext));
* ?>
* </code>
*
* LICENSE: This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* @category Crypt
* @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access private
* @see Crypt_DES::_prepareKey()
* @see Crypt_DES::_processBlock()
*/
/**
* Contains array_reverse($keys[CRYPT_DES_DECRYPT])
*/
define('CRYPT_DES_ENCRYPT', 0);
/**
* Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
*/
define('CRYPT_DES_DECRYPT', 1);
/**#@-*/
/**#@+
* @access public
* @see Crypt_DES::encrypt()
* @see Crypt_DES::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_DES_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_DES_MODE_ECB', 1);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_DES_MODE_CBC', 2);
/**#@-*/
/**#@+
* @access private
* @see Crypt_DES::Crypt_DES()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_DES_MODE_INTERNAL', 1);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_DES_MODE_MCRYPT', 2);
/**#@-*/
/**
* Pure-PHP implementation of DES.
*
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
* @package Crypt_DES
*/
class Crypt_DES {
/**
* The Key Schedule
*
* @see Crypt_DES::setKey()
* @var Array
* @access private
*/
var $keys = "\0\0\0\0\0\0\0\0";
/**
* The Encryption Mode
*
* @see Crypt_DES::Crypt_DES()
* @var Integer
* @access private
*/
var $mode;
/**
* Continuous Buffer status
*
* @see Crypt_DES::enableContinuousBuffer()
* @var Boolean
* @access private
*/
var $continuousBuffer = false;
/**
* Padding status
*
* @see Crypt_DES::enablePadding()
* @var Boolean
* @access private
*/
var $padding = true;
/**
* The Initialization Vector
*
* @see Crypt_DES::setIV()
* @var String
* @access private
*/
var $iv = "\0\0\0\0\0\0\0\0";
/**
* A "sliding" Initialization Vector
*
* @see Crypt_DES::enableContinuousBuffer()
* @var String
* @access private
*/
var $encryptIV = "\0\0\0\0\0\0\0\0";
/**
* A "sliding" Initialization Vector
*
* @see Crypt_DES::enableContinuousBuffer()
* @var String
* @access private
*/
var $decryptIV = "\0\0\0\0\0\0\0\0";
/**
* mcrypt resource for encryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String
* @access private
*/
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Does the (en|de)mcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @var Boolean
* @access private
*/
var $changed = true;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
*
* @param optional Integer $mode
* @return Crypt_DES
* @access public
*/
function Crypt_DES($mode = CRYPT_MODE_DES_CBC)
{
if ( !defined('CRYPT_DES_MODE') ) {
switch (true) {
case extension_loaded('mcrypt'):
// i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
// but since that can be changed after the object has been created, there doesn't seem to be
// a lot of point...
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
break;
default:
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
}
}
switch ( CRYPT_DES_MODE ) {
case CRYPT_DES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CTR:
$this->mode = 'ctr';
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
break;
case CRYPT_DES_MODE_CBC:
default:
$this->mode = MCRYPT_MODE_CBC;
}
break;
default:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
case CRYPT_DES_MODE_CTR:
case CRYPT_DES_MODE_CBC:
$this->mode = $mode;
break;
default:
$this->mode = CRYPT_DES_MODE_CBC;
}
}
}
/**
* Sets the key.
*
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
* null byte if it is less then eight characters long.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* If the key is not explicitly set, it'll be assumed to be all zero's.
*
* @access public
* @param String $key
*/
function setKey($key)
{
$this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key);
$this->changed = true;
}
/**
* Sets the initialization vector. (optional)
*
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
* to be all zero's.
*
* @access public
* @param String $iv
*/
function setIV($iv)
{
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
$this->changed = true;
}
/**
* Generate CTR XOR encryption key
*
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
* plaintext / ciphertext in CTR mode.
*
* @see Crypt_DES::decrypt()
* @see Crypt_DES::encrypt()
* @access public
* @param Integer $length
* @param String $iv
*/
function _generate_xor($length, &$iv)
{
$xor = '';
$num_blocks = ($length + 7) >> 3;
for ($i = 0; $i < $num_blocks; $i++) {
$xor.= $iv;
for ($j = 4; $j <= 8; $j+=4) {
$temp = substr($iv, -$j, 4);
switch ($temp) {
case "\xFF\xFF\xFF\xFF":
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
break;
case "\x7F\xFF\xFF\xFF":
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
break 2;
default:
extract(unpack('Ncount', $temp));
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
break 2;
}
}
}
return $xor;
}
/**
* Encrypts a message.
*
* $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
* URL:
*
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
*
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
* length.
*
* @see Crypt_DES::decrypt()
* @access public
* @param String $plaintext
*/
function encrypt($plaintext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
if ($this->changed) {
if (!isset($this->enmcrypt)) {
$this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
}
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
$this->changed = false;
}
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
}
return $ciphertext;
}
if (!is_array($this->keys)) {
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
}
$ciphertext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
}
break;
case CRYPT_DES_MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
$xor = $block;
$ciphertext.= $block;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case CRYPT_DES_MODE_CTR:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$ciphertext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
}
return $ciphertext;
}
/**
* Decrypts a message.
*
* If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
*
* @see Crypt_DES::encrypt()
* @access public
* @param String $ciphertext
*/
function decrypt($ciphertext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
if ($this->changed) {
if (!isset($this->demcrypt)) {
$this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
}
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
$this->changed = false;
}
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
if (!is_array($this->keys)) {
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
}
$plaintext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
}
break;
case CRYPT_DES_MODE_CBC:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
$xor = $block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case CRYPT_DES_MODE_CTR:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$plaintext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
}
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
}
/**
* Treat consecutive "packets" as if they are a continuous buffer.
*
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
* will yield different outputs:
*
* <code>
* echo $des->encrypt(substr($plaintext, 0, 8));
* echo $des->encrypt(substr($plaintext, 8, 8));
* </code>
* <code>
* echo $des->encrypt($plaintext);
* </code>
*
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
* another, as demonstrated with the following:
*
* <code>
* $des->encrypt(substr($plaintext, 0, 8));
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* </code>
* <code>
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* </code>
*
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
*
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
* however, they are also less intuitive and more likely to cause you problems.
*
* @see Crypt_DES::disableContinuousBuffer()
* @access public
*/
function enableContinuousBuffer()
{
$this->continuousBuffer = true;
}
/**
* Treat consecutive packets as if they are a discontinuous buffer.
*
* The default behavior.
*
* @see Crypt_DES::enableContinuousBuffer()
* @access public
*/
function disableContinuousBuffer()
{
$this->continuousBuffer = false;
$this->encryptIV = $this->iv;
$this->decryptIV = $this->iv;
}
/**
* Pad "packets".
*
* DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
* a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
*
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
* transmitted separately)
*
* @see Crypt_DES::disablePadding()
* @access public
*/
function enablePadding()
{
$this->padding = true;
}
/**
* Do not pad packets.
*
* @see Crypt_DES::enablePadding()
* @access public
*/
function disablePadding()
{
$this->padding = false;
}
/**
* Pads a string
*
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
* 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
*
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
* and padding will, hence forth, be enabled.
*
* @see Crypt_DES::_unpad()
* @access private
*/
function _pad($text)
{
$length = strlen($text);
if (!$this->padding) {
if (($length & 7) == 0) {
return $text;
} else {
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
$this->padding = true;
}