- [bug] Crypt_Rijndael calculated IVs incorrectly

- [new] renamed Crypt_HMAC to Crypt_Hash and revised the API
- [new] added Crypt_AES
- [new] added AES support to Net_SSH2


git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@21 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
Jim Wigginton 2009-02-16 22:22:13 +00:00
parent c30f3b7e9a
commit 39de68ab48
6 changed files with 240 additions and 150 deletions

View File

@ -2,7 +2,7 @@
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/** /**
* Pure-PHP implementations of DES. * Pure-PHP implementation of DES.
* *
* Uses mcrypt, if available, and an internal implementation, otherwise. * Uses mcrypt, if available, and an internal implementation, otherwise.
* *
@ -53,7 +53,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: DES.php,v 1.5 2008-08-04 17:59:12 terrafrost Exp $ * @version $Id: DES.php,v 1.6 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -154,7 +154,7 @@ class Crypt_DES {
* The Initialization Vector * The Initialization Vector
* *
* @see Crypt_DES::setIV() * @see Crypt_DES::setIV()
* @var Integer * @var String
* @access private * @access private
*/ */
var $iv = "\0\0\0\0\0\0\0\0"; var $iv = "\0\0\0\0\0\0\0\0";
@ -163,7 +163,7 @@ class Crypt_DES {
* A "sliding" Initialization Vector * A "sliding" Initialization Vector
* *
* @see Crypt_DES::enableContinuousBuffer() * @see Crypt_DES::enableContinuousBuffer()
* @var Integer * @var String
* @access private * @access private
*/ */
var $encryptIV = "\0\0\0\0\0\0\0\0"; var $encryptIV = "\0\0\0\0\0\0\0\0";
@ -172,7 +172,7 @@ class Crypt_DES {
* A "sliding" Initialization Vector * A "sliding" Initialization Vector
* *
* @see Crypt_DES::enableContinuousBuffer() * @see Crypt_DES::enableContinuousBuffer()
* @var Integer * @var String
* @access private * @access private
*/ */
var $decryptIV = "\0\0\0\0\0\0\0\0"; var $decryptIV = "\0\0\0\0\0\0\0\0";
@ -215,7 +215,8 @@ class Crypt_DES {
case CRYPT_DES_MODE_MCRYPT: case CRYPT_DES_MODE_MCRYPT:
switch ($mode) { switch ($mode) {
case CRYPT_DES_MODE_ECB: case CRYPT_DES_MODE_ECB:
$this->mode = MCRYPT_MODE_ECB; break; $this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CBC: case CRYPT_DES_MODE_CBC:
default: default:
$this->mode = MCRYPT_MODE_CBC; $this->mode = MCRYPT_MODE_CBC;
@ -274,10 +275,10 @@ class Crypt_DES {
* *
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @access public * @access public
* @param Integer $algorithm_directory * @param optional Integer $algorithm_directory
* @param Integer $mode_directory * @param optional Integer $mode_directory
*/ */
function setMCrypt($algorithm_directory, $mode_directory) function setMCrypt($algorithm_directory = '', $mode_directory = '')
{ {
$this->mcrypt = array($algorithm_directory, $mode_directory); $this->mcrypt = array($algorithm_directory, $mode_directory);
} }
@ -504,21 +505,26 @@ class Crypt_DES {
*/ */
function _pad($text) function _pad($text)
{ {
$length = strlen($text);
if (!$this->padding) { if (!$this->padding) {
if (strlen($text) & 7 == 0) { if ($length & 7 == 0) {
return $text; return $text;
} else { } else {
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
$this->padding = true; $this->padding = true;
} }
} }
$length = 8 - (strlen($text) & 7); $pad = 8 - ($length & 7);
return str_pad($text, strlen($text) + $length, chr($length)); return str_pad($text, $length + $pad, chr($pad));
} }
/** /**
* Unpads a string * Unpads a string
* *
* If padding is enabled and the reported padding length exceeds the block size, padding will be, hence forth, disabled.
*
* @see Crypt_DES::_pad() * @see Crypt_DES::_pad()
* @access private * @access private
*/ */
@ -529,6 +535,13 @@ class Crypt_DES {
} }
$length = ord($text[strlen($text) - 1]); $length = ord($text[strlen($text) - 1]);
if ($length > 8) {
user_error("The number of bytes reported as being padded ($length) exceeds the block size (8)", E_USER_NOTICE);
$this->padding = false;
return $text;
}
return substr($text, 0, -$length); return substr($text, 0, -$length);
} }
@ -836,4 +849,3 @@ class Crypt_DES {
// vim: ts=4:sw=4:et: // vim: ts=4:sw=4:et:
// vim6: fdl=1: // vim6: fdl=1:
?>

View File

@ -2,12 +2,30 @@
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/** /**
* Pure-PHP implementation of keyed-hash message authentication codes (HMACs). * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
* *
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports md5 and sha1. * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports md5, md5-96, sha1, and
* sha1-96. If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as
* as opposed to the hash. If no valid algorithm is provided, sha1 will be used.
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* {@internal The variable names are the same as those in
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Hash.php');
*
* $hash = new Crypt_Hash('sha1');
*
* $hash->setKey('abcdefg');
*
* echo base64_encode($hash->hash('abcdefg'));
* ?>
* </code>
*
* LICENSE: This library is free software; you can redistribute it and/or * LICENSE: This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
@ -24,58 +42,54 @@
* MA 02111-1307 USA * MA 02111-1307 USA
* *
* @category Crypt * @category Crypt
* @package Crypt_HMAC * @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: HMAC.php,v 1.3 2007-09-23 04:41:39 terrafrost Exp $ * @version $Id: Hash.php,v 1.1 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_HMAC::Crypt_HMAC() * @see Crypt_Hash::Crypt_Hash()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
*/ */
define('CRYPT_HMAC_MODE_INTERNAL', 1); define('CRYPT_HASH_MODE_INTERNAL', 1);
/** /**
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
*/ */
define('CRYPT_HMAC_MODE_MHASH', 2); define('CRYPT_HASH_MODE_MHASH', 2);
/** /**
* Toggles the hash() implementation, which works on PHP 5.1.2+. * Toggles the hash() implementation, which works on PHP 5.1.2+.
*/ */
define('CRYPT_HMAC_MODE_HASH', 3); define('CRYPT_HASH_MODE_HASH', 3);
/**#@-*/ /**#@-*/
/** /**
* Pure-PHP implementation of keyed-hash message authentication codes (HMACs). * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
* *
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0 * @version 0.1.0
* @access public * @access public
* @package Crypt_HMAC * @package Crypt_Hash
*/ */
class Crypt_HMAC { class Crypt_Hash {
/** /**
* Byte-length of compression blocks * Byte-length of compression blocks / key (Internal HMAC)
* *
* The following URL provides more information: * @see Crypt_Hash::setAlgorithm()
*
* {@link http://tools.ietf.org/html/rfc2104#section-2 http://tools.ietf.org/html/rfc2104#section-2}
*
* @see Crypt_HMAC::setHash()
* @var Integer * @var Integer
* @access private * @access private
*/ */
var $b; var $b;
/** /**
* Byte-length of hash outputs * Byte-length of hash output (Internal HMAC)
* *
* @see Crypt_HMAC::setHash() * @see Crypt_Hash::setHash()
* @var Integer * @var Integer
* @access private * @access private
*/ */
@ -84,7 +98,7 @@ class Crypt_HMAC {
/** /**
* Hash Algorithm * Hash Algorithm
* *
* @see Crypt_HMAC::setHash() * @see Crypt_Hash::setHash()
* @var String * @var String
* @access private * @access private
*/ */
@ -93,65 +107,59 @@ class Crypt_HMAC {
/** /**
* Key * Key
* *
* @see Crypt_HMAC::setKey() * @see Crypt_Hash::setKey()
* @var String * @var String
* @access private * @access private
*/ */
var $key = ''; var $key = '';
/** /**
* Outer XOR * Outer XOR (Internal HMAC)
* *
* @see Crypt_HMAC::setKey() * @see Crypt_Hash::setKey()
* @var String * @var String
* @access private * @access private
*/ */
var $opad; var $opad;
/** /**
* Inner XOR * Inner XOR (Internal HMAC)
* *
* @see Crypt_HMAC::setKey() * @see Crypt_Hash::setKey()
* @var String * @var String
* @access private * @access private
*/ */
var $ipad; var $ipad;
/**
* Final HMAC Length
*
* @see Crypt_HMAC::hmac()
* @var String
* @access private
*/
var $length = 0;
/** /**
* Default Constructor. * Default Constructor.
* *
* @return Crypt_HMAC * @param optional String $hash
* @return Crypt_Hash
* @access public * @access public
*/ */
function Crypt_HMAC() function Crypt_Hash($hash = 'sha1')
{ {
if ( !defined('CRYPT_HMAC_MODE') ) { if ( !defined('CRYPT_HASH_MODE') ) {
switch (true) { switch (true) {
case extension_loaded('hash'): case extension_loaded('hash'):
define('CRYPT_HMAC_MODE', CRYPT_HMAC_MODE_HASH); define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
break; break;
case extension_loaded('mhash'): case extension_loaded('mhash'):
define('CRYPT_HMAC_MODE', CRYPT_HMAC_MODE_MHASH); define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
break; break;
default: default:
define('CRYPT_HMAC_MODE', CRYPT_HMAC_MODE_INTERNAL); define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
} }
} }
$this->setHash('sha1'); $this->setHash($hash);
} }
/** /**
* Sets the key. * Sets the key for HMACs
*
* Keys can be of any length.
* *
* @access public * @access public
* @param String $key * @param String $key
@ -164,8 +172,6 @@ class Crypt_HMAC {
/** /**
* Sets the hash function. * Sets the hash function.
* *
* Currently, only 'sha1' and 'md5' are supported. If you do not supply a valid $hash, 'sha1' will be used.
*
* @access public * @access public
* @param String $hash * @param String $hash
*/ */
@ -174,7 +180,13 @@ class Crypt_HMAC {
switch ($hash) { switch ($hash) {
case 'md5-96': case 'md5-96':
case 'sha1-96': case 'sha1-96':
$this->length = 12; $this->l = 12; // 96 / 8 = 12
break;
case 'md5':
$this->l = 16;
break;
case 'sha1':
$this->l = 20;
} }
switch (CRYPT_HMAC_MODE) { switch (CRYPT_HMAC_MODE) {
@ -208,14 +220,12 @@ class Crypt_HMAC {
case 'md5': case 'md5':
case 'md5-96': case 'md5-96':
$this->b = 64; $this->b = 64;
$this->l = 16;
$this->hash = 'md5'; $this->hash = 'md5';
break; break;
case 'sha1': case 'sha1':
case 'sha1-96': case 'sha1-96':
default: default:
$this->b = 64; $this->b = 64;
$this->l = 20;
$this->hash = 'sha1'; $this->hash = 'sha1';
} }
@ -229,28 +239,46 @@ class Crypt_HMAC {
* @access public * @access public
* @param String $text * @param String $text
*/ */
function hmac($text) function hash($text)
{ {
switch (CRYPT_HMAC_MODE) { if (!empty($this->key)) {
case CRYPT_HMAC_MODE_MHASH: switch (CRYPT_HASH_MODE) {
$hmac = mhash($this->hash, $text, $this->key); case CRYPT_HASH_MODE_MHASH:
break; $output = mhash($this->hash, $text, $this->key);
case CRYPT_HMAC_MODE_HASH: break;
$hmac = hash_hmac($this->hash, $text, $this->key, true); case CRYPT_HASH_MODE_HASH:
break; $output = hash_hmac($this->hash, $text, $this->key, true);
case CRYPT_HMAC_MODE_INTERNAL: break;
$hash = $this->hash; case CRYPT_HASH_MODE_INTERNAL:
$hash = $this->hash;
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the
resultant L byte string as the actual key to HMAC."
$key = strlen($this->key) > $this->b ? $this->hash($this->key) : $this->key; -- http://tools.ietf.org/html/rfc2104#section-2 */
$key = str_pad($key, $this->b, chr(0)); // step 1 $key = strlen($this->key) > $this->b ? $hash($this->key) : $this->key;
$temp = $this->ipad ^ $key; // step 2
$temp.= $text; // step 3 $key = str_pad($key, $this->b, chr(0));// step 1
$temp = pack('H*', $hash($temp)); // step 4 $temp = $this->ipad ^ $key; // step 2
$hmac = $this->opad ^ $key; // step 5 $temp .= $text; // step 3
$hmac.= $temp; // step 6 $temp = pack('H*', $hash($temp)); // step 4
$hmac = pack('H*', $hash($hmac)); // step 7 $output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$output = pack('H*', $hash($output)); // step 7
}
} else {
switch (CRYPT_HASH_MODE) {
case CRYPT_HASH_MODE_MHASH:
$output = mhash($this->hash, $text);
break;
case CRYPT_HASH_MODE_MHASH:
$output = hash($this->hash, $text, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$hash = $this->hash;
$output = pack('H*', $hash($output));
}
} }
return $this->length ? substr($hmac, 0, $this->length) : $hmac; return substr($output, 0, $this->l);
} }
} }

View File

@ -55,7 +55,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: RC4.php,v 1.3 2007-07-25 21:56:14 terrafrost Exp $ * @version $Id: RC4.php,v 1.4 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -259,10 +259,10 @@ class Crypt_RC4 {
* *
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @access public * @access public
* @param Integer $algorithm_directory * @param optional Integer $algorithm_directory
* @param Integer $mode_directory * @param optional Integer $mode_directory
*/ */
function setMCrypt($algorithm_directory, $mode_directory) function setMCrypt($algorithm_directory = '', $mode_directory = '')
{ {
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
$this->mcrypt = array($algorithm_directory, $mode_directory); $this->mcrypt = array($algorithm_directory, $mode_directory);

View File

@ -4,8 +4,7 @@
/** /**
* Pure-PHP implementation of Rijndael. * Pure-PHP implementation of Rijndael.
* *
* Does not use mcrypt, even when available, since mcrypt doesn't implement Rijndael - it implements a subset of Rijndael * Does not use mcrypt, even when available, for reasons that are explained below.
* known as AES.
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
@ -15,8 +14,8 @@
* 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until * 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. * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
* *
* Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. AES, itself, only * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
* supports block lengths of 128 and key lengths of 128, 192, and 256. * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
* algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224 * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
* are first defined as valid key / block lengths in * are first defined as valid key / block lengths in
@ -65,7 +64,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright MMVIII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: Rijndael.php,v 1.1 2009-02-01 15:37:25 terrafrost Exp $ * @version $Id: Rijndael.php,v 1.2 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -88,6 +87,20 @@ define('CRYPT_RIJNDAEL_MODE_ECB', 1);
define('CRYPT_RIJNDAEL_MODE_CBC', 2); define('CRYPT_RIJNDAEL_MODE_CBC', 2);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_AES::Crypt_AES()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
/**#@-*/
/** /**
* Pure-PHP implementation of Rijndael. * Pure-PHP implementation of Rijndael.
* *
@ -338,6 +351,11 @@ class Crypt_Rijndael {
/** /**
* Default Constructor. * Default Constructor.
* *
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
* CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
*
* @param optional Integer $mode
* @return Crypt_Rijndael
* @access public * @access public
*/ */
function Crypt_Rijndael($mode = CRYPT_MODE_RIJNDAEL_CBC) { function Crypt_Rijndael($mode = CRYPT_MODE_RIJNDAEL_CBC) {
@ -464,7 +482,7 @@ class Crypt_Rijndael {
*/ */
function setIV($iv) function setIV($iv)
{ {
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));; $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));;
} }
/** /**
@ -1013,6 +1031,7 @@ class Crypt_Rijndael {
} }
$pad = $this->block_size - ($length % $this->block_size); $pad = $this->block_size - ($length % $this->block_size);
return str_pad($text, $length + $pad, chr($pad)); return str_pad($text, $length + $pad, chr($pad));
} }

View File

@ -47,7 +47,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: TripleDES.php,v 1.4 2008-08-04 17:59:12 terrafrost Exp $ * @version $Id: TripleDES.php,v 1.5 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -119,7 +119,7 @@ class Crypt_TripleDES {
* The Initialization Vector * The Initialization Vector
* *
* @see Crypt_TripleDES::setIV() * @see Crypt_TripleDES::setIV()
* @var Integer * @var String
* @access private * @access private
*/ */
var $iv = "\0\0\0\0\0\0\0\0"; var $iv = "\0\0\0\0\0\0\0\0";
@ -128,7 +128,7 @@ class Crypt_TripleDES {
* A "sliding" Initialization Vector * A "sliding" Initialization Vector
* *
* @see Crypt_TripleDES::enableContinuousBuffer() * @see Crypt_TripleDES::enableContinuousBuffer()
* @var Integer * @var String
* @access private * @access private
*/ */
var $encryptIV = "\0\0\0\0\0\0\0\0"; var $encryptIV = "\0\0\0\0\0\0\0\0";
@ -137,7 +137,7 @@ class Crypt_TripleDES {
* A "sliding" Initialization Vector * A "sliding" Initialization Vector
* *
* @see Crypt_TripleDES::enableContinuousBuffer() * @see Crypt_TripleDES::enableContinuousBuffer()
* @var Integer * @var String
* @access private * @access private
*/ */
var $decryptIV = "\0\0\0\0\0\0\0\0"; var $decryptIV = "\0\0\0\0\0\0\0\0";
@ -292,10 +292,10 @@ class Crypt_TripleDES {
* *
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @access public * @access public
* @param Integer $algorithm_directory * @param optional Integer $algorithm_directory
* @param Integer $mode_directory * @param optional Integer $mode_directory
*/ */
function setMCrypt($algorithm_directory, $mode_directory) function setMCrypt($algorithm_directory = '', $mode_directory = '')
{ {
$this->mcrypt = array($algorithm_directory, $mode_directory); $this->mcrypt = array($algorithm_directory, $mode_directory);
if ( $this->mode == CRYPT_DES_MODE_3CBC ) { if ( $this->mode == CRYPT_DES_MODE_3CBC ) {
@ -560,21 +560,26 @@ class Crypt_TripleDES {
*/ */
function _pad($text) function _pad($text)
{ {
$length = strlen($text);
if (!$this->padding) { if (!$this->padding) {
if (strlen($text) & 7 == 0) { if ($length & 7 == 0) {
return $text; return $text;
} else { } else {
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
$this->padding = true; $this->padding = true;
} }
} }
$length = 8 - (strlen($text) & 7); $pad = 8 - ($length & 7);
return str_pad($text, strlen($text) + $length, chr($length)); return str_pad($text, $length + $pad, chr($pad));
} }
/** /**
* Unpads a string * Unpads a string
* *
* If padding is enabled and the reported padding length exceeds the block size, padding will be, hence forth, disabled.
*
* @see Crypt_TripleDES::_pad() * @see Crypt_TripleDES::_pad()
* @access private * @access private
*/ */
@ -585,10 +590,16 @@ class Crypt_TripleDES {
} }
$length = ord($text[strlen($text) - 1]); $length = ord($text[strlen($text) - 1]);
if ($length > 8) {
user_error("The number of bytes reported as being padded ($length) exceeds the block size (8)", E_USER_NOTICE);
$this->padding = false;
return $text;
}
return substr($text, 0, -$length); return substr($text, 0, -$length);
} }
} }
// vim: ts=4:sw=4:et: // vim: ts=4:sw=4:et:
// vim6: fdl=1: // vim6: fdl=1:
?>

View File

@ -41,7 +41,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: SSH2.php,v 1.8 2008-05-26 19:42:01 terrafrost Exp $ * @version $Id: SSH2.php,v 1.9 2009-02-16 22:22:13 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -58,20 +58,25 @@ require_once('Math/BigInteger.php');
require_once('Crypt/Random.php'); require_once('Crypt/Random.php');
/** /**
* Include Crypt_HMAC.php * Include Crypt_Hash
*/ */
require_once('Crypt/HMAC.php'); require_once('Crypt/Hash.php');
/** /**
* Include Crypt_TripleDES.php * Include Crypt_TripleDES
*/ */
require_once('Crypt/TripleDES.php'); require_once('Crypt/TripleDES.php');
/** /**
* Include Crypt_RC4.php * Include Crypt_RC4
*/ */
require_once('Crypt/RC4.php'); require_once('Crypt/RC4.php');
/**
* Include Crypt_AES
*/
require_once('Crypt/AES.php');
/**#@+ /**#@+
* Execution Bitmap Masks * Execution Bitmap Masks
* *
@ -227,13 +232,31 @@ class Net_SSH2 {
var $languages_client_to_server; var $languages_client_to_server;
/** /**
* Block Size * Block Size for Server to Client Encryption
* *
* "Note that the length of the concatenation of 'packet_length',
* 'padding_length', 'payload', and 'random padding' MUST be a multiple
* of the cipher block size or 8, whichever is larger. This constraint
* MUST be enforced, even when using stream ciphers."
*
* -- http://tools.ietf.org/html/rfc4253#section-6
*
* @see Net_SSH2::Net_SSH2()
* @see Net_SSH2::_send_binary_packet() * @see Net_SSH2::_send_binary_packet()
* @var Integer * @var Integer
* @access private * @access private
*/ */
var $block_size = 8; var $encrypt_block_size = 8;
/**
* Block Size for Client to Server Encryption
*
* @see Net_SSH2::Net_SSH2()
* @see Net_SSH2::_get_binary_packet()
* @var Integer
* @access private
*/
var $decrypt_block_size = 8;
/** /**
* Server to Client Encryption Object * Server to Client Encryption Object
@ -525,11 +548,11 @@ class Net_SSH2 {
); );
static $encryption_algorithms = array( static $encryption_algorithms = array(
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
'aes192-cbc', // OPTIONAL AES with a 192-bit key 'aes192-cbc', // OPTIONAL AES with a 192-bit key
'aes128-cbc', // RECOMMENDED AES with a 128-bit key 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
'none' // OPTIONAL no encryption; NOT RECOMMENDED 'none' // OPTIONAL no encryption; NOT RECOMMENDED
); );
@ -628,9 +651,7 @@ class Net_SSH2 {
$decrypt = $encryption_algorithms[$i]; $decrypt = $encryption_algorithms[$i];
switch ($decrypt) { switch ($decrypt) {
case '3des-cbc': case '3des-cbc':
// uses the default block size
$decryptKeyLength = 24; // eg. 192 / 8 $decryptKeyLength = 24; // eg. 192 / 8
$decryptIVLength = 8; // eg. 64 / 8
break; break;
case 'aes256-cbc': case 'aes256-cbc':
$decryptKeyLength = 32; // eg. 256 / 8 $decryptKeyLength = 32; // eg. 256 / 8
@ -643,7 +664,6 @@ class Net_SSH2 {
break; break;
case 'arcfour': case 'arcfour':
$decryptKeyLength = 16; // eg. 128 / 8 $decryptKeyLength = 16; // eg. 128 / 8
$decryptIVLength = 0;
break; break;
case 'none'; case 'none';
$decryptKeyLength = 0; $decryptKeyLength = 0;
@ -659,7 +679,6 @@ class Net_SSH2 {
switch ($encrypt) { switch ($encrypt) {
case '3des-cbc': case '3des-cbc':
$encryptKeyLength = 24; $encryptKeyLength = 24;
$encryptIVLength = 8;
break; break;
case 'aes256-cbc': case 'aes256-cbc':
$encryptKeyLength = 32; $encryptKeyLength = 32;
@ -672,7 +691,6 @@ class Net_SSH2 {
break; break;
case 'arcfour': case 'arcfour':
$encryptKeyLength = 16; $encryptKeyLength = 16;
$encryptIVLength = 0;
break; break;
case 'none'; case 'none';
$encryptKeyLength = 0; $encryptKeyLength = 0;
@ -917,15 +935,19 @@ class Net_SSH2 {
switch ($encrypt) { switch ($encrypt) {
case '3des-cbc': case '3des-cbc':
$this->encrypt = new Crypt_TripleDES(); $this->encrypt = new Crypt_TripleDES();
// $this->encrypt_block_size = 64 / 8 == the default
break; break;
case 'aes256-cbc': case 'aes256-cbc':
//$this->encrypt = new Crypt_AES(); $this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16; // eg. 128 / 8
break; break;
case 'aes192-cbc': case 'aes192-cbc':
//$this->encrypt = new Crypt_AES(); $this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16;
break; break;
case 'aes128-cbc': case 'aes128-cbc':
//$this->encrypt = new Crypt_AES(); $this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16;
break; break;
case 'arcfour': case 'arcfour':
$this->encrypt = new Crypt_RC4(); $this->encrypt = new Crypt_RC4();
@ -939,13 +961,16 @@ class Net_SSH2 {
$this->decrypt = new Crypt_TripleDES(); $this->decrypt = new Crypt_TripleDES();
break; break;
case 'aes256-cbc': case 'aes256-cbc':
//$this->decrypt = new Crypt_AES(); $this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break; break;
case 'aes192-cbc': case 'aes192-cbc':
//$this->decrypt = new Crypt_AES(); $this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break; break;
case 'aes128-cbc': case 'aes128-cbc':
//$this->decrypt = new Crypt_AES(); $this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break; break;
case 'arcfour': case 'arcfour':
$this->decrypt = new Crypt_RC4(); $this->decrypt = new Crypt_RC4();
@ -966,26 +991,22 @@ class Net_SSH2 {
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
} }
$this->hmac_create = new Crypt_HMAC(); $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'none':
$this->hmac_create->setHash('none');
$createKeyLength = 0;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_create->setHash('sha1'); $this->hmac_create = new Crypt_Hash('sha1');
$createKeyLength = 20; $createKeyLength = 20;
break; break;
case 'hmac-sha1-96': case 'hmac-sha1-96':
$this->hmac_create->setHash('sha1-96'); $this->hmac_create = new Crypt_Hash('sha1-96');
$createKeyLength = 20; $createKeyLength = 20;
break; break;
case 'hmac-md5': case 'hmac-md5':
$this->hmac_create->setHash('md5'); $this->hmac_create = new Crypt_Hash('md5');
$createKeyLength = 16; $createKeyLength = 16;
break; break;
case 'hmac-md5-96': case 'hmac-md5-96':
$this->hmac_create->setHash('md5-96'); $this->hmac_create = new Crypt_Hash('md5-96');
$createKeyLength = 16; $createKeyLength = 16;
} }
@ -995,30 +1016,26 @@ class Net_SSH2 {
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
} }
$this->hmac_check = new Crypt_HMAC(); $checkKeyLength = 0;
$this->hmac_size = 0;
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'none':
$this->hmac_check->setHash('none');
$checkKeyLength = 0;
$this->hmac_size = 0;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_check->setHash('sha1'); $this->hmac_check = new Crypt_Hash('sha1');
$checkKeyLength = 20; $checkKeyLength = 20;
$this->hmac_size = 20; $this->hmac_size = 20;
break; break;
case 'hmac-sha1-96': case 'hmac-sha1-96':
$this->hmac_check->setHash('sha1-96'); $this->hmac_check = new Crypt_Hash('sha1-96');
$checkKeyLength = 20; $checkKeyLength = 20;
$this->hmac_size = 12; $this->hmac_size = 12;
break; break;
case 'hmac-md5': case 'hmac-md5':
$this->hmac_check->setHash('md5'); $this->hmac_check = new Crypt_Hash('md5');
$checkKeyLength = 16; $checkKeyLength = 16;
$this->hmac_size = 16; $this->hmac_size = 16;
break; break;
case 'hmac-md5-96': case 'hmac-md5-96':
$this->hmac_check->setHash('md5-96'); $this->hmac_check = new Crypt_Hash('md5-96');
$checkKeyLength = 16; $checkKeyLength = 16;
$this->hmac_size = 12; $this->hmac_size = 12;
} }
@ -1026,16 +1043,16 @@ class Net_SSH2 {
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
$iv = pack('H*', $hash($keyBytes . $source . 'A' . $this->session_id)); $iv = pack('H*', $hash($keyBytes . $source . 'A' . $this->session_id));
while ($encryptIVLength > strlen($iv)) { while ($this->encrypt_block_size > strlen($iv)) {
$iv.= pack('H*', $hash($keyBytes . $source . $iv)); $iv.= pack('H*', $hash($keyBytes . $source . $iv));
} }
$this->encrypt->setIV(substr($iv, 0, $encryptIVLength)); $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
$iv = pack('H*', $hash($keyBytes . $source . 'B' . $this->session_id)); $iv = pack('H*', $hash($keyBytes . $source . 'B' . $this->session_id));
while ($decryptIVLength > strlen($iv)) { while ($this->decrypt_block_size > strlen($iv)) {
$iv.= pack('H*', $hash($keyBytes . $source . $iv)); $iv.= pack('H*', $hash($keyBytes . $source . $iv));
} }
$this->decrypt->setIV(substr($iv, 0, $decryptIVLength)); $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
$key = pack('H*', $hash($keyBytes . $source . 'C' . $this->session_id)); $key = pack('H*', $hash($keyBytes . $source . 'C' . $this->session_id));
while ($encryptKeyLength > strlen($key)) { while ($encryptKeyLength > strlen($key)) {
@ -1331,7 +1348,7 @@ class Net_SSH2 {
return false; return false;
} }
$raw = fread($this->fsock, $this->block_size); $raw = fread($this->fsock, $this->decrypt_block_size);
if ($this->decrypt !== false) { if ($this->decrypt !== false) {
$raw = $this->decrypt->decrypt($raw); $raw = $this->decrypt->decrypt($raw);
@ -1341,8 +1358,11 @@ class Net_SSH2 {
$packet_length = $temp['packet_length']; $packet_length = $temp['packet_length'];
$padding_length = $temp['padding_length']; $padding_length = $temp['padding_length'];
$temp = fread($this->fsock, $packet_length + 4 - $this->block_size); $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($temp) : $temp; if ($remaining_length > 0) {
$temp = fread($this->fsock, $remaining_length);
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($temp) : $temp;
}
$payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
$padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty $padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
@ -1464,10 +1484,10 @@ class Net_SSH2 {
return false; return false;
} }
// 4, for the packet length + 1, for the padding length + 4, for the minimal padding amount // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
$packet_length = strlen($data) + 9; $packet_length = strlen($data) + 9;
// round up to the nearest $this->block_size // round up to the nearest $this->encrypt_block_size
$packet_length+= (($this->block_size - 1) * $packet_length) % $this->block_size; $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
// subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
$padding_length = $packet_length - strlen($data) - 5; $padding_length = $packet_length - strlen($data) - 5;