diff --git a/core/src/plugins/access.sftp_psl/SFTPPSL_StreamWrapper.php b/core/src/plugins/access.sftp_psl/SFTPPSL_StreamWrapper.php index 0a3315cf8e..7a12584cd9 100644 --- a/core/src/plugins/access.sftp_psl/SFTPPSL_StreamWrapper.php +++ b/core/src/plugins/access.sftp_psl/SFTPPSL_StreamWrapper.php @@ -112,719 +112,729 @@ * @package Net_SFTP_StreamWrapper * @link http://www.php.net/manual/en/class.streamwrapper.php */ -class SFTPPSL_StreamWrapper -{ - /** - * SFTP Object - * - * @var Net_SFTP - * @access private - */ - private $sftp; - - /** - * SFTP Path - * - * @var String - * @access private - */ - private $path; - - /** - * Pointer Offset - * - * @var Integer - * @access private - */ - private $position; - - /** - * Context resource - * - * @var Resource - * @access public - */ - public $context; - - /** - * Mode - * - * SUPPORTED: r, r+, w, w+, a, a+, c, c+ - * NOT SUPPORTED: x, x+ - * - * @var String - * @access private - */ - private $mode; - - /** - * SFTP Connection Instances - * - * Rather than re-create the connection we re-use instances if possible - * - * @var array - * @access private - */ - private static $instances; - - /** - * Directory Listing - * - * @var array - * @access private - */ - private $dir_entries; - - /** - * This method is called in response to closedir() - * - * Closes a directory handle - * - * Alias of stream_close() - * - * @return bool - * @access public - */ - public function dir_closedir() - { - $this->stream_close(); - - $this->dir_entries = FALSE; - - return TRUE; - } - - /** - * This method is called in response to opendir() - * - * Opens up a directory handle to be used in subsequent closedir(), readdir(), and rewinddir() calls - * - * NOTES: - * It loads the entire directory contents into memory. - * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and removed in 5.4 we are going - * to ignore it - * - * @param String $path - * @param Integer $options - * @return bool - * @access public - */ - public function dir_opendir($path, $options) - { - if ( $this->stream_open($path, NULL, NULL, $opened_path) ) { - $this->dir_entries = $this->sftp->nlist($this->path); - return TRUE; - } else { - return FALSE; - } - } - - /** - * This method is called in response to readdir() - * - * Reads entry from directory - * - * NOTE: In this method, Pointer Offset is an index of the array returned by Net_SFTP::nlist() - * - * @return string - * @access public - */ - public function dir_readdir() - { - if ($this->dir_entries === false) { - return FALSE; - } - - if ( isset($this->dir_entries[$this->position]) ) { - $filename = $this->dir_entries[$this->position]; - - $this->position += 1; - - return $filename; - } else { - return FALSE; - } - } - - /** - * This method is called in response to rewinddir() - * - * Resets the directory pointer to the beginning of the directory - * - * @return bool - * @access public - */ - public function dir_rewinddir() - { - $this->position = 0; - - return TRUE; - } - - /** - * Attempts to create the directory specified by the path - * - * Makes a directory - * - * NOTE: Only valid option is STREAM_MKDIR_RECURSIVE ( http://www.php.net/manual/en/function.mkdir.php ) - * - * @param String $path - * @param Integer $mode - * @param Integer $options - * @return bool - * @access public - */ - public function mkdir($path, $mode, $options) - { - $connection = $this->stream_open($path, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - if ($options === STREAM_MKDIR_RECURSIVE) { - $mkdir = $this->sftp->mkdir($this->path, $mode, true); - } else { - $mkdir = $this->sftp->mkdir($this->path, $mode, false); - } - - $this->stream_close(); - - return $mkdir; - } - - /** - * Attempts to rename path_from to path_to - * - * Attempts to rename oldname to newname, moving it between directories if necessary. - * If newname exists, it will be overwritten. - * - * @param String $path_from - * @param String $path_to - * @return bool - * @access public - */ - public function rename($path_from, $path_to) - { - $path1 = parse_url($path_from); - $path2 = parse_url($path_to); - unset($path1['path'], $path2['path']); - if ($path1 != $path2) { - return FALSE; - } - unset($path1, $path2); - - $connection = $this->stream_open($path_from, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - $path_to = parse_url($path_to, PHP_URL_PATH); - - // "It is an error if there already exists a file with the name specified by newpath." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 - if (!$this->sftp->rename($this->path, $path_to)) { - if ($this->sftp->stat($path_to)) { - $del = $this->sftp->delete($path_to, true); - $rename = $this->sftp->rename($this->path, $path_to); - - $this->stream_close(); - return $del && $rename; - } - } - - $this->stream_close(); - return TRUE; - } - - /** - * Attempts to remove the directory named by the path - * - * Removes a directory - * - * NOTE: rmdir() does not have a $recursive parameter as mkdir() does ( http://www.php.net/manual/en/streamwrapper.rmdir.php ) - * - * @param String $path - * @param Integer $options - * @return bool - * @access public - */ - public function rmdir($path, $options) - { - $connection = $this->stream_open($path, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - $rmdir = $this->sftp->rmdir($this->path); - - $this->stream_close(); - - return $rmdir; - } - - /** - * This method is called in response to stream_select() - * - * Retrieves the underlaying resource - * - * @param Integer $cast_as - * @return resource - * @access public - */ - public function stream_cast($cast_as) - { - return $this->sftp->fsock; - } - - /** - * This method is called in response to fclose() - * - * Closes SFTP connection - * - * @return void - * @access public - */ - public function stream_close() - { - // We do not really close connections because - // connections are assigned to a class static variable, so the Net_SFTP object will persist - // even after the stream object has been destroyed. But even without that, it's probably - // unnecessary as it'd be garbage collected out anyway. - // http://www.frostjedi.com/phpbb3/viewtopic.php?f=46&t=167493&sid=3161a478bd0bb359f6cefc956d6ac488&start=15#p391181 - - //$this->sftp->disconnect(); - - $this->position = 0; - } - - /** - * This method is called in response to feof() - * - * Tests for end-of-file on a file pointer - * - * @return bool - * @access public - */ - public function stream_eof() - { - $filesize = $this->sftp->size($this->path); - - if ($this->position >= $filesize) { - return TRUE; - } else { - return FALSE; - } - } - - /** - * This method is called in response to fflush() - * - * NOTE: Always returns true because Net_SFTP doesn't cache stuff before writing - * - * @return bool - * @access public - */ - public function stream_flush() - { - return TRUE; - } - - /** - * Advisory file locking - * - * Not Implemented - * - * @param Integer $operation - * @return Boolean - * @access public - */ - public function stream_lock($operation) - { - return FALSE; - } - - /** - * This method is called to set metadata on the stream. It is called when one of the following functions is called on a stream URL: - * - touch() - * - chmod() - * - chown() - * - chgrp() - * - * Changes stream options - * - * @param String $path - * @param Integer $option - * @param mixed $var - * @return bool - * @access public - */ - public function stream_metadata($path, $option, $var) - { - $connection = $this->stream_open($path, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - switch ($option) { - case 1: // PHP_STREAM_META_TOUCH - $touch = $this->sftp->touch($this->path, $var[1], $var[0]); - - $this->stream_close(); - return $touch; - - case 2: // PHP_STREAM_META_OWNER_NAME - $this->stream_close(); - return FALSE; - - case 3: // PHP_STREAM_META_OWNER - $chown = $this->sftp->chown($this->path, $var); - - $this->stream_close(); - return $chown; - - case 4: // PHP_STREAM_META_GROUP_NAME - $this->stream_close(); - return FALSE; - - case 5: // PHP_STREAM_META_GROUP - $chgrp = $this->sftp->chgrp($this->path, $var); - - $this->stream_close(); - return $chgrp; - - case 6: // PHP_STREAM_META_ACCESS - $chmod = $this->sftp->chmod($var, $this->path); - - $this->stream_close(); - return $chmod; - - default: - $this->stream_close(); - return FALSE; - } - } - - /** - * This method is called immediately after the wrapper is initialized - * - * Connects to an SFTP server - * - * NOTE: This method is not get called by default for the following functions: - * dir_opendir(), mkdir(), rename(), rmdir(), stream_metadata(), unlink() and url_stat() - * So I implemented a call to stream_open() at the beginning of the functions and stream_close() at the end - * - * The wrapper will also reuse open connections - * - * @param String $path - * @param String $mode - * @param Integer $options - * @param String &$opened_path - * @return bool - * @access public - */ - public function stream_open($path, $mode, $options, &$opened_path) - { - $url = parse_url($path); - - $host = $url["host"]; - $port = $url["port"]; - $user = $url["user"]; - $pass = $url["pass"]; - - $this->path = $url["path"]; - - $connection_uuid = md5( $host.$port.$user ); // Generate a unique ID for the current connection - - if ( isset(self::$instances[$connection_uuid]) ) { - // Get previously established connection - $this->sftp = self::$instances[$connection_uuid]; - } else { - //$context = stream_context_get_options($this->context); - - if (!isset($user) || !isset($pass)) { - return FALSE; - } - - // Connection - $sftp = new Net_SFTP($host, isset($port) ? $port : 22); - if (!$sftp->login($user, $pass)) { - return FALSE; - } - - // Store connection instance - self::$instances[$connection_uuid] = $sftp; - - // Get current connection - $this->sftp = $sftp; - } - - $filesize = $this->sftp->size($this->path); - - if (isset($mode)) { - $this->mode = preg_replace('#[bt]$#', '', $mode); - } else { - $this->mode = 'r'; - } - - switch ($this->mode[0]) { - case 'r': - $this->position = 0; - break; - case 'w': - $this->position = 0; - if ($filesize === FALSE) { - $this->sftp->touch( $this->path ); - } else { - $this->sftp->truncate( $this->path, 0 ); - } - break; - case 'a': - if ($filesize === FALSE) { - $this->position = 0; - $this->sftp->touch( $this->path ); - } else { - $this->position = $filesize; - } - break; - case 'c': - $this->position = 0; - if ($filesize === FALSE) { - $this->sftp->touch( $this->path ); - } - break; - - default: - return FALSE; - } - - if ($options == STREAM_USE_PATH) { - $opened_path = $this->sftp->pwd(); - } - - return TRUE; - } - - /** - * This method is called in response to fread() and fgets() - * - * Reads from stream - * - * @param Integer $count - * @return mixed - * @access public - */ - public function stream_read($count) - { - switch ($this->mode) { - case 'w': - case 'a': - case 'x': - case 'x+': - case 'c': - return FALSE; - } - - $chunk = $this->sftp->get( $this->path, FALSE, $this->position, $count ); - - $this->position += strlen($chunk); - - return $chunk; - } - - /** - * This method is called in response to fseek() - * - * Seeks to specific location in a stream - * - * @param Integer $offset - * @param Integer $whence = SEEK_SET - * @return bool - * @access public - */ - public function stream_seek($offset, $whence) - { - $filesize = $this->sftp->size($this->path); - - switch ($whence) { - case SEEK_SET: +class SFTPPSL_StreamWrapper{ + + /** + * SFTP Object + * + * @var Net_SFTP + * @access private + */ + private $sftp; + + /** + * SFTP Path + * + * @var String + * @access private + */ + private $path; + + /** + * Pointer Offset + * + * @var Integer + * @access private + */ + private $position; + + /** + * Context resource + * + * @var Resource + * @access public + */ + var $context; + + /** + * Mode + * + * SUPPORTED: r, r+, w, w+, a, a+, c, c+ + * NOT SUPPORTED: x, x+ + * + * @var String + * @access private + */ + private $mode; + + /** + * SFTP Connection Instances + * + * Rather than re-create the connection we re-use instances if possible + * + * @var array + * @access private + */ + private static $instances; + + /** + * Directory Listing + * + * @var array + * @access private + */ + private $dir_entries; + + /** + * This method is called in response to closedir() + * + * Closes a directory handle + * + * Alias of stream_close() + * + * @return bool + * @access public + */ + function dir_closedir() + { + $this->stream_close(); + + $this->dir_entries = FALSE; + + return TRUE; + } + + /** + * This method is called in response to opendir() + * + * Opens up a directory handle to be used in subsequent closedir(), readdir(), and rewinddir() calls + * + * NOTES: + * It loads the entire directory contents into memory. + * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and removed in 5.4 we are going + * to ignore it + * + * @param String $path + * @param Integer $options + * @return bool + * @access public + */ + function dir_opendir($path, $options) + { + if ( $this->stream_open($path, NULL, NULL, $opened_path) ) { + $this->dir_entries = $this->sftp->nlist($this->path); + return TRUE; + } + else { + return FALSE; + } + } + + /** + * This method is called in response to readdir() + * + * Reads entry from directory + * + * NOTE: In this method, Pointer Offset is an index of the array returned by Net_SFTP::nlist() + * + * @return string + * @access public + */ + function dir_readdir() + { + if ($this->dir_entries === false) { + return FALSE; + } + + if ( isset($this->dir_entries[$this->position]) ) { + $filename = $this->dir_entries[$this->position]; + + $this->position += 1; + + return $filename; + } + else { + return FALSE; + } + } + + /** + * This method is called in response to rewinddir() + * + * Resets the directory pointer to the beginning of the directory + * + * @return bool + * @access public + */ + function dir_rewinddir() + { + $this->position = 0; + + return TRUE; + } + + /** + * Attempts to create the directory specified by the path + * + * Makes a directory + * + * NOTE: Only valid option is STREAM_MKDIR_RECURSIVE ( http://www.php.net/manual/en/function.mkdir.php ) + * + * @param String $path + * @param Integer $mode + * @param Integer $options + * @return bool + * @access public + */ + function mkdir($path, $mode, $options) + { + $connection = $this->stream_open($path, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + if ( $options === STREAM_MKDIR_RECURSIVE ) { + $mkdir = $this->sftp->mkdir($this->path, $mode, true); + } + else { + $mkdir = $this->sftp->mkdir($this->path, $mode, false); + } + + $this->stream_close(); + + return $mkdir; + } + + /** + * Attempts to rename path_from to path_to + * + * Attempts to rename oldname to newname, moving it between directories if necessary. + * If newname exists, it will be overwritten. + * + * @param String $path_from + * @param String $path_to + * @return bool + * @access public + */ + function rename($path_from, $path_to) + { + $path1 = parse_url($path_from); + $path2 = parse_url($path_to); + unset($path1['path'], $path2['path']); + if ($path1 != $path2) { + return FALSE; + } + unset($path1, $path2); + + $connection = $this->stream_open($path_from, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + $path_to = parse_url($path_to, PHP_URL_PATH); + + // "It is an error if there already exists a file with the name specified by newpath." + // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 + if (!$this->sftp->rename($this->path, $path_to)) { + if ($this->sftp->stat($path_to)) { + $del = $this->sftp->delete($path_to, true); + $rename = $this->sftp->rename($this->path, $path_to); + + $this->stream_close(); + return $del && $rename; + } + } + + $this->stream_close(); + return TRUE; + } + + /** + * Attempts to remove the directory named by the path + * + * Removes a directory + * + * NOTE: rmdir() does not have a $recursive parameter as mkdir() does ( http://www.php.net/manual/en/streamwrapper.rmdir.php ) + * + * @param String $path + * @param Integer $options + * @return bool + * @access public + */ + function rmdir($path, $options) + { + $connection = $this->stream_open($path, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + $rmdir = $this->sftp->rmdir($this->path); + + $this->stream_close(); + + return $rmdir; + } + + /** + * This method is called in response to stream_select() + * + * Retrieves the underlaying resource + * + * @param Integer $cast_as + * @return resource + * @access public + */ + function stream_cast($cast_as) + { + return $this->sftp->fsock; + } + + /** + * This method is called in response to fclose() + * + * Closes SFTP connection + * + * @return void + * @access public + */ + function stream_close() + { + // We do not really close connections because + // connections are assigned to a class static variable, so the Net_SFTP object will persist + // even after the stream object has been destroyed. But even without that, it's probably + // unnecessary as it'd be garbage collected out anyway. + // http://www.frostjedi.com/phpbb3/viewtopic.php?f=46&t=167493&sid=3161a478bd0bb359f6cefc956d6ac488&start=15#p391181 + + //$this->sftp->disconnect(); + + $this->position = 0; + } + + /** + * This method is called in response to feof() + * + * Tests for end-of-file on a file pointer + * + * @return bool + * @access public + */ + function stream_eof() + { + $filesize = $this->sftp->size($this->path); + + if ($this->position >= $filesize) { + return TRUE; + } else { + return FALSE; + } + } + + /** + * This method is called in response to fflush() + * + * NOTE: Always returns true because Net_SFTP doesn't cache stuff before writing + * + * @return bool + * @access public + */ + function stream_flush() + { + return TRUE; + } + + /** + * Advisory file locking + * + * Not Implemented + * + * @param Integer $operation + * @return Boolean + * @access public + */ + function stream_lock($operation) + { + return FALSE; + } + + /** + * This method is called to set metadata on the stream. It is called when one of the following functions is called on a stream URL: + * - touch() + * - chmod() + * - chown() + * - chgrp() + * + * Changes stream options + * + * @param String $path + * @param Integer $option + * @param mixed $var + * @return bool + * @access public + */ + function stream_metadata($path, $option, $var) + { + $connection = $this->stream_open($path, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + switch ($option) { + case 1: // PHP_STREAM_META_TOUCH + $touch = $this->sftp->touch($this->path, $var[1], $var[0]); + + $this->stream_close(); + return $touch; + + case 2: // PHP_STREAM_META_OWNER_NAME + $this->stream_close(); + return FALSE; + + case 3: // PHP_STREAM_META_OWNER + $chown = $this->sftp->chown($this->path, $var); + + $this->stream_close(); + return $chown; + + case 4: // PHP_STREAM_META_GROUP_NAME + $this->stream_close(); + return FALSE; + + case 5: // PHP_STREAM_META_GROUP + $chgrp = $this->sftp->chgrp($this->path, $var); + + $this->stream_close(); + return $chgrp; + + case 6: // PHP_STREAM_META_ACCESS + $chmod = $this->sftp->chmod($var, $this->path); + + $this->stream_close(); + return $chmod; + + default: + $this->stream_close(); + return FALSE; + } + } + + /** + * This method is called immediately after the wrapper is initialized + * + * Connects to an SFTP server + * + * NOTE: This method is not get called by default for the following functions: + * dir_opendir(), mkdir(), rename(), rmdir(), stream_metadata(), unlink() and url_stat() + * So I implemented a call to stream_open() at the beginning of the functions and stream_close() at the end + * + * The wrapper will also reuse open connections + * + * @param String $path + * @param String $mode + * @param Integer $options + * @param String &$opened_path + * @return bool + * @access public + */ + function stream_open($path, $mode, $options, &$opened_path) + { + $url = parse_url($path); + + $host = $url["host"]; + $port = $url["port"]; + $user = $url["user"]; + $pass = $url["pass"]; + + $this->path = $url["path"]; + + $connection_uuid = md5( $host.$port.$user ); // Generate a unique ID for the current connection + + if ( isset(self::$instances[$connection_uuid]) ) + { + // Get previously established connection + $this->sftp = self::$instances[$connection_uuid]; + } + else + { + //$context = stream_context_get_options($this->context); + + if (!isset($user) || !isset($pass)) { + return FALSE; + } + + // Connection + $sftp = new Net_SFTP($host, isset($port) ? $port : 22); + if (!$sftp->login($user, $pass)) { + return FALSE; + } + + // Store connection instance + self::$instances[$connection_uuid] = $sftp; + + // Get current connection + $this->sftp = $sftp; + } + + $filesize = $this->sftp->size($this->path); + + if (isset($mode)) { + $this->mode = preg_replace('#[bt]$#', '', $mode); + } + else { + $this->mode = 'r'; + } + + switch ($this->mode[0]) { + case 'r': + $this->position = 0; + break; + case 'w': + $this->position = 0; + if ($filesize === FALSE) { + $this->sftp->touch( $this->path ); + } + else { + $this->sftp->truncate( $this->path, 0 ); + } + break; + case 'a': + if ($filesize === FALSE) { + $this->position = 0; + $this->sftp->touch( $this->path ); + } + else { + $this->position = $filesize; + } + break; + case 'c': + $this->position = 0; + if ($filesize === FALSE) { + $this->sftp->touch( $this->path ); + } + break; + + default: + return FALSE; + } + + if ($options == STREAM_USE_PATH) { + $opened_path = $this->sftp->pwd(); + } + + return TRUE; + } + + /** + * This method is called in response to fread() and fgets() + * + * Reads from stream + * + * @param Integer $count + * @return mixed + * @access public + */ + function stream_read($count) + { + switch ($this->mode) { + case 'w': + case 'a': + case 'x': + case 'x+': + case 'c': + return FALSE; + } + + $chunk = $this->sftp->get( $this->path, FALSE, $this->position, $count ); + + $this->position += strlen($chunk); + + return $chunk; + } + + /** + * This method is called in response to fseek() + * + * Seeks to specific location in a stream + * + * @param Integer $offset + * @param Integer $whence = SEEK_SET + * @return bool + * @access public + */ + function stream_seek($offset, $whence) + { + $filesize = $this->sftp->size($this->path); + + switch ($whence) { + case SEEK_SET: if ($offset >= $filesize || $offset < 0) { return FALSE; } break; - case SEEK_CUR: - $offset += $this->position; - break; - - case SEEK_END: - $offset += $filesize; - break; - - default: - return FALSE; - } - - $this->position = $offset; - return TRUE; - } - - /** - * This method is called to set options on the stream - * - * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush() isn't. - * The other two aren't supported because of limitations in Net_SFTP. - * - * @param Integer $option - * @param Integer $arg1 - * @param Integer $arg2 - * @return Boolean - * @access public - */ - public function stream_set_option($option, $arg1, $arg2) - { - return FALSE; - } - - /** - * This method is called in response to fstat() - * - * Retrieves information about a file resource - * - * @return mixed - * @access public - */ - public function stream_stat() - { - $stat = $this->sftp->stat($this->path); - - if ( !empty($stat) ) { - // mode fix - $stat['mode'] = $stat['permissions']; - unset($stat['permissions']); - - return $stat; - } else { - return FALSE; - } - } - - /** - * This method is called in response to fseek() to determine the current position - * - * Retrieves the current position of a stream - * - * @return Integer - * @access public - */ - public function stream_tell() - { - return $this->position; - } - - /** - * Will respond to truncation, e.g., through ftruncate() - * - * Truncates a stream - * - * NOTE: - * If $new_size is larger than the file then the file is extended with null bytes. - * If $new_size is smaller than the file then the file is truncated to that size. - * - * ( http://www.php.net/manual/en/function.ftruncate.php ) - * - * @param Integer $new_size - * @return bool - * @access public - */ - public function stream_truncate($new_size) - { - return $this->sftp->truncate( $this->path, $new_size ); - } - - /** - * This method is called in response to fwrite() - * - * Writes to stream - * - * @param String $data - * @return mixed - * @access public - */ - public function stream_write($data) - { - switch ($this->mode) { - case 'r': - case 'x': - case 'x+': - return FALSE; - } - - $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->position); - - $this->position += strlen($data); - - return strlen($data); - } - - /** - * Deletes filename specified by the path - * - * Deletes a file - * - * @param String $path - * @return bool - * @access public - */ - public function unlink($path) - { - $connection = $this->stream_open($path, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - $del = $this->sftp->delete($this->path); - - $this->stream_close(); - - return $del; - } - - /** - * This method is called in response to all stat() related functions - * - * Retrieves information about a file - * - * @see SFTP_StreamWrapper::stream_stat() - * @param String $path - * @param Integer $flags - * @return mixed - * @access public - */ - public function url_stat($path, $flags) - { - $connection = $this->stream_open($path, NULL, NULL, $opened_path); - if ($connection === false) { - return FALSE; - } - - if ($flags === STREAM_URL_STAT_LINK) { - $stat = $this->sftp->lstat($this->path); - } else { - $stat = $this->sftp->stat($this->path); - } - - $this->stream_close(); - - if ( !empty($stat) ) { - // mode fix - $stat['mode'] = $stat['permissions']; - unset($stat['permissions']); - - return $stat; - } else { - return FALSE; - } - } + case SEEK_CUR: + $offset += $this->position; + break; + + case SEEK_END: + $offset += $filesize; + break; + + default: + return FALSE; + } + + $this->position = $offset; + return TRUE; + } + + /** + * This method is called to set options on the stream + * + * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush() isn't. + * The other two aren't supported because of limitations in Net_SFTP. + * + * @param Integer $option + * @param Integer $arg1 + * @param Integer $arg2 + * @return Boolean + * @access public + */ + function stream_set_option($option, $arg1, $arg2) + { + return FALSE; + } + + /** + * This method is called in response to fstat() + * + * Retrieves information about a file resource + * + * @return mixed + * @access public + */ + function stream_stat() + { + $stat = $this->sftp->stat($this->path); + + if( !empty($stat) ) { + // mode fix + $stat['mode'] = $stat['permissions']; + unset($stat['permissions']); + + return $stat; + } else { + return FALSE; + } + } + + /** + * This method is called in response to fseek() to determine the current position + * + * Retrieves the current position of a stream + * + * @return Integer + * @access public + */ + function stream_tell() + { + return $this->position; + } + + /** + * Will respond to truncation, e.g., through ftruncate() + * + * Truncates a stream + * + * NOTE: + * If $new_size is larger than the file then the file is extended with null bytes. + * If $new_size is smaller than the file then the file is truncated to that size. + * + * ( http://www.php.net/manual/en/function.ftruncate.php ) + * + * @param Integer $new_size + * @return bool + * @access public + */ + function stream_truncate($new_size) + { + return $this->sftp->truncate( $this->path, $new_size ); + } + + /** + * This method is called in response to fwrite() + * + * Writes to stream + * + * @param String $data + * @return mixed + * @access public + */ + function stream_write($data) + { + switch ($this->mode) { + case 'r': + case 'x': + case 'x+': + return FALSE; + } + + $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->position); + + $this->position += strlen($data); + + return strlen($data); + } + + /** + * Deletes filename specified by the path + * + * Deletes a file + * + * @param String $path + * @return bool + * @access public + */ + function unlink($path) + { + $connection = $this->stream_open($path, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + $del = $this->sftp->delete($this->path); + + $this->stream_close(); + + return $del; + } + + /** + * This method is called in response to all stat() related functions + * + * Retrieves information about a file + * + * @see SFTP_StreamWrapper::stream_stat() + * @param String $path + * @param Integer $flags + * @return mixed + * @access public + */ + function url_stat($path, $flags) + { + $connection = $this->stream_open($path, NULL, NULL, $opened_path); + if ($connection === false) { + return FALSE; + } + + if ( $flags === STREAM_URL_STAT_LINK ) { + $stat = $this->sftp->lstat($this->path); + } + else { + $stat = $this->sftp->stat($this->path); + } + + $this->stream_close(); + + if( !empty($stat) ) { + // mode fix + $stat['mode'] = $stat['permissions']; + unset($stat['permissions']); + + return $stat; + } else { + return FALSE; + } + } } @@ -832,4 +842,6 @@ public function url_stat($path, $flags) * Register "sftp://" protocol */ stream_wrapper_register('sftp', 'SFTPPSL_StreamWrapper') - or die ('Failed to register protocol'); + or die ('Failed to register protocol'); + +?> \ No newline at end of file diff --git a/core/src/plugins/access.sftp_psl/class.sftpPSLAccessDriver.php b/core/src/plugins/access.sftp_psl/class.sftpPSLAccessDriver.php index 76e0a20555..f5133ea383 100644 --- a/core/src/plugins/access.sftp_psl/class.sftpPSLAccessDriver.php +++ b/core/src/plugins/access.sftp_psl/class.sftpPSLAccessDriver.php @@ -1,22 +1,22 @@ - * This file is part of Pydio. + * This file is part of AjaXplorer. * - * Pydio is free software: you can redistribute it and/or modify + * AjaXplorer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * Pydio is distributed in the hope that it will be useful, + * AjaXplorer 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Pydio. If not, see . + * along with AjaXplorer. If not, see . * - * The latest code can be found at . + * The latest code can be found at . * */ defined('AJXP_EXEC') or die( 'Access not allowed' ); @@ -34,143 +34,143 @@ class sftpPSLAccessDriver extends fsAccessDriver { - /** - * @var Repository - */ - public $repository; - public $driverConf; - protected $wrapperClassName; - protected $urlBase; - - /** - * initRepository - */ - public function initRepository() - { - if (is_array($this->pluginConf)) { - $this->driverConf = $this->pluginConf; - } else { - $this->driverConf = array(); - } - - ConfService::setConf("PROBE_REAL_SIZE", false); - - require_once($this->getBaseDir()."/SFTPPSL_StreamWrapper.php"); - - $create = $this->repository->getOption("CREATE"); - $path = $this->repository->getOption("PATH"); - - $wrapperData = $this->detectStreamWrapper(true); - $this->wrapperClassName = $wrapperData["classname"]; - $this->urlBase = $wrapperData["protocol"]."://".$this->repository->getId(); + /** + * @var Repository + */ + public $repository; + public $driverConf; + protected $wrapperClassName; + protected $urlBase; + + /** + * initRepository + */ + function initRepository() { + if(is_array($this->pluginConf)){ + $this->driverConf = $this->pluginConf; + }else{ + $this->driverConf = array(); + } + + ConfService::setConf("PROBE_REAL_SIZE", false); + + require_once($this->getBaseDir()."/SFTPPSL_StreamWrapper.php"); + + $create = $this->repository->getOption("CREATE"); + $path = $this->repository->getOption("PATH"); + + $wrapperData = $this->detectStreamWrapper(true); + $this->wrapperClassName = $wrapperData["classname"]; + $this->urlBase = $wrapperData["protocol"]."://".$this->repository->getId(); // print "lol"; - } - - public function detectStreamWrapper($register = false) - { - if ($register) { - require_once($this->getBaseDir()."/SFTPPSL_StreamWrapper.php"); - } - return parent::detectStreamWrapper($register); - } - - /** - * Parse - * @param DOMNode $contribNode - */ - protected function parseSpecificContributions(&$contribNode) - { - parent::parseSpecificContributions($contribNode); - if($contribNode->nodeName != "actions") return ; - $this->disableArchiveBrowsingContributions($contribNode); - } - - public function filesystemFileSize($filePath) - { - $bytesize = filesize($filePath); - if ($bytesize < 0) { - $bytesize = sprintf("%u", $bytesize); - } - return $bytesize; - } - - /** - * @param $src - * @param $dest - * @param $basedir - * @return zipfile - */ - public function makeZip ($src, $dest, $basedir) - { - @set_time_limit(60); - require_once(AJXP_BIN_FOLDER."/pclzip.lib.php"); - $filePaths = array(); - - $uniqid = uniqid(); - $uniqfolder = '/tmp/ajaxplorer-zip-'.$uniqid; - mkdir($uniqfolder); - - foreach ($src as $item) { - $basedir = trim(dirname($item)); - $basename = basename($item); - $uniqpath = $uniqfolder.'/'.$basename; - $this->full_copy($this->urlBase.$item, $uniqpath); - $filePaths[] = array(PCLZIP_ATT_FILE_NAME => $uniqpath, - PCLZIP_ATT_FILE_NEW_SHORT_NAME => $basename); - } - $this->logDebug("Pathes", $filePaths); - $this->logDebug("Basedir", array($basedir)); - $archive = new PclZip($dest); - $vList = $archive->create($filePaths, PCLZIP_OPT_REMOVE_PATH, $uniqfolder, PCLZIP_OPT_NO_COMPRESSION); - $this->recursiveRmdir($uniqfolder); - if (!$vList) { - throw new Exception("Zip creation error : ($dest) ".$archive->errorInfo(true)); - } - return $vList; - } - - public function full_copy( $source, $destination ) - { - if ( is_dir( $source ) ) { - @mkdir( $destination ); - $directory = dir( $source ); - while ( FALSE !== ( $readdirectory = $directory->read() ) ) { - if ($readdirectory == '.' || $readdirectory == '..') { - continue; - } - $PathDir = $source . '/' . $readdirectory; - if ( is_dir( $PathDir ) ) { - $this->full_copy( $PathDir, $destination . '/' . $readdirectory ); - continue; - } - copy( $PathDir, $destination . '/' . $readdirectory ); - } - - $directory->close(); - } else { - copy( $source, $destination ); - } - } - - public function recursiveRmdir($path) - { - if (is_dir($path)) { - $path = rtrim($path, '/'); - $subdir = dir($path); - while (($file = $subdir->read()) !== false) { - if ($file != '.' && $file != '..') { - (!is_link("$path/$file") && is_dir("$path/$file")) ? $this->recursiveRmdir("$path/$file") : unlink("$path/$file"); - } - } - $subdir->close(); - rmdir($path); - return true; - } - return false; - } - - public function isWriteable($dir, $type="dir") - { - return is_writable($dir); - } + } + + function detectStreamWrapper($register = false) { + if($register){ + require_once($this->getBaseDir()."/SFTPPSL_StreamWrapper.php"); + } + return parent::detectStreamWrapper($register); + } + + /** + * Parse + * @param DOMNode $contribNode + */ + protected function parseSpecificContributions(&$contribNode){ + parent::parseSpecificContributions($contribNode); + if($contribNode->nodeName != "actions") return ; + $this->disableArchiveBrowsingContributions($contribNode); + } + + function filesystemFileSize($filePath){ + $bytesize = filesize($filePath); + if($bytesize < 0){ + $bytesize = sprintf("%u", $bytesize); + } + return $bytesize; + } + + /** + * @param $src + * @param $dest + * @param $basedir + * @return zipfile + */ + function makeZip ($src, $dest, $basedir) + { + @set_time_limit(60); + require_once(AJXP_BIN_FOLDER."/pclzip.lib.php"); + $filePaths = array(); + + $uniqid = uniqid(); + $uniqfolder = '/tmp/ajaxplorer-zip-'.$uniqid; + mkdir($uniqfolder); + + foreach ($src as $item){ + $basedir = trim(dirname($item)); + $basename = basename($item); + $uniqpath = $uniqfolder.'/'.$basename; + $this->full_copy($this->urlBase.$item, $uniqpath); + $filePaths[] = array(PCLZIP_ATT_FILE_NAME => $uniqpath, + PCLZIP_ATT_FILE_NEW_SHORT_NAME => $basename); + } + AJXP_Logger::debug("Pathes", $filePaths); + AJXP_Logger::debug("Basedir", array($basedir)); + $archive = new PclZip($dest); + $vList = $archive->create($filePaths, PCLZIP_OPT_REMOVE_PATH, $uniqfolder, PCLZIP_OPT_NO_COMPRESSION); + $this->recursiveRmdir($uniqfolder); + if(!$vList){ + throw new Exception("Zip creation error : ($dest) ".$archive->errorInfo(true)); + } + return $vList; + } + + function full_copy( $source, $destination ) { + if ( is_dir( $source ) ) { + @mkdir( $destination ); + $directory = dir( $source ); + while ( FALSE !== ( $readdirectory = $directory->read() ) ) { + if ( $readdirectory == '.' || $readdirectory == '..' ) { + continue; + } + $PathDir = $source . '/' . $readdirectory; + if ( is_dir( $PathDir ) ) { + $this->full_copy( $PathDir, $destination . '/' . $readdirectory ); + continue; + } + copy( $PathDir, $destination . '/' . $readdirectory ); + } + + $directory->close(); + }else { + copy( $source, $destination ); + } + } + + function recursiveRmdir($path) + { + if (is_dir($path)) + { + $path = rtrim($path, '/'); + $subdir = dir($path); + while (($file = $subdir->read()) !== false) + { + if ($file != '.' && $file != '..') + { + (!is_link("$path/$file") && is_dir("$path/$file")) ? $this->recursiveRmdir("$path/$file") : unlink("$path/$file"); + } + } + $subdir->close(); + rmdir($path); + return true; + } + return false; + } + + function isWriteable($dir, $type="dir") + { + return is_writable($dir); + } } + +?> \ No newline at end of file diff --git a/core/src/plugins/access.sftp_psl/class.sftpPSLAccessWrapper.php b/core/src/plugins/access.sftp_psl/class.sftpPSLAccessWrapper.php index a255f3cfc7..afdf9fc0bd 100644 --- a/core/src/plugins/access.sftp_psl/class.sftpPSLAccessWrapper.php +++ b/core/src/plugins/access.sftp_psl/class.sftpPSLAccessWrapper.php @@ -1,22 +1,22 @@ - * This file is part of Pydio. + * This file is part of AjaXplorer. * - * Pydio is free software: you can redistribute it and/or modify + * AjaXplorer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * Pydio is distributed in the hope that it will be useful, + * AjaXplorer 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Pydio. If not, see . + * along with AjaXplorer. If not, see . * - * The latest code can be found at . + * The latest code can be found at . * */ defined('AJXP_EXEC') or die( 'Access not allowed' ); @@ -34,204 +34,196 @@ class sftpPSLAccessWrapper extends fsAccessWrapper { - public static function isRemote() - { - return true; - } - - /** - * Initialize the stream from the given path. - */ - protected static function initPath($path, $streamType = '', $storeOpenContext = false, $skipZip = true) - { - $url = parse_url($path); - $repoId = $url["host"]; - $path = $url["path"]; - - $repoObject = ConfService::getRepositoryById($repoId); - - if(!isSet($repoObject)) throw new Exception("Cannot find repository with id ".$repoId); - - $basePath = $repoObject->getOption("PATH"); - $host = $repoObject->getOption("SFTP_HOST"); - $port = $repoObject->getOption("SFTP_PORT"); - - $credentials = AJXP_Safe::tryLoadingCredentialsFromSources($url, $repoObject); - $user = $credentials["user"]; - $pass = $credentials["password"]; - - if ($basePath[strlen($basePath)-1] == "/") { - $basePath = substr($basePath, 0, -1); - } - - if ($basePath[0] != "/") { - $basePath = "/$basePath"; - } - - $path = AJXP_Utils::securePath($path); - - if ($path[0] == "/") { - $path = substr($path, 1); - } - - return "sftp://".$user.':'.$pass.'@'.$host.':'.$port.$basePath."/".$path; // http://username:password@hostname:port/path/file.ext - } - - /** - * Implementation of AjxpStream - * - * @param String $path - * @return string - */ - public static function getRealFSReference($path, $persistent = false) - { - if ($persistent) { - $tmpFile = AJXP_Utils::getAjxpTmpDir()."/".md5(time()); - $tmpHandle = fopen($tmpFile, "wb"); - self::copyFileInStream($path, $tmpHandle); - fclose($tmpHandle); - return $tmpFile; - } else { - return self::initPath($path); - } - } - - /** - * Opens the stream - * Diff with parent class : do not "securePath", as it removes double slash - * - * @param String $path Maybe in the form "ajxp.fs://repositoryId/pathToFile" - * @param String $mode - * @param unknown_type $options - * @param unknown_type $opened_path - * @return unknown - */ - public function stream_open($path, $mode, $options, &$context) - { - try { - $this->realPath = $this->initPath($path); - } catch (Exception $e) { - AJXP_Logger::error(__CLASS__,"stream_open", "Error while opening stream $path"); - return false; - } - if ($this->realPath == -1) { - $this->fp = -1; - return true; - } else { - $this->fp = fopen($this->realPath, $mode, $options); - return ($this->fp !== false); - } - } - - /** - * Opens a handle to the dir - * Fix PEAR by being sure it ends up with "/", to avoid - * adding the current dir to the children list. - * - * @param unknown_type $path - * @param unknown_type $options - * @return unknown - */ - public function dir_opendir ($path , $options ) - { - $this->realPath = $this->initPath($path); - if ($this->realPath[strlen($this->realPath)-1] != "/") { - $this->realPath.="/"; - } - if (is_string($this->realPath)) { - $this->dH = opendir($this->realPath); - } else if ($this->realPath == -1) { - $this->dH = -1; - } - return $this->dH !== false; - } - - public function unlink($path) - { - $this->realPath = $this->initPath($path, "file", false, true); - @unlink($this->realPath); - if (is_file($this->realPath)) { - return false; - } else { - return true; - } - } - - /** - * Stats the given path. - * - * @param string $path - * @param mixed $flags - * @return array - */ - public function url_stat($path, $flags) - { - $realPath = self::initPath($path); - $stat = @stat($realPath); - $parts = parse_url($path); - $repoObject = ConfService::getRepositoryById($parts["host"]); - - AbstractAccessDriver::fixPermissions($stat, $repoObject, array($this, "detectRemoteUserId")); - - return $stat; - } - - public function detectRemoteUserId($repoObject) - { - $host = $repoObject->getOption("SFTP_HOST"); - $port = $repoObject->getOption("SFTP_PORT"); - - $credentials = AJXP_Safe::tryLoadingCredentialsFromSources(NULL, $repoObject); - $user = $credentials["user"]; - $pass = $credentials["password"]; - - $ssh2 = new Net_SSH2($host, $port); - if ($ssh2->login($user, $pass)) { - $output = $ssh2->exec( 'id' ); - - if (trim($output != "")) { - $res = sscanf($output, "uid=%i(%s) gid=%i(%s) groups=%i(%s)"); - preg_match_all("/(\w*)=(\w*)\((\w*)\)/", $output, $matches); - if (count($matches[0]) == 3) { - $uid = $matches[2][0]; - $gid = $matches[2][1]; - - return array($uid, $gid); - } - } - - $ssh2->disconnect(); - } - return array(null,null); - } - - /** - * Override parent function. - * We may have performance problems on big files here. - * - * @param String $path - * @param Stream $stream - */ - public static function copyFileInStream($path, $stream) - { - $src = fopen(self::initPath($path), "rb"); - while ($content = fread($src, 5120)) { - fputs($stream, $content, strlen($content)); - if(strlen($content) == 0) break; - } - fclose($src); - } - - /** - * Remove a temporary file - * - * @param String $tmpDir - * @param String $tmpFile - */ - public static function removeTmpFile($tmpDir, $tmpFile) - { - if(is_file($tmpFile)) unlink($tmpFile); - if(is_dir($tmpDir)) rmdir($tmpDir); - } + public static function isRemote(){ + return true; + } + + /** + * Initialize the stream from the given path. + */ + protected static function initPath($path, $streamType = '', $storeOpenContext = false, $skipZip = true){ + $url = parse_url($path); + $repoId = $url["host"]; + $path = $url["path"]; + + $repoObject = ConfService::getRepositoryById($repoId); + + if(!isSet($repoObject)) throw new Exception("Cannot find repository with id ".$repoId); + + $basePath = $repoObject->getOption("PATH"); + $host = $repoObject->getOption("SFTP_HOST"); + $port = $repoObject->getOption("SFTP_PORT"); + + $credentials = AJXP_Safe::tryLoadingCredentialsFromSources($url, $repoObject); + $user = $credentials["user"]; + $pass = $credentials["password"]; + + if($basePath[strlen($basePath)-1] == "/"){ + $basePath = substr($basePath, 0, -1); + } + + if($basePath[0] != "/"){ + $basePath = "/$basePath"; + } + + $path = AJXP_Utils::securePath($path); + + if($path[0] == "/"){ + $path = substr($path, 1); + } + + return "sftp://".$user.':'.$pass.'@'.$host.':'.$port.$basePath."/".$path; // http://username:password@hostname:port/path/file.ext + } + + /** + * Implementation of AjxpStream + * + * @param String $path + * @return string + */ + public static function getRealFSReference($path, $persistent = false){ + if($persistent){ + $tmpFile = AJXP_Utils::getAjxpTmpDir()."/".md5(time()); + $tmpHandle = fopen($tmpFile, "wb"); + self::copyFileInStream($path, $tmpHandle); + fclose($tmpHandle); + return $tmpFile; + }else{ + return self::initPath($path); + } + } + + /** + * Opens the stream + * Diff with parent class : do not "securePath", as it removes double slash + * + * @param String $path Maybe in the form "ajxp.fs://repositoryId/pathToFile" + * @param String $mode + * @param unknown_type $options + * @param unknown_type $opened_path + * @return unknown + */ + public function stream_open($path, $mode, $options, &$context) + { + try{ + $this->realPath = $this->initPath($path); + }catch (Exception $e){ + AJXP_Logger::logAction("error", array("message" => "Error while opening stream $path")); + return false; + } + if($this->realPath == -1){ + $this->fp = -1; + return true; + }else{ + $this->fp = fopen($this->realPath, $mode, $options); + return ($this->fp !== false); + } + } + + /** + * Opens a handle to the dir + * Fix PEAR by being sure it ends up with "/", to avoid + * adding the current dir to the children list. + * + * @param unknown_type $path + * @param unknown_type $options + * @return unknown + */ + public function dir_opendir ($path , $options ){ + $this->realPath = $this->initPath($path); + if($this->realPath[strlen($this->realPath)-1] != "/"){ + $this->realPath.="/"; + } + if(is_string($this->realPath)){ + $this->dH = opendir($this->realPath); + }else if($this->realPath == -1){ + $this->dH = -1; + } + return $this->dH !== false; + } + + public function unlink($path){ + $this->realPath = $this->initPath($path, "file", false, true); + @unlink($this->realPath); + if(is_file($this->realPath)){ + return false; + }else{ + return true; + } + } + + /** + * Stats the given path. + * + * @param string $path + * @param mixed $flags + * @return array + */ + public function url_stat($path, $flags){ + $realPath = self::initPath($path); + $stat = @stat($realPath); + $parts = parse_url($path); + $repoObject = ConfService::getRepositoryById($parts["host"]); + + AbstractAccessDriver::fixPermissions($stat, $repoObject, array($this, "detectRemoteUserId")); + + return $stat; + } + + public function detectRemoteUserId($repoObject){ + $host = $repoObject->getOption("SFTP_HOST"); + $port = $repoObject->getOption("SFTP_PORT"); + + $credentials = AJXP_Safe::tryLoadingCredentialsFromSources(NULL, $repoObject); + $user = $credentials["user"]; + $pass = $credentials["password"]; + + $ssh2 = new Net_SSH2($host, $port); + if ($ssh2->login($user, $pass)) { + $output = $ssh2->exec( 'id' ); + + if(trim($output != "")){ + $res = sscanf($output, "uid=%i(%s) gid=%i(%s) groups=%i(%s)"); + preg_match_all("/(\w*)=(\w*)\((\w*)\)/", $output, $matches); + if(count($matches[0]) == 3){ + $uid = $matches[2][0]; + $gid = $matches[2][1]; + + return array($uid, $gid); + } + } + + $ssh2->disconnect(); + } + return array(null,null); + } + + /** + * Override parent function. + * We may have performance problems on big files here. + * + * @param String $path + * @param Stream $stream + */ + public static function copyFileInStream($path, $stream){ + + $src = fopen(self::initPath($path), "rb"); + while ($content = fread($src, 5120)) { + fputs($stream, $content, strlen($content)); + if(strlen($content) == 0) break; + } + fclose($src); + } + + /** + * Remove a temporary file + * + * @param String $tmpDir + * @param String $tmpFile + */ + public static function removeTmpFile($tmpDir, $tmpFile){ + if(is_file($tmpFile)) unlink($tmpFile); + if(is_dir($tmpDir)) rmdir($tmpDir); + } } diff --git a/core/src/plugins/access.sftp_psl/i18n/conf/en.php b/core/src/plugins/access.sftp_psl/i18n/conf/en.php index 3ad2af7824..6d9776ad38 100644 --- a/core/src/plugins/access.sftp_psl/i18n/conf/en.php +++ b/core/src/plugins/access.sftp_psl/i18n/conf/en.php @@ -1,22 +1,22 @@ -* This file is part of Pydio. +* Copyright 2007-2011 Charles du Jeu +* This file is part of AjaXplorer. * -* Pydio is free software: you can redistribute it and/or modify +* AjaXplorer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * -* Pydio is distributed in the hope that it will be useful, +* AjaXplorer 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License -* along with Pydio. If not, see . +* along with AjaXplorer. If not, see . * -* The latest code can be found at . +* The latest code can be found at . */ $mess=array( "SSH File Transfer Protocol (SFTP)" => "SSH File Transfer Protocol (SFTP)", @@ -30,3 +30,4 @@ "Fix Permissions" => "Fix Permissions", "How to handle remote permissions to be used by PHP as local permissions. See manual." => "How to handle remote permissions to be used by PHP as local permissions. See manual." ); +?> \ No newline at end of file diff --git a/core/src/plugins/access.sftp_psl/i18n/conf/fr.php b/core/src/plugins/access.sftp_psl/i18n/conf/fr.php index 52c7460a85..df6f6dcb9c 100644 --- a/core/src/plugins/access.sftp_psl/i18n/conf/fr.php +++ b/core/src/plugins/access.sftp_psl/i18n/conf/fr.php @@ -1,22 +1,22 @@ -* This file is part of Pydio. +* Copyright 2007-2011 Charles du Jeu +* This file is part of AjaXplorer. * -* Pydio is free software: you can redistribute it and/or modify +* AjaXplorer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * -* Pydio is distributed in the hope that it will be useful, +* AjaXplorer 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License -* along with Pydio. If not, see . +* along with AjaXplorer. If not, see . * -* The latest code can be found at . +* The latest code can be found at . */ $mess=array( "SSH File Transfer Protocol (SFTP)" => "SSH File Transfer Protocol (SFTP)", @@ -30,3 +30,4 @@ "Fix Permissions" => "Correction des permissions", "How to handle remote permissions to be used by PHP as local permissions. See manual." => "Gestion des permissions entre le serveur local et le serveur distant." ); +?> \ No newline at end of file diff --git a/core/src/plugins/access.sftp_psl/manifest.xml b/core/src/plugins/access.sftp_psl/manifest.xml index 66a071d7f9..21a8e2bfc6 100644 --- a/core/src/plugins/access.sftp_psl/manifest.xml +++ b/core/src/plugins/access.sftp_psl/manifest.xml @@ -11,7 +11,7 @@ Rou Nik - http://pyd.io/plugins/access/sftp_psl + http://ajaxplorer.info/plugins/access/sftp_psl 0.8 diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/AES.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/AES.php index 81fa2feab6..4ebf07e545 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/AES.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/AES.php @@ -4,13 +4,13 @@ /** * Pure-PHP implementation of AES. * - * Uses mcrypt, if available/possible, and an internal implementation, otherwise. + * 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 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()} + * 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 @@ -42,10 +42,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -66,7 +66,7 @@ * Include Crypt_Rijndael */ if (!class_exists('Crypt_Rijndael')) { - require_once('Rijndael.php'); + require_once 'Rijndael.php'; } /**#@+ @@ -81,31 +81,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); +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', CRYPT_MODE_ECB); +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', CRYPT_MODE_CBC); +define('CRYPT_AES_MODE_CBC', 2); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); +define('CRYPT_AES_MODE_CFB', 3); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); +define('CRYPT_AES_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -115,11 +115,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_AES_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_AES_MODE_MCRYPT', 2); /**#@-*/ /** @@ -132,41 +132,114 @@ */ class Crypt_AES extends Crypt_Rijndael { /** - * The namespace used by the cipher for its constants. + * mcrypt resource for encryption * - * @see Crypt_Base::const_namespace + * 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 $const_namespace = 'AES'; + var $enmcrypt; /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_AES_MODE_ECB + * mcrypt resource for decryption * - * - CRYPT_AES_MODE_CBC + * 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. * - * - CRYPT_AES_MODE_CTR - * - * - CRYPT_AES_MODE_CFB + * @see Crypt_AES::decrypt() + * @var String + * @access private + */ + var $demcrypt; + + /** + * mcrypt resource for CFB mode * - * - CRYPT_AES_MODE_OFB + * @see Crypt_AES::encrypt() + * @see Crypt_AES::decrypt() + * @var String + * @access private + */ + var $ecb; + + /** + * Default Constructor. * - * If not explictly set, CRYPT_AES_MODE_CBC will be used. + * 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. * - * @see Crypt_Rijndael::Crypt_Rijndael() - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode + * @return Crypt_AES * @access public */ function Crypt_AES($mode = CRYPT_AES_MODE_CBC) { - parent::Crypt_Rijndael($mode); + if ( !defined('CRYPT_AES_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()): + 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->paddable = true; + $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_CFB: + $this->mode = 'ncfb'; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_AES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + + break; + default: + switch ($mode) { + case CRYPT_AES_MODE_ECB: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_ECB; + break; + case CRYPT_AES_MODE_CTR: + $this->mode = CRYPT_RIJNDAEL_MODE_CTR; + break; + case CRYPT_AES_MODE_CFB: + $this->mode = CRYPT_RIJNDAEL_MODE_CFB; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = CRYPT_RIJNDAEL_MODE_OFB; + break; + case CRYPT_AES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_CBC; + } + } + + if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { + parent::Crypt_Rijndael($this->mode); + } + } /** @@ -174,7 +247,6 @@ function Crypt_AES($mode = CRYPT_AES_MODE_CBC) * * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. * - * @see Crypt_Rijndael::setBlockLength() * @access public * @param Integer $length */ @@ -182,6 +254,286 @@ function setBlockLength($length) { return; } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_RIJNDAEL_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) + { + parent::setIV($iv); + if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $this->changed = true; + } + } + + /** + * 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(); + + // re: http://phpseclib.sourceforge.net/cfb-demo.phps + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == 'ncfb' && $this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 16 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= 16) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16)); + $iv = substr($ciphertext, -16); + $len%= 16; + } else { + while ($len >= 16) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16); + $ciphertext.= $iv; + $len-= 16; + $i+= 16; + } + } + } + + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + + return $ciphertext; + } + + if ($this->paddable) { + $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 == 'ncfb' && $this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 16 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= 16) { + $cb = substr($ciphertext, $i, $len - $len % 16); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -16); + $len%= 16; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + + return $plaintext; + } + + if ($this->paddable) { + // 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->paddable ? $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 = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); + $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, ''); + + if ($mode == 'ncfb') { + $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + } + + } // 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); + + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + + $this->changed = false; + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * The default behavior. + * + * @see Crypt_Rijndael::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + parent::enableContinuousBuffer(); + + if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { + $this->enbuffer['enmcrypt_init'] = true; + $this->debuffer['demcrypt_init'] = true; + } + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + parent::disableContinuousBuffer(); + + if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); + mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); + } + } } // vim: ts=4:sw=4:et: diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Blowfish.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Blowfish.php index 248a229c18..a7913cc82f 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Blowfish.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Blowfish.php @@ -10,7 +10,7 @@ * * Useful resources are as follows: * - * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish} + * - {@link http://en.wikipedia.org/wiki/Blowfish Wikipedia description of Blowfish} * * Here's a short example of how to use this library: * @@ -55,15 +55,6 @@ * @link http://phpseclib.sourceforge.net */ -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - require_once 'Base.php'; -} - /**#@+ * @access public * @see Crypt_Blowfish::encrypt() @@ -76,31 +67,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR); +define('CRYPT_BLOWFISH_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_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB); +define('CRYPT_BLOWFISH_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_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC); +define('CRYPT_BLOWFISH_MODE_CBC', 2); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB); +define('CRYPT_BLOWFISH_MODE_CFB', 3); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); +define('CRYPT_BLOWFISH_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -110,11 +101,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_BLOWFISH_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_BLOWFISH_MODE_MCRYPT', 2); /**#@-*/ /** @@ -126,52 +117,158 @@ * @access public * @package Crypt_Blowfish */ -class Crypt_Blowfish extends Crypt_Base { +class Crypt_Blowfish { /** - * Block Length of the cipher + * The Key as String * - * @see Crypt_Base::block_size - * @var Integer + * @see Crypt_Blowfish::setKey() + * @var Array * @access private */ - var $block_size = 8; + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /** - * The default password key_size used by setPassword() + * The Encryption Mode * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() + * @see Crypt_Blowfish::Crypt_Blowfish() * @var Integer * @access private */ - var $password_key_size = 56; + var $mode; + + /** + * Continuous Buffer status + * + * @see Crypt_Blowfish::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Padding status + * + * @see Crypt_Blowfish::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; /** - * The namespace used by the cipher for its constants. + * The Initialization Vector * - * @see Crypt_Base::const_namespace + * @see Crypt_Blowfish::setIV() * @var String * @access private */ - var $const_namespace = 'BLOWFISH'; + var $iv = "\0\0\0\0\0\0\0\0"; /** - * The mcrypt specific name of the cipher + * A "sliding" Initialization Vector * - * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_Blowfish::enableContinuousBuffer() * @var String * @access private */ - var $cipher_name_mcrypt = 'blowfish'; + var $encryptIV = "\0\0\0\0\0\0\0\0"; /** - * Optimizing value while CFB-encrypting + * A "sliding" Initialization Vector * - * @see Crypt_Base::cfb_init_len - * @var Integer + * @see Crypt_Blowfish::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_Blowfish::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_Blowfish::decrypt() + * @var String + * @access private + */ + var $demcrypt; + + /** + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_Blowfish::setKey() + * @see Crypt_Blowfish::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_Blowfish::setKey() + * @see Crypt_Blowfish::setIV() + * @var Boolean * @access private */ - var $cfb_init_len = 500; + var $dechanged = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Blowfish::Crypt_Blowfish() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Blowfish::encrypt() + * @var Array + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Blowfish::decrypt() + * @var Array + * @access private + */ + var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_Blowfish::encrypt() + * @see Crypt_Blowfish::decrypt() + * @var String + * @access private + */ + var $ecb; + + /** + * Performance-optimized callback function for en/decrypt() + * + * @var Callback + * @access private + */ + var $inline_crypt; /** * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each @@ -359,42 +456,73 @@ class Crypt_Blowfish extends Crypt_Base { * @var array $bctx * @access private */ - var $bctx; - - /** - * Holds the last used key - * - * @var Array - * @access private - */ - var $kl; + var $bctx = array(); /** * Default Constructor. * * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_BLOWFISH_MODE_ECB - * - * - CRYPT_BLOWFISH_MODE_CBC - * - * - CRYPT_BLOWFISH_MODE_CTR - * - * - CRYPT_BLOWFISH_MODE_CFB - * - * - CRYPT_BLOWFISH_MODE_OFB - * * If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used. * - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode * @access public */ function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC) { - parent::Crypt_Base($mode); + if ( !defined('CRYPT_BLOWFISH_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('blowfish', mcrypt_list_algorithms()): + define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_MCRYPT); + break; + default: + define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_INTERNAL); + } + } + + switch ( CRYPT_BLOWFISH_MODE ) { + case CRYPT_BLOWFISH_MODE_MCRYPT: + switch ($mode) { + case CRYPT_BLOWFISH_MODE_ECB: + $this->paddable = true; + $this->mode = MCRYPT_MODE_ECB; + break; + case CRYPT_BLOWFISH_MODE_CTR: + $this->mode = 'ctr'; + break; + case CRYPT_BLOWFISH_MODE_CFB: + $this->mode = 'ncfb'; + $this->ecb = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, ''); + break; + case CRYPT_BLOWFISH_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_BLOWFISH_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + $this->enmcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, ''); + $this->demcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, ''); + + break; + default: + switch ($mode) { + case CRYPT_BLOWFISH_MODE_ECB: + case CRYPT_BLOWFISH_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_BLOWFISH_MODE_CTR: + case CRYPT_BLOWFISH_MODE_CFB: + case CRYPT_BLOWFISH_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_BLOWFISH_MODE_CBC; + } + $this->inline_crypt_setup(); + } } /** @@ -409,7 +537,6 @@ function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC) * If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes. * * @access public - * @see Crypt_Base::setKey() * @param String $key */ function setKey($key) @@ -423,22 +550,14 @@ function setKey($key) $key = substr($key, 0, 56); } - parent::setKey($key); - } + $this->key = $key; - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - if (isset($this->kl['key']) && $this->key === $this->kl['key']) { - // already expanded + $this->enchanged = true; + $this->dechanged = true; + + if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) { return; } - $this->kl = array('key' => $this->key); /* key-expanding p[] and S-Box building sb[] */ $this->bctx = array( @@ -452,7 +571,7 @@ function _setupKey() ); // unpack binary string in unsigned chars - $key = array_values(unpack('C*', $this->key)); + $key = array_values(unpack('C*', $key)); $keyl = count($key); for ($j = 0, $i = 0; $i < 18; ++$i) { // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ... @@ -467,185 +586,530 @@ function _setupKey() // encrypt the zero-string, replace P1 and P2 with the encrypted data, // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys - $data = "\0\0\0\0\0\0\0\0"; + $datal = 0; + $datar = 0; for ($i = 0; $i < 18; $i += 2) { - list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); - $this->bctx['p'][$i ] = $l; - $this->bctx['p'][$i + 1] = $r; + $this->_encryptBlock($datal, $datar); + $this->bctx['p'][$i ] = $datal; + $this->bctx['p'][$i + 1] = $datar; } for ($i = 0; $i < 4; ++$i) { for ($j = 0; $j < 256; $j += 2) { - list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); - $this->bctx['sb'][$i][$j ] = $l; - $this->bctx['sb'][$i][$j + 1] = $r; + $this->_encryptBlock($datal, $datar); + $this->bctx['sb'][$i][$j ] = $datal; + $this->bctx['sb'][$i][$j + 1] = $datar; } } } /** - * Encrypts a block + * Encrypt the block. * * @access private - * @param String $in - * @return String + * @param int $Xl left uInt32 part of the block + * @param int $Xr right uInt32 part of the block + * @return void */ - function _encryptBlock($in) + function _encryptBlock(&$Xl, &$Xr) { - $p = $this->bctx["p"]; - // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower - $sb_0 = $this->bctx["sb"][0]; - $sb_1 = $this->bctx["sb"][1]; - $sb_2 = $this->bctx["sb"][2]; - $sb_3 = $this->bctx["sb"][3]; - - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - - for ($i = 0; $i < 16; $i+= 2) { - $l^= $p[$i]; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; - - $r^= $p[$i + 1]; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; - } - return pack("N*", $r ^ $p[17], $l ^ $p[16]); - } + $p = $this->bctx['p']; + $sb_0 = $this->bctx['sb'][0]; + $sb_1 = $this->bctx['sb'][1]; + $sb_2 = $this->bctx['sb'][2]; + $sb_3 = $this->bctx['sb'][3]; + $l = $Xl; + $r = $Xr; - /** - * Decrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $p = $this->bctx["p"]; - $sb_0 = $this->bctx["sb"][0]; - $sb_1 = $this->bctx["sb"][1]; - $sb_2 = $this->bctx["sb"][2]; - $sb_3 = $this->bctx["sb"][3]; - - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - - for ($i = 17; $i > 2; $i-= 2) { - $l^= $p[$i]; + $i = -1; + while ($i < 15) { + $l^= $p[++$i]; $r^= ($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff] ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]; - $r^= $p[$i - 1]; + $r^= $p[++$i]; $l^= ($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff] ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]; + + } + $Xr = $l ^ $p[16]; + $Xl = $r ^ $p[17]; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib/salt'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < 56) { + //$dk.= $this->_pbkdf($password, $salt, $count, $i++); + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey($key); + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_BLOWFISH_MODE_ECB is being used. If not explictly set, it'll be assumed + * to be all null bytes. + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); + $this->enchanged = true; + $this->dechanged = true; + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with up to 8 additional bytes. Other Blowfish 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_Blowfish::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) { + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + } + $this->enchanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= 8) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); + $iv = substr($ciphertext, -8); + $len%= 8; + } else { + while ($len >= 8) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); + $ciphertext.= $iv; + $len-= 8; + $i+= 8; + } + } + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if (empty($this->bctx)) { + $this->setKey($this->key); + } + + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + + /** + * 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_Blowfish::encrypt() + * @access public + * @param String $ciphertext + */ + function decrypt($ciphertext) + { + if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) { + if ($this->paddable) { + // 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) + (8 - strlen($ciphertext) % 8) % 8, chr(0)); + } + + if ($this->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + } + $this->dechanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= 8) { + $cb = substr($ciphertext, $i, $len - $len % 8); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -8); + $len%= 8; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + return $plaintext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if (empty($this->bctx)) { + $this->setKey($this->key); + } + + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * @see Crypt_Blowfish::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_Blowfish::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + $this->continuousBuffer = false; + $this->encryptIV = $this->iv; + $this->decryptIV = $this->iv; + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); + mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); + } + } + + /** + * Pad "packets". + * + * Blowfish works by encrypting 8 bytes at a time. If you ever need to encrypt or decrypt something that's not + * a multiple of 8, 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_Blowfish::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Blowfish::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). + * + * 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_Blowfish::_unpad() + * @access private + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % 8 == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size (8)"); + $this->padding = true; + } } - return pack("N*", $r ^ $p[0], $l ^ $p[1]); + $pad = 8 - ($length % 8); + + return str_pad($text, $length + $pad, chr($pad)); } /** - * Setup the performance-optimized function for de/encrypt() + * Unpads a string + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. * - * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Blowfish::_pad() * @access private */ - function _setupInlineCrypt() + function _unpad($text) { - $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions(); + if (!$this->padding) { + return $text; + } - // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. - // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10); + $length = ord($text[strlen($text) - 1]); - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Blowfish, {$this->mode}"; + if (!$length || $length > 8) { + return false; } - if (!isset($lambda_functions[$code_hash])) { - switch (true) { - case $gen_hi_opt_code: - $p = $this->bctx['p']; - $init_crypt = ' - static $sb_0, $sb_1, $sb_2, $sb_3; - if (!$sb_0) { - $sb_0 = $self->bctx["sb"][0]; - $sb_1 = $self->bctx["sb"][1]; - $sb_2 = $self->bctx["sb"][2]; - $sb_3 = $self->bctx["sb"][3]; - } - '; + return substr($text, 0, -$length); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @return String + * @access private + */ + function _string_shift(&$string) + { + $substr = substr($string, 0, 8); + $string = substr($string, 8); + return $substr; + } + + /** + * 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_Blowfish::decrypt() + * @see Crypt_Blowfish::encrypt() + * @access public + * @param String $iv + */ + function _generate_xor(&$iv) + { + $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: - $p = array(); - for ($i = 0; $i < 18; ++$i) { - $p[] = '$p_' . $i; - } - $init_crypt = ' - list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"]; - list(' . implode(',', $p) . ') = $self->bctx["p"]; - - '; + extract(unpack('Ncount', $temp)); + $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); + break 2; } + } + + return $xor; + } + + /** + * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt + * + * @access private + */ + function inline_crypt_setup() + {/*{{{*/ + $lambda_functions =& Crypt_Blowfish::get_lambda_functions(); + $block_size = 8; + $mode = $this->mode; + $code_hash = "$mode"; + + if (!isset($lambda_functions[$code_hash])) { + $init_cryptBlock = ' + extract($self->bctx["p"], EXTR_PREFIX_ALL, "p"); + extract($self->bctx["sb"], EXTR_PREFIX_ALL, "sb"); + '; // Generating encrypt code: - $encrypt_block = ' + $_encryptBlock = ' $in = unpack("N*", $in); $l = $in[1]; $r = $in[2]; '; for ($i = 0; $i < 16; $i+= 2) { - $encrypt_block.= ' - $l^= ' . $p[$i] . '; + $_encryptBlock.= ' + $l^= $p_'.($i).'; $r^= ($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff] ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]; - $r^= ' . $p[$i + 1] . '; + $r^= $p_'.($i + 1).'; $l^= ($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff] ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]; '; } - $encrypt_block.= ' - $in = pack("N*", - $r ^ ' . $p[17] . ', - $l ^ ' . $p[16] . ' - ); + $_encryptBlock.= ' + $in = pack("N*", $r ^ $p_17, $l ^ $p_16); '; // Generating decrypt code: - $decrypt_block = ' + $_decryptBlock = ' $in = unpack("N*", $in); $l = $in[1]; $r = $in[2]; '; for ($i = 17; $i > 2; $i-= 2) { - $decrypt_block.= ' - $l^= ' . $p[$i] . '; + $_decryptBlock.= ' + $l^= $p_'.($i).'; $r^= ($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff] ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]; - $r^= ' . $p[$i - 1] . '; + $r^= $p_'.($i - 1).'; $l^= ($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff] ^ $sb_2[$r >> 8 & 0xff]) + @@ -653,24 +1117,350 @@ function _setupInlineCrypt() '; } - $decrypt_block.= ' - $in = pack("N*", - $r ^ ' . $p[0] . ', - $l ^ ' . $p[1] . ' - ); + $_decryptBlock.= ' + $in = pack("N*", $r ^ $p_0, $l ^ $p_1); '; - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => '', - 'init_decrypt' => '', - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); + // Generating mode of operation code: + switch ($mode) { + case CRYPT_BLOWFISH_MODE_ECB: + $encrypt = ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_encryptBlock.' + $ciphertext.= $in; + } + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_BLOWFISH_MODE_CBC: + $encrypt = ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + $in = $self->encryptIV; + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.') ^ $in; + '.$_encryptBlock.' + $ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + $iv = $self->decryptIV; + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $block = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in ^ $iv; + $iv = $block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $iv; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_BLOWFISH_MODE_CTR: + $encrypt = ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["encrypted"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["encrypted"])) { + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $buffer["encrypted"].= $in; + } + $key = $self->_string_shift($buffer["encrypted"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $key = $in; + $ciphertext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"]; + } + } + + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["ciphertext"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["ciphertext"])) { + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $buffer["ciphertext"].= $in; + } + $key = $self->_string_shift($buffer["ciphertext"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $key = $in; + $plaintext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"]; + } + } + return $plaintext; + '; + break; + case CRYPT_BLOWFISH_MODE_CFB: + $encrypt = ' + $ciphertext = ""; + $buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $iv = &$self->encryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->encryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.'; + $iv = $in ^ substr($text, $i, '.$block_size.'); + $ciphertext.= $iv; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $block = $iv ^ substr($text, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $iv = &$self->decryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->decryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $cb = substr($text, $i, '.$block_size.'); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $plaintext.= $iv ^ substr($text, $i); + $iv = substr_replace($iv, substr($text, $i), 0, $len); + $pos = $len; + } + + return $plaintext; + '; + break; + case CRYPT_BLOWFISH_MODE_OFB: + $encrypt = ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $plaintext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $plaintext; + '; + break; + } + $fnc_head = '$action, &$self, $text'; + $fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'; + + if (function_exists('create_function') && is_callable('create_function')) { + $lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body); + } else { + eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }'); + } } $this->inline_crypt = $lambda_functions[$code_hash]; + }/*}}}*/ + + /** + * Holds the lambda_functions table (classwide) + * + * @see inline_crypt_setup() + * @return Array + * @access private + */ + function &get_lambda_functions() + { + static $functions = array(); + return $functions; } } diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/DES.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/DES.php index 7789b7d383..87943b016e 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/DES.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/DES.php @@ -39,10 +39,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -59,28 +59,27 @@ * @link http://phpseclib.sourceforge.net */ -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - require_once 'Base.php'; -} - /**#@+ * @access private - * @see Crypt_DES::_setupKey() + * @see Crypt_DES::_prepareKey() * @see Crypt_DES::_processBlock() */ /** - * Contains $keys[CRYPT_DES_ENCRYPT] + * Contains array_reverse($keys[CRYPT_DES_DECRYPT]) */ define('CRYPT_DES_ENCRYPT', 0); /** - * Contains $keys[CRYPT_DES_DECRYPT] + * Contains array_reverse($keys[CRYPT_DES_ENCRYPT]) */ define('CRYPT_DES_DECRYPT', 1); +/** + * Contains $keys[CRYPT_DES_ENCRYPT] as 1-dim array + */ +define('CRYPT_DES_ENCRYPT_1DIM', 2); +/** + * Contains $keys[CRYPT_DES_DECRYPT] as 1-dim array + */ +define('CRYPT_DES_DECRYPT_1DIM', 3); /**#@-*/ /**#@+ @@ -95,31 +94,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_DES_MODE_CTR', CRYPT_MODE_CTR); +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', CRYPT_MODE_ECB); +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', CRYPT_MODE_CBC); +define('CRYPT_DES_MODE_CBC', 2); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB); +define('CRYPT_DES_MODE_CFB', 3); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); +define('CRYPT_DES_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -129,11 +128,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_DES_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_DES_MODE_MCRYPT', 2); /**#@-*/ /** @@ -144,92 +143,166 @@ * @access public * @package Crypt_DES */ -class Crypt_DES extends Crypt_Base { +class Crypt_DES { + /** + * The Key Schedule + * + * @see Crypt_DES::setKey() + * @var Array + * @access private + */ + var $keys = "\0\0\0\0\0\0\0\0"; + /** - * Block Length of the cipher + * The Encryption Mode * - * @see Crypt_Base::block_size + * @see Crypt_DES::Crypt_DES() * @var Integer * @access private */ - var $block_size = 8; + var $mode; /** - * The Key + * Continuous Buffer status * - * @see Crypt_Base::key - * @see setKey() - * @var String + * @see Crypt_DES::enableContinuousBuffer() + * @var Boolean * @access private */ - var $key = "\0\0\0\0\0\0\0\0"; + var $continuousBuffer = false; /** - * The default password key_size used by setPassword() + * Padding status * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer + * @see Crypt_DES::enablePadding() + * @var Boolean * @access private */ - var $password_key_size = 8; + var $padding = true; /** - * The namespace used by the cipher for its constants. + * The Initialization Vector * - * @see Crypt_Base::const_namespace + * @see Crypt_DES::setIV() * @var String * @access private */ - var $const_namespace = 'DES'; + var $iv = "\0\0\0\0\0\0\0\0"; /** - * The mcrypt specific name of the cipher + * A "sliding" Initialization Vector * - * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_DES::enableContinuousBuffer() * @var String * @access private */ - var $cipher_name_mcrypt = 'des'; + var $encryptIV = "\0\0\0\0\0\0\0\0"; /** - * Optimizing value while CFB-encrypting + * A "sliding" Initialization Vector * - * @see Crypt_Base::cfb_init_len - * @var Integer + * @see Crypt_DES::enableContinuousBuffer() + * @var String * @access private */ - var $cfb_init_len = 500; + var $decryptIV = "\0\0\0\0\0\0\0\0"; /** - * Switch for DES/3DES encryption + * mcrypt resource for encryption * - * Used only if $engine == CRYPT_DES_MODE_INTERNAL + * 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_DES::_setupKey() - * @see Crypt_DES::_processBlock() - * @var Integer + * @see Crypt_DES::encrypt() + * @var String * @access private */ - var $des_rounds = 1; + var $enmcrypt; /** - * max possible size of $key + * mcrypt resource for decryption * - * @see Crypt_DES::setKey() + * 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_DES::decrypt() * @var String * @access private */ - var $key_size_max = 8; + var $demcrypt; /** - * The Key Schedule + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_DES::setKey() + * @see Crypt_DES::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_DES::setKey() + * @see Crypt_DES::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_DES::Crypt_DES() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes * - * @see Crypt_DES::_setupKey() + * @see Crypt_DES::encrypt() + * @var Array + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_DES::decrypt() * @var Array * @access private */ - var $keys; + var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_DES::encrypt() + * @see Crypt_DES::decrypt() + * @var String + * @access private + */ + var $ecb; + + /** + * Performance-optimized callback function for en/decrypt() + * + * @var Callback + * @access private + */ + var $inline_crypt; + + /** + * Holds whether performance-optimized $inline_crypt should be used or not. + * + * @var Boolean + * @access private + */ + var $use_inline_crypt = false; /** * Shuffle table. @@ -239,7 +312,7 @@ class Crypt_DES extends Crypt_Base { * corresponding bit in the index value. * * @see Crypt_DES::_processBlock() - * @see Crypt_DES::_setupKey() + * @see Crypt_DES::_prepareKey() * @var Array * @access private */ @@ -665,29 +738,73 @@ class Crypt_DES extends Crypt_Base { /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_DES_MODE_ECB - * - * - CRYPT_DES_MODE_CBC - * - * - CRYPT_DES_MODE_CTR - * - * - CRYPT_DES_MODE_CFB + * 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. * - * - CRYPT_DES_MODE_OFB - * - * If not explictly set, CRYPT_DES_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode + * @return Crypt_DES * @access public */ function Crypt_DES($mode = CRYPT_DES_MODE_CBC) { - parent::Crypt_Base($mode); + if ( !defined('CRYPT_DES_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()): + 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->paddable = true; + $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_CFB: + $this->mode = 'ncfb'; + $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); + break; + case CRYPT_DES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_DES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); + $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); + + break; + default: + switch ($mode) { + case CRYPT_DES_MODE_ECB: + case CRYPT_DES_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_DES_MODE_CTR: + case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_DES_MODE_CBC; + } + if (function_exists('create_function') && is_callable('create_function')) { + $this->inline_crypt_setup(); + $this->use_inline_crypt = true; + } + } } /** @@ -701,50 +818,673 @@ function Crypt_DES($mode = CRYPT_DES_MODE_CBC) * * If the key is not explicitly set, it'll be assumed to be all zero's. * - * @see Crypt_Base::setKey() * @access public * @param String $key */ function setKey($key) { - // We check/cut here only up to max length of the key. - // Key padding to the proper length will be done in _setupKey() - if (strlen($key) > $this->key_size_max) { - $key = substr($key, 0, $this->key_size_max); + $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key); + $this->enchanged = true; + $this->dechanged = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib/salt'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < 8) { // $dkLen == 8 + //$dk.= $this->_pbkdf($password, $salt, $count, $i++); + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } } - // Sets the key - parent::setKey($key); + $this->setKey($key); + } + + /** + * 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->enchanged = true; + $this->dechanged = true; } /** - * Encrypts a block + * 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_Base::_encryptBlock() - * @see Crypt_Base::encrypt() + * @see Crypt_DES::decrypt() * @see Crypt_DES::encrypt() - * @access private - * @param String $in - * @return String + * @access public + * @param String $iv */ - function _encryptBlock($in) + function _generate_xor(&$iv) { - return $this->_processBlock($in, CRYPT_DES_ENCRYPT); + $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; } /** - * Decrypts a block + * 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_Base::_decryptBlock() - * @see Crypt_Base::decrypt() * @see Crypt_DES::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + } + $this->enchanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= 8) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->keys, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); + $iv = substr($ciphertext, -8); + $len%= 8; + } else { + while ($len >= 8) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); + $ciphertext.= $iv; + $len-= 8; + $i+= 8; + } + } + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + } + + 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"); + } + + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; + $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; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + if (strlen($block) > strlen($buffer['encrypted'])) { + $buffer['encrypted'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); + } + $key = $this->_string_shift($buffer['encrypted']); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_DES_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= 8) { + $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT) ^ substr($plaintext, $i, 8); + $ciphertext.= $iv; + $len-= 8; + $i+= 8; + } + if ($len) { + $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + case CRYPT_DES_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor']); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $ciphertext.= substr($plaintext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer['xor'] = substr($key, $start) . $buffer['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->paddable) { + // 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->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + } + $this->dechanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= 8) { + $cb = substr($ciphertext, $i, $len - $len % 8); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -8); + $len%= 8; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + return $plaintext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if (!is_array($this->keys)) { + $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); + } + + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; + $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; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); + } + $key = $this->_string_shift($buffer['ciphertext']); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % 8) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_DES_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + while ($len >= 8) { + $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $cb = substr($ciphertext, $i, 8); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= 8; + $i+= 8; + } + if ($len) { + $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $plaintext.= $iv ^ substr($ciphertext, $i); + $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); + $pos = $len; + } + return $plaintext; + case CRYPT_DES_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor']); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $plaintext.= substr($ciphertext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % 8) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + } + + return $this->paddable ? $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: + * + * + * echo $des->encrypt(substr($plaintext, 0, 8)); + * echo $des->encrypt(substr($plaintext, 8, 8)); + * + * + * echo $des->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $des->encrypt(substr($plaintext, 0, 8)); + * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); + * + * + * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); + * + * + * 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; + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { + mcrypt_generic_init($this->enmcrypt, $this->keys, $this->iv); + mcrypt_generic_init($this->demcrypt, $this->keys, $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 - * @param String $in - * @return String */ - function _decryptBlock($in) + function _pad($text) { - return $this->_processBlock($in, CRYPT_DES_DECRYPT); + $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)"); + $this->padding = true; + } + } + + $pad = 8 - ($length & 7); + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_DES::_pad() + * @access private + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > 8) { + return false; + } + + return substr($text, 0, -$length); } /** @@ -754,8 +1494,6 @@ function _decryptBlock($in) * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general * idea of what this function does. * - * @see Crypt_DES::_encryptBlock() - * @see Crypt_DES::_decryptBlock() * @access private * @param String $block * @param Integer $mode @@ -763,93 +1501,74 @@ function _decryptBlock($in) */ function _processBlock($block, $mode) { - static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; - if (!$sbox1) { - $sbox1 = array_map("intval", $this->sbox1); - $sbox2 = array_map("intval", $this->sbox2); - $sbox3 = array_map("intval", $this->sbox3); - $sbox4 = array_map("intval", $this->sbox4); - $sbox5 = array_map("intval", $this->sbox5); - $sbox6 = array_map("intval", $this->sbox6); - $sbox7 = array_map("intval", $this->sbox7); - $sbox8 = array_map("intval", $this->sbox8); - /* Merge $shuffle with $[inv]ipmap */ - for ($i = 0; $i < 256; ++$i) { - $shuffleip[] = $this->shuffle[$this->ipmap[$i]]; - $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]]; - } - } - + $shuffle = $this->shuffle; + $invipmap = $this->invipmap; + $ipmap = $this->ipmap; + $sbox1 = $this->sbox1; + $sbox2 = $this->sbox2; + $sbox3 = $this->sbox3; + $sbox4 = $this->sbox4; + $sbox5 = $this->sbox5; + $sbox6 = $this->sbox6; + $sbox7 = $this->sbox7; + $sbox8 = $this->sbox8; $keys = $this->keys[$mode]; - $ki = -1; // Do the initial IP permutation. $t = unpack('Nl/Nr', $block); list($l, $r) = array($t['l'], $t['r']); - $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); + $block = ($shuffle[$ipmap[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffle[$ipmap[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01"); // Extract L0 and R0. $t = unpack('Nl/Nr', $block); list($l, $r) = array($t['l'], $t['r']); - for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { - // Perform the 16 steps. - for ($i = 0; $i < 16; $i++) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - // Merge key schedule. - $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki]; - $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki]; - - // S-box indexing. - $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ - $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ - $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ - $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l; - // end of "the Feistel (F) function" - - $l = $r; - $r = $t; - } + // Perform the 16 steps. + for ($i = 0; $i < 16; $i++) { + // start of "the Feistel (F) function" - see the following URL: + // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png + // Merge key schedule. + $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[$i][0]; + $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[$i][1]; + + // S-box indexing. + $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ + $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ + $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ + $sbox7[$b1 & 0x3F] ^ $sbox8[$b2 & 0x3F] ^ $l; + // end of "the Feistel (F) function" - // Last step should not permute L & R. - $t = $l; $l = $r; $r = $t; } // Perform the inverse IP permutation. - return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); + return ($shuffle[$invipmap[($l >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffle[$invipmap[($r >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffle[$invipmap[($l >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffle[$invipmap[($r >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffle[$invipmap[($l >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffle[$invipmap[($r >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffle[$invipmap[$l & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffle[$invipmap[$r & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01"); } /** - * Creates the key schedule + * Creates the key schedule. * - * @see Crypt_Base::_setupKey() * @access private + * @param String $key + * @return Array */ - function _setupKey() + function _prepareKey($key) { - if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) { - // already expanded - return; - } - $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds); - static $shifts = array( // number of key bits shifted per round 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ); @@ -1299,237 +2018,518 @@ function _setupKey() 0x10081108, 0x10081508, 0x11081108, 0x11081508 ); + // pad the key and remove extra characters as appropriate. + $key = str_pad(substr($key, 0, 8), 8, chr(0)); + + // Perform the PC/1 transformation and compute C and D. + $t = unpack('Nl/Nr', $key); + list($l, $r) = array($t['l'], $t['r']); + $key = ($this->shuffle[$pc1map[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") | + ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") | + ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") | + ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") | + ($this->shuffle[$pc1map[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") | + ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") | + ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") | + ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00"); + $key = unpack('Nc/Nd', $key); + $c = ($key['c'] >> 4) & 0x0FFFFFFF; + $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F); + $keys = array(); - for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { - // pad the key and remove extra characters as appropriate. - $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0"); - - // Perform the PC/1 transformation and compute C and D. - $t = unpack('Nl/Nr', $key); - list($l, $r) = array($t['l'], $t['r']); - $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") | - ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") | - ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") | - ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") | - ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") | - ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") | - ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") | - ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00"); - $key = unpack('Nc/Nd', $key); - $c = ( $key['c'] >> 4) & 0x0FFFFFFF; - $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F); - - $keys[$des_round] = array( - CRYPT_DES_ENCRYPT => array(), - CRYPT_DES_DECRYPT => array_fill(0, 32, 0) + for ($i = 0; $i < 16; $i++) { + $c <<= $shifts[$i]; + $c = ($c | ($c >> 28)) & 0x0FFFFFFF; + $d <<= $shifts[$i]; + $d = ($d | ($d >> 28)) & 0x0FFFFFFF; + + // Perform the PC-2 transformation. + $cp = $pc2mapc1[$c >> 24] | $pc2mapc2[($c >> 16) & 0xFF] | + $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[$c & 0xFF]; + $dp = $pc2mapd1[$d >> 24] | $pc2mapd2[($d >> 16) & 0xFF] | + $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[$d & 0xFF]; + + // Reorder: odd bytes/even bytes. Push the result in key schedule. + $keys[] = array( + ($cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | + (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF), + (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | + (($dp >> 8) & 0x0000FF00) | ($dp & 0x000000FF) ); - for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) { - $c <<= $shifts[$i]; - $c = ($c | ($c >> 28)) & 0x0FFFFFFF; - $d <<= $shifts[$i]; - $d = ($d | ($d >> 28)) & 0x0FFFFFFF; - - // Perform the PC-2 transformation. - $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] | - $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF]; - $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] | - $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; - - // Reorder: odd bytes/even bytes. Push the result in key schedule. - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = - $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | - (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = - $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | - (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); - } } - switch ($this->des_rounds) { - case 3: // 3DES keys - $this->keys = array( - CRYPT_DES_ENCRYPT => array_merge( - $keys[0][CRYPT_DES_ENCRYPT], - $keys[1][CRYPT_DES_DECRYPT], - $keys[2][CRYPT_DES_ENCRYPT] - ), - CRYPT_DES_DECRYPT => array_merge( - $keys[2][CRYPT_DES_DECRYPT], - $keys[1][CRYPT_DES_ENCRYPT], - $keys[0][CRYPT_DES_DECRYPT] - ) - ); - break; - // case 1: // DES keys - default: - $this->keys = array( - CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT], - CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT] - ); + $keys = array( + CRYPT_DES_ENCRYPT => $keys, + CRYPT_DES_DECRYPT => array_reverse($keys), + CRYPT_DES_ENCRYPT_1DIM => array(), + CRYPT_DES_DECRYPT_1DIM => array() + ); + + // Generate 1-dim arrays for inline en/decrypting + for ($i = 0; $i < 16; ++$i) { + $keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][0]; + $keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][1]; + $keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][0]; + $keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][1]; } + + return $keys; } /** - * Setup the performance-optimized function for de/encrypt() + * String Shift + * + * Inspired by array_shift * - * @see Crypt_Base::_setupInlineCrypt() + * @param String $string + * @return String * @access private */ - function _setupInlineCrypt() + function _string_shift(&$string) { - $lambda_functions =& Crypt_DES::_getLambdaFunctions(); - - // Engine configuration for: - // - DES ($des_rounds == 1) or - // - 3DES ($des_rounds == 3) - $des_rounds = $this->des_rounds; - - // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. - // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - - // Generation of a uniqe hash for our generated code - switch (true) { - case $gen_hi_opt_code: - // For hi-optimized code, we create for each combination of - // $mode, $des_rounds and $this->key its own encrypt/decrypt function. - $code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - // After max 10 hi-optimized functions, we create generic - // (still very fast.. but not ultra) functions for each $mode/$des_rounds - // Currently 2 * 5 generic functions will be then max. possible. - $code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; - } + $substr = substr($string, 0, 8); + $string = substr($string, 8); + return $substr; + } + + /** + * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt + * + * @param optional Integer $des_rounds (1 = DES[default], 3 = TribleDES) + * @access private + */ + function inline_crypt_setup($des_rounds = 1) + { + $lambda_functions =& Crypt_DES::get_lambda_functions(); + $block_size = 8; + $mode = $this->mode; + + $code_hash = "$mode,$des_rounds"; - // Is there a re-usable $lambda_functions in there? If not, we have to create it. if (!isset($lambda_functions[$code_hash])) { - // Init code for both, encrypt and decrypt. - $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; - if (!$sbox1) { - $sbox1 = array_map("intval", $self->sbox1); - $sbox2 = array_map("intval", $self->sbox2); - $sbox3 = array_map("intval", $self->sbox3); - $sbox4 = array_map("intval", $self->sbox4); - $sbox5 = array_map("intval", $self->sbox5); - $sbox6 = array_map("intval", $self->sbox6); - $sbox7 = array_map("intval", $self->sbox7); - $sbox8 = array_map("intval", $self->sbox8);' - /* Merge $shuffle with $[inv]ipmap */ . ' - for ($i = 0; $i < 256; ++$i) { - $shuffleip[] = $self->shuffle[$self->ipmap[$i]]; - $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]]; - } + // Generating encrypt code: + $ki = -1; + $init_cryptBlock = ' + $shuffle = $self->shuffle; + $invipmap = $self->invipmap; + $ipmap = $self->ipmap; + $sbox1 = $self->sbox1; + $sbox2 = $self->sbox2; + $sbox3 = $self->sbox3; + $sbox4 = $self->sbox4; + $sbox5 = $self->sbox5; + $sbox6 = $self->sbox6; + $sbox7 = $self->sbox7; + $sbox8 = $self->sbox8; + '; + + $_cryptBlock = '$in = unpack("N*", $in);'."\n"; + // Do the initial IP permutation. + $_cryptBlock .= ' + $l = $in[1]; + $r = $in[2]; + $in = unpack("N*", + ($shuffle[$ipmap[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffle[$ipmap[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01") + ); + + '.'' /* Extract L0 and R0 */ .' + $l = $in[1]; + $r = $in[2]; + '; + + $l = 'l'; + $r = 'r'; + for ($des_round = 0; $des_round < $des_rounds; ++$des_round) { + // Perform the 16 steps. + // start of "the Feistel (F) function" - see the following URL: + // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png + // Merge key schedule. + for ($i = 0; $i < 8; ++$i) { + $_cryptBlock .= ' + $b1 = (($' . $r . ' >> 3) & 0x1FFFFFFF) ^ ($' . $r . ' << 29) ^ $k_'.(++$ki).'; + $b2 = (($' . $r . ' >> 31) & 0x00000001) ^ ($' . $r . ' << 1) ^ $k_'.(++$ki).'; + $' . $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ + $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ + $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ + $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $l . '; + + $b1 = (($' . $l . ' >> 3) & 0x1FFFFFFF) ^ ($' . $l . ' << 29) ^ $k_'.(++$ki).'; + $b2 = (($' . $l . ' >> 31) & 0x00000001) ^ ($' . $l . ' << 1) ^ $k_'.(++$ki).'; + $' . $r . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ + $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ + $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ + $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $r . '; + '; } + + // Last step should not permute L & R. + $t = $l; + $l = $r; + $r = $t; + } + + // Perform the inverse IP permutation. + $_cryptBlock .= '$in = ( + ($shuffle[$invipmap[($' . $r . ' >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffle[$invipmap[($' . $l . ' >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffle[$invipmap[($' . $r . ' >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffle[$invipmap[($' . $l . ' >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffle[$invipmap[($' . $r . ' >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffle[$invipmap[($' . $l . ' >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffle[$invipmap[ $' . $r . ' & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffle[$invipmap[ $' . $l . ' & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01") + ); '; - switch (true) { - case $gen_hi_opt_code: - // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers. - // No futher initialisation of the $keys schedule is necessary. - // That is the extra performance boost. - $k = array( - CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT], - CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT] - ); - $init_encrypt = ''; - $init_decrypt = ''; - break; - default: - // In generic optimized code mode, we have to use, as the best compromise [currently], - // our key schedule as $ke/$kd arrays. (with hardcoded indexes...) - $k = array( - CRYPT_DES_ENCRYPT => array(), - CRYPT_DES_DECRYPT => array() - ); - for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) { - $k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']'; - $k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']'; - } - $init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];'; - $init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];'; + // Generating mode of operation code: + switch ($mode) { + case CRYPT_DES_MODE_ECB: + $encrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $ciphertext = ""; + $plaintext_len = strlen($text); + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_cryptBlock.' + $ciphertext.= $in; + } + + return $ciphertext; + '; + + $decrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $plaintext = ""; + $ciphertext_len = strlen($text); + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_cryptBlock.' + $plaintext.= $in; + } + + return $self->_unpad($plaintext); + '; break; - } + case CRYPT_DES_MODE_CBC: + $encrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $ciphertext = ""; + $plaintext_len = strlen($text); + + $in = $self->encryptIV; + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.') ^ $in; + '.$_cryptBlock.' + $ciphertext.= $in; + } - // Creating code for en- and decryption. - $crypt_block = array(); - foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) { - - /* Do the initial IP permutation. */ - $crypt_block[$c] = ' - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - $in = unpack("N*", - ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01") - ); - ' . /* Extract L0 and R0 */ ' - $l = $in[1]; - $r = $in[2]; - '; - - $l = '$l'; - $r = '$r'; - - // Perform DES or 3DES. - for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) { - // Perform the 16 steps. - for ($i = 0; $i < 16; ++$i) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - // Merge key schedule. - $crypt_block[$c].= ' - $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . '; - $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' . - /* S-box indexing. */ - $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ - $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ - $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ - $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . '; + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $ciphertext; '; - // end of "the Feistel (F) function" - // swap L & R - list($l, $r) = array($r, $l); - } - list($l, $r) = array($r, $l); - } + $decrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $plaintext = ""; + $ciphertext_len = strlen($text); - // Perform the inverse IP permutation. - $crypt_block[$c].= '$in = - ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); - '; - } + $iv = $self->decryptIV; - // Creates the inline-crypt function - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => $init_encrypt, - 'init_decrypt' => $init_decrypt, - 'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT], - 'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT] - ) - ); - } + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $block = substr($text, $i, '.$block_size.'); + '.$_cryptBlock.' + $plaintext.= $in ^ $iv; + $iv = $block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $iv; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_DES_MODE_CTR: + $encrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["encrypted"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["encrypted"])) { + $in = $self->_generate_xor($xor); + '.$_cryptBlock.' + $buffer["encrypted"].= $in; + } + $key = $self->_string_shift($buffer["encrypted"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_cryptBlock.' + $key = $in; + $ciphertext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"]; + } + } + + return $ciphertext; + '; + + $decrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["ciphertext"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["ciphertext"])) { + $in = $self->_generate_xor($xor); + '.$_cryptBlock.' + $buffer["ciphertext"].= $in; + } + $key = $self->_string_shift($buffer["ciphertext"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_cryptBlock.' + $key = $in; + $plaintext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"]; + } + } + + return $plaintext; + '; + break; + case CRYPT_DES_MODE_CFB: + $encrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $ciphertext = ""; + $buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $iv = &$self->encryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->encryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_cryptBlock.'; + $iv = $in ^ substr($text, $i, '.$block_size.'); + $ciphertext.= $iv; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_cryptBlock.' + $iv = $in; + $block = $iv ^ substr($text, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + '; + + $decrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $plaintext = ""; + $buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $iv = &$self->decryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->decryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_cryptBlock.' + $iv = $in; + $cb = substr($text, $i, '.$block_size.'); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_cryptBlock.' + $iv = $in; + $plaintext.= $iv ^ substr($text, $i); + $iv = substr_replace($iv, substr($text, $i), 0, $len); + $pos = $len; + } + + return $plaintext; + '; + break; + case CRYPT_DES_MODE_OFB: + $encrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_cryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_cryptBlock.' + $xor = $in; + $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $ciphertext; + '; - // Set the inline-crypt function as callback in: $this->inline_crypt + $decrypt = $init_cryptBlock . ' + extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k"); + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_cryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_cryptBlock.' + $xor = $in; + $plaintext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $plaintext; + '; + break; + } + $lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }'); + } $this->inline_crypt = $lambda_functions[$code_hash]; } + + /** + * Holds the lambda_functions table (classwide) + * + * @see inline_crypt_setup() + * @return Array + * @access private + */ + function &get_lambda_functions() + { + static $functions = array(); + return $functions; + } } // vim: ts=4:sw=4:et: diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/RC4.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/RC4.php index 7b9de4ca10..97f7ece164 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/RC4.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/RC4.php @@ -41,10 +41,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -61,15 +61,6 @@ * @link http://phpseclib.sourceforge.net */ -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - require_once 'Base.php'; -} - /**#@+ * @access private * @see Crypt_RC4::Crypt_RC4() @@ -77,11 +68,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_RC4_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_RC4_MODE_MCRYPT', 2); /**#@-*/ /**#@+ @@ -100,87 +91,201 @@ * @access public * @package Crypt_RC4 */ -class Crypt_RC4 extends Crypt_Base { +class Crypt_RC4 { /** - * Block Length of the cipher - * - * RC4 is a stream cipher - * so we the block_size to 0 + * The Key * - * @see Crypt_Base::block_size - * @var Integer + * @see Crypt_RC4::setKey() + * @var String * @access private */ - var $block_size = 0; + var $key = "\0"; /** - * The default password key_size used by setPassword() + * The Key Stream for encryption * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer + * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object + * + * @see Crypt_RC4::setKey() + * @var Array * @access private */ - var $password_key_size = 128; // = 1024 bits + var $encryptStream = false; /** - * The namespace used by the cipher for its constants. + * The Key Stream for decryption * - * @see Crypt_Base::const_namespace - * @var String + * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object + * + * @see Crypt_RC4::setKey() + * @var Array * @access private */ - var $const_namespace = 'RC4'; - + var $decryptStream = false; /** - * The mcrypt specific name of the cipher + * The $i and $j indexes for encryption * - * @see Crypt_Base::cipher_name_mcrypt - * @var String + * @see Crypt_RC4::_crypt() + * @var Integer * @access private */ - var $cipher_name_mcrypt = 'arcfour'; + var $encryptIndex = 0; /** - * Holds whether performance-optimized $inline_crypt() can/should be used. + * The $i and $j indexes for decryption * - * @see Crypt_Base::inline_crypt - * @var mixed + * @see Crypt_RC4::_crypt() + * @var Integer * @access private */ - var $use_inline_crypt = false; // currently not available + var $decryptIndex = 0; /** - * The Key + * The Encryption Algorithm * - * @see Crypt_RC4::setKey() - * @var String + * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR. + * + * @see Crypt_RC4::Crypt_RC4() + * @var Integer * @access private */ - var $key = "\0"; + var $mode; /** - * The Key Stream for decryption and encryption + * Continuous Buffer status * - * @see Crypt_RC4::setKey() - * @var Array + * @see Crypt_RC4::enableContinuousBuffer() + * @var Boolean * @access private */ - var $stream; + var $continuousBuffer = false; /** * Default Constructor. * * Determines whether or not the mcrypt extension should be used. * - * @see Crypt_Base::Crypt_Base() * @return Crypt_RC4 * @access public */ function Crypt_RC4() { - parent::Crypt_Base(CRYPT_MODE_STREAM); + if ( !defined('CRYPT_RC4_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()): + define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT); + break; + default: + define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL); + } + } + + switch ( CRYPT_RC4_MODE ) { + case CRYPT_RC4_MODE_MCRYPT: + switch (true) { + case defined('MCRYPT_ARCFOUR'): + $this->mode = MCRYPT_ARCFOUR; + break; + case defined('MCRYPT_RC4'); + $this->mode = MCRYPT_RC4; + } + $this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); + $this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); + + } + } + + /** + * Sets the key. + * + * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will + * be used. If no key is explicitly set, it'll be assumed to be a single null byte. + * + * @access public + * @param String $key + */ + function setKey($key) + { + $this->key = $key; + + if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { + mcrypt_generic_init($this->encryptStream, $this->key, ''); + mcrypt_generic_init($this->decryptStream, $this->key, ''); + return; + } + + $keyLength = strlen($key); + $keyStream = array(); + for ($i = 0; $i < 256; $i++) { + $keyStream[$i] = $i; + } + $j = 0; + for ($i = 0; $i < 256; $i++) { + $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; + $temp = $keyStream[$i]; + $keyStream[$i] = $keyStream[$j]; + $keyStream[$j] = $temp; + } + + $this->encryptIndex = $this->decryptIndex = array(0, 0); + $this->encryptStream = $this->decryptStream = $keyStream; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count, $dkLen + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib/salt'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + if (!isset($dkLen)) { + $dkLen = 128; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < $dkLen) { + //$dk.= $this->_pbkdf($password, $salt, $count, $i++); + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey(substr($key, 0, $dkLen)); } /** @@ -206,35 +311,15 @@ function setIV($iv) { } - /** - * Sets the key. - * - * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will - * be used. If no key is explicitly set, it'll be assumed to be a single null byte. - * - * @access public - * @see Crypt_Base::setKey() - * @param String $key - */ - function setKey($key) - { - parent::setKey(substr($key, 0, 256)); - } - /** * Encrypts a message. * - * @see Crypt_Base::decrypt() * @see Crypt_RC4::_crypt() * @access public * @param String $plaintext - * @return String $ciphertext */ function encrypt($plaintext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { - return parent::encrypt($plaintext); - } return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); } @@ -244,92 +329,162 @@ function encrypt($plaintext) * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * Atleast if the continuous buffer is disabled. * - * @see Crypt_Base::encrypt() * @see Crypt_RC4::_crypt() * @access public * @param String $ciphertext - * @return String $plaintext */ function decrypt($ciphertext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { - return parent::decrypt($ciphertext); - } return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); } - /** - * Setup the key (expansion) + * Encrypts or decrypts a message. * - * @see Crypt_Base::_setupKey() + * @see Crypt_RC4::encrypt() + * @see Crypt_RC4::decrypt() * @access private + * @param String $text + * @param Integer $mode */ - function _setupKey() + function _crypt($text, $mode) { - $key = $this->key; - $keyLength = strlen($key); - $keyStream = array(); - for ($i = 0; $i < 256; $i++) { - $keyStream[$i] = $i; + if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { + $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->$keyStream, $this->key, ''); + } + + return mcrypt_generic($this->$keyStream, $text); } - $j = 0; - for ($i = 0; $i < 256; $i++) { - $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; + + if ($this->encryptStream === false) { + $this->setKey($this->key); + } + + switch ($mode) { + case CRYPT_RC4_ENCRYPT: + $keyStream = $this->encryptStream; + list($i, $j) = $this->encryptIndex; + break; + case CRYPT_RC4_DECRYPT: + $keyStream = $this->decryptStream; + list($i, $j) = $this->decryptIndex; + } + + $newText = ''; + for ($k = 0; $k < strlen($text); $k++) { + $i = ($i + 1) & 255; + $j = ($j + $keyStream[$i]) & 255; $temp = $keyStream[$i]; $keyStream[$i] = $keyStream[$j]; $keyStream[$j] = $temp; + $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255]; + $newText.= chr(ord($text[$k]) ^ $temp); + } + + if ($this->continuousBuffer) { + switch ($mode) { + case CRYPT_RC4_ENCRYPT: + $this->encryptStream = $keyStream; + $this->encryptIndex = array($i, $j); + break; + case CRYPT_RC4_DECRYPT: + $this->decryptStream = $keyStream; + $this->decryptIndex = array($i, $j); + } } - $this->stream = array(); - $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array( - 0, // index $i - 0, // index $j - $keyStream - ); + return $newText; } /** - * Encrypts or decrypts a message. + * Treat consecutive "packets" as if they are a continuous buffer. * - * @see Crypt_RC4::encrypt() - * @see Crypt_RC4::decrypt() - * @access private - * @param String $text - * @param Integer $mode - * @return String $text + * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rc4->encrypt(substr($plaintext, 0, 8)); + * echo $rc4->encrypt(substr($plaintext, 8, 8)); + * + * + * echo $rc4->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rc4->encrypt(substr($plaintext, 0, 8)); + * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); + * + * + * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); + * + * + * 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_RC4::disableContinuousBuffer() + * @access public */ - function _crypt($text, $mode) + function enableContinuousBuffer() { - if ($this->changed) { - $this->_setup(); - $this->changed = false; + if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { + mcrypt_generic_init($this->encryptStream, $this->key, ''); + mcrypt_generic_init($this->decryptStream, $this->key, ''); } - $stream = &$this->stream[$mode]; - if ($this->continuousBuffer) { - $i = &$stream[0]; - $j = &$stream[1]; - $keyStream = &$stream[2]; - } else { - $i = $stream[0]; - $j = $stream[1]; - $keyStream = $stream[2]; + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_RC4::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) { + $this->encryptIndex = $this->decryptIndex = array(0, 0); + $this->encryptStream = $this->decryptStream = false; } - $len = strlen($text); - for ($k = 0; $k < $len; ++$k) { - $i = ($i + 1) & 255; - $ksi = $keyStream[$i]; - $j = ($j + $ksi) & 255; - $ksj = $keyStream[$j]; + $this->continuousBuffer = false; + } - $keyStream[$i] = $ksj; - $keyStream[$j] = $ksi; - $text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]); - } + /** + * Dummy function. + * + * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is + * included is so that you can switch between a block cipher and a stream cipher transparently. + * + * @see Crypt_RC4::disablePadding() + * @access public + */ + function enablePadding() + { + } - return $text; + /** + * Dummy function. + * + * @see Crypt_RC4::enablePadding() + * @access public + */ + function disablePadding() + { } } diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Rijndael.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Rijndael.php index 9be500e678..b81e87d850 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Rijndael.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Rijndael.php @@ -4,26 +4,25 @@ /** * Pure-PHP implementation of Rijndael. * - * Uses mcrypt, if available/possible, and an internal implementation, otherwise. + * Does not use mcrypt, even when available, for reasons that are explained below. * * PHP versions 4 and 5 * - * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If - * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from - * {@link Crypt_Rijndael::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 192-bits and 192 bits will be the key length until + * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If + * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from + * {@link Crypt_Rijndael::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. * * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example, * 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 * 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 - * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: + * are first defined as valid key / block lengths in + * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: * Extensions: Other block and Cipher Key lengths. - * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224). * - * {@internal The variable names are the same as those in + * {@internal The variable names are the same as those in * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}} * * Here's a short example of how to use this library: @@ -51,10 +50,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -71,15 +70,6 @@ * @link http://phpseclib.sourceforge.net */ -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - require_once 'Base.php'; -} - /**#@+ * @access public * @see Crypt_Rijndael::encrypt() @@ -92,31 +82,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR); +define('CRYPT_RIJNDAEL_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_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB); +define('CRYPT_RIJNDAEL_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_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC); +define('CRYPT_RIJNDAEL_MODE_CBC', 2); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); +define('CRYPT_RIJNDAEL_MODE_CFB', 3); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); +define('CRYPT_RIJNDAEL_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -126,11 +116,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); /**#@-*/ /** @@ -141,51 +131,80 @@ * @access public * @package Crypt_Rijndael */ -class Crypt_Rijndael extends Crypt_Base { +class Crypt_Rijndael { /** - * The default password key_size used by setPassword() + * The Encryption Mode * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() + * @see Crypt_Rijndael::Crypt_Rijndael() * @var Integer * @access private */ - var $password_key_size = 16; + var $mode; /** - * The namespace used by the cipher for its constants. + * The Key * - * @see Crypt_Base::const_namespace + * @see Crypt_Rijndael::setKey() * @var String * @access private */ - var $const_namespace = 'RIJNDAEL'; + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /** - * The mcrypt specific name of the cipher + * The Initialization Vector * - * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. - * Crypt_Rijndael determines automatically whether mcrypt is useable - * or not for the current $block_size/$key_size. - * In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. + * @see Crypt_Rijndael::setIV() + * @var String + * @access private + */ + var $iv = ''; + + /** + * A "sliding" Initialization Vector * - * @see Crypt_Base::cipher_name_mcrypt - * @see Crypt_Base::engine - * @see _setupEngine() + * @see Crypt_Rijndael::enableContinuousBuffer() * @var String * @access private */ - var $cipher_name_mcrypt = 'rijndael-128'; + var $encryptIV = ''; /** - * The default salt used by setPassword() + * A "sliding" Initialization Vector * - * @see Crypt_Base::password_default_salt - * @see Crypt_Base::setPassword() + * @see Crypt_Rijndael::enableContinuousBuffer() * @var String * @access private */ - var $password_default_salt = 'phpseclib'; + var $decryptIV = ''; + + /** + * Continuous Buffer status + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Padding status + * + * @see Crypt_Rijndael::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + + /** + * Does the key schedule need to be (re)calculated? + * + * @see setKey() + * @see setBlockLength() + * @see setKeyLength() + * @var Boolean + * @access private + */ + var $changed = true; /** * Has the key length explicitly been set or should it be derived from the key, itself? @@ -214,14 +233,25 @@ class Crypt_Rijndael extends Crypt_Base { */ var $dw; + /** + * The Block Length + * + * @see setBlockLength() + * @var Integer + * @access private + * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with + * $Nb because we need this value and not $Nb to pad strings appropriately. + */ + var $block_size = 16; + /** * The Block Length divided by 32 * * @see setBlockLength() * @var Integer * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size - * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size + * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. * @@ -234,8 +264,8 @@ class Crypt_Rijndael extends Crypt_Base { * @see setKeyLength() * @var Integer * @access private - * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk - * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could + * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size + * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. */ @@ -268,361 +298,77 @@ class Crypt_Rijndael extends Crypt_Base { */ var $c; - /** - * Holds the last used key- and block_size information - * - * @var Array - * @access private - */ - var $kl; - /** * Precomputed mixColumns table * - * According to (section 5.2.1), - * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so - * those are the names we'll use. - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $t0 = array( - 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, - 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, - 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, - 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, - 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, - 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, - 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, - 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, - 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, - 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, - 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, - 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, - 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, - 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, - 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, - 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, - 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, - 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, - 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, - 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, - 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, - 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, - 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, - 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, - 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, - 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, - 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, - 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, - 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, - 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, - 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, - 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A - ); + var $t0; /** * Precomputed mixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $t1 = array( - 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, - 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, - 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, - 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, - 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, - 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, - 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, - 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, - 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, - 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, - 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, - 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, - 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, - 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, - 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, - 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, - 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, - 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, - 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, - 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, - 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, - 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, - 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, - 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, - 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, - 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, - 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, - 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, - 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, - 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, - 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, - 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 - ); + var $t1; /** * Precomputed mixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $t2 = array( - 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, - 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, - 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, - 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, - 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, - 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, - 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, - 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, - 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, - 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, - 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, - 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, - 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, - 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, - 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, - 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, - 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, - 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, - 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, - 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, - 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, - 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, - 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, - 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, - 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, - 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, - 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, - 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, - 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, - 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, - 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, - 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 - ); + var $t2; /** * Precomputed mixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $t3 = array( - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C - ); + var $t3; /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $dt0 = array( - 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, - 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, - 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, - 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, - 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, - 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, - 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, - 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, - 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, - 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, - 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, - 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, - 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, - 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, - 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, - 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, - 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, - 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, - 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, - 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, - 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, - 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, - 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, - 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, - 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, - 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, - 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, - 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, - 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, - 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, - 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, - 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 - ); + var $dt0; /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $dt1 = array( - 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, - 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, - 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, - 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, - 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, - 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, - 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, - 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, - 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, - 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, - 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, - 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, - 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, - 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, - 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, - 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, - 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, - 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, - 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, - 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, - 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, - 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, - 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, - 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, - 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, - 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, - 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, - 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, - 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, - 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, - 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, - 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 - ); + var $dt1; /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $dt2 = array( - 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, - 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, - 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, - 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, - 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, - 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, - 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, - 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, - 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, - 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, - 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, - 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, - 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, - 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, - 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, - 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, - 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, - 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, - 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, - 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, - 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, - 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, - 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, - 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, - 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, - 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, - 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, - 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, - 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, - 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, - 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, - 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 - ); + var $dt2; /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael() * @var Array * @access private */ - var $dt3 = array( - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 - ); + var $dt3; /** * The SubByte S-Box @@ -631,24 +377,7 @@ class Crypt_Rijndael extends Crypt_Base { * @var Array * @access private */ - var $sbox = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - ); + var $sbox; /** * The inverse SubByte S-Box @@ -657,51 +386,222 @@ class Crypt_Rijndael extends Crypt_Base { * @var Array * @access private */ - var $isbox = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); + var $isbox; /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. + * Performance-optimized callback function for en/decrypt() * - * $mode could be: - * - * - CRYPT_RIJNDAEL_MODE_ECB + * @see Crypt_Rijndael::encrypt() + * @see Crypt_Rijndael::decrypt() + * @see Crypt_Rijndael::inline_crypt_setup() + * @see Crypt_Rijndael::$use_inline_crypt + * @var Callback + * @access private + */ + var $inline_crypt; + + /** + * Holds whether performance-optimized $inline_crypt should be used or not. * - * - CRYPT_RIJNDAEL_MODE_CBC + * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Rijndael::inline_crypt_setup() + * @see Crypt_Rijndael::$inline_crypt + * @var Boolean + * @access private + */ + var $use_inline_crypt = true; + + /** + * Is the mode one that is paddable? * - * - CRYPT_RIJNDAEL_MODE_CTR + * @see Crypt_Rijndael::Crypt_Rijndael() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes * - * - CRYPT_RIJNDAEL_MODE_CFB + * @see Crypt_Rijndael::encrypt() + * @var String + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0); + + /** + * Decryption buffer for CTR, OFB and CFB modes * - * - CRYPT_RIJNDAEL_MODE_OFB + * @see Crypt_Rijndael::decrypt() + * @var String + * @access private + */ + var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0); + + /** + * Default Constructor. * - * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * 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. * - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode + * @return Crypt_Rijndael * @access public */ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) { - parent::Crypt_Base($mode); + switch ($mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + case CRYPT_RIJNDAEL_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_RIJNDAEL_MODE_CTR: + case CRYPT_RIJNDAEL_MODE_CFB: + case CRYPT_RIJNDAEL_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_CBC; + } + + $t3 = &$this->t3; + $t2 = &$this->t2; + $t1 = &$this->t1; + $t0 = &$this->t0; + + $dt3 = &$this->dt3; + $dt2 = &$this->dt2; + $dt1 = &$this->dt1; + $dt0 = &$this->dt0; + + // according to (section 5.2.1), + // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + // those are the names we'll use. + $t3 = array( + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + ); + + $dt3 = array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + ); + + for ($i = 0; $i < 256; $i++) { + $t2[] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); + $t1[] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); + $t0[] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); + + $dt2[] = (($dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); + $dt1[] = (($dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); + $dt0[] = (($dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); + } + + // sbox for the S-Box substitution + $this->sbox = array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ); + + // sbox for the inverse S-Box substitution + $this->isbox = array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ); + + if (!function_exists('create_function') || !is_callable('create_function')) { + $this->use_inline_crypt = false; + } } /** @@ -714,31 +614,27 @@ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) * * If the key is not explicitly set, it'll be assumed to be all null bytes. * - * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits. - * - * @see Crypt_Base:setKey() - * @see setKeyLength() * @access public * @param String $key */ function setKey($key) { - parent::setKey($key); + $this->key = $key; + $this->changed = true; + } - if (!$this->explicit_key_length) { - $length = strlen($key); - switch (true) { - case $length <= 16: - $this->key_size = 16; - break; - case $length <= 24: - $this->key_size = 24; - break; - default: - $this->key_size = 32; - } - $this->_setupEngine(); - } + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_RIJNDAEL_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, $this->block_size), $this->block_size, chr(0)); } /** @@ -747,42 +643,76 @@ function setKey($key) * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. * - * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined - * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to - * 192/256 bits as, for example, mcrypt will do. - * - * That said, if you want be compatible with other Rijndael and AES implementations, - * you should not setKeyLength(160) or setKeyLength(224). - * - * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use - * the mcrypt php extention, even if available. - * This results then in slower encryption. - * * @access public * @param Integer $length */ function setKeyLength($length) { - switch (true) { - case $length == 160: - $this->key_size = 20; - break; - case $length == 224: - $this->key_size = 28; - break; - case $length <= 128: - $this->key_size = 16; - break; - case $length <= 192: - $this->key_size = 24; - break; - default: - $this->key_size = 32; + $length >>= 5; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; } + $this->Nk = $length; + $this->key_size = $length << 2; $this->explicit_key_length = true; $this->changed = true; - $this->_setupEngine(); + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $method + * Set $dkLen by calling setKeyLength() + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size + //$dk.= $this->_pbkdf($password, $salt, $count, $i++); + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey(substr($key, 0, $this->key_size)); } /** @@ -805,76 +735,335 @@ function setBlockLength($length) $this->Nb = $length; $this->block_size = $length << 2; $this->changed = true; - $this->_setupEngine(); } /** - * Setup the fastest possible $engine - * - * Determines if the mcrypt (MODE_MCRYPT) $engine available - * and usable for the current $block_size and $key_size. + * Generate CTR XOR encryption key * - * If not, the slower MODE_INTERNAL $engine will be set. + * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the + * plaintext / ciphertext in CTR mode. * - * @see setKey() - * @see setKeyLength() - * @see setBlockLength() - * @access private + * @see Crypt_Rijndael::decrypt() + * @see Crypt_Rijndael::encrypt() + * @access public + * @param Integer $length + * @param String $iv */ - function _setupEngine() + function _generate_xor($length, &$iv) { - if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { - // No mcrypt support at all for rijndael - return; + $xor = ''; + $block_size = $this->block_size; + $num_blocks = floor(($length + ($block_size - 1)) / $block_size); + for ($i = 0; $i < $num_blocks; $i++) { + $xor.= $iv; + for ($j = 4; $j <= $block_size; $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; + } + } } - // The required mcrypt module name for the current $block_size of rijndael - $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); + return $xor; + } - // Determining the availibility/usability of $cipher_name_mcrypt - switch (true) { - case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys - case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size - $engine = CRYPT_MODE_INTERNAL; - break; - default: - $engine = CRYPT_MODE_MCRYPT; + /** + * Encrypts a message. + * + * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael + * 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_Rijndael::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + if ($this->changed) { + $this->_setup(); } - - if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { - // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb - return; + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); } - // Set the $engine - $this->engine = $engine; - $this->cipher_name_mcrypt = $cipher_name_mcrypt; - - if ($this->enmcrypt) { - // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, - // (re)open them with the module named in $this->cipher_name_mcrypt - mcrypt_module_close($this->enmcrypt); - mcrypt_module_close($this->demcrypt); - $this->enmcrypt = null; - $this->demcrypt = null; - - if ($this->ecb) { - mcrypt_module_close($this->ecb); - $this->ecb = null; - } + $block_size = $this->block_size; + $buffer = &$this->enbuffer; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); + } + break; + case CRYPT_RIJNDAEL_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $block = $this->_encryptBlock($block ^ $xor); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_RIJNDAEL_MODE_CTR: + $xor = $this->encryptIV; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['encrypted'])) { + $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + } + $key = $this->_string_shift($buffer['encrypted'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1 + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } } + + return $ciphertext; } /** - * Setup the CRYPT_MODE_MCRYPT $engine + * Decrypts a message. * - * @see Crypt_Base::_setupMcrypt() - * @access private + * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until + * it is. + * + * @see Crypt_Rijndael::encrypt() + * @access public + * @param String $ciphertext */ - function _setupMcrypt() + function decrypt($ciphertext) { - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); - parent::_setupMcrypt(); + if ($this->changed) { + $this->_setup(); + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + if ($this->paddable) { + // 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) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); + } + + $block_size = $this->block_size; + $buffer = &$this->debuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); + } + break; + case CRYPT_RIJNDAEL_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $this->_decryptBlock($block) ^ $xor; + $xor = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_RIJNDAEL_MODE_CTR: + $xor = $this->decryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + } + $key = $this->_string_shift($buffer['ciphertext'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv); + $cb = substr($ciphertext, $i, $block_size); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $plaintext.= $iv ^ substr($ciphertext, $i); + $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); + $pos = $len; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } /** @@ -886,24 +1075,17 @@ function _setupMcrypt() */ function _encryptBlock($in) { - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[] = (int)$this->t0[$i]; - $t1[] = (int)$this->t1[$i]; - $t2[] = (int)$this->t2[$i]; - $t3[] = (int)$this->t3[$i]; - $sbox[] = (int)$this->sbox[$i]; - } - } - $state = array(); - $words = unpack('N*', $in); + $words = unpack('N*word', $in); - $c = $this->c; $w = $this->w; + $t0 = $this->t0; + $t1 = $this->t1; + $t2 = $this->t2; + $t3 = $this->t3; $Nb = $this->Nb; $Nr = $this->Nr; + $c = $this->c; // addRoundKey $i = -1; @@ -911,11 +1093,11 @@ function _encryptBlock($in) $state[] = $word ^ $w[0][++$i]; } - // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - - // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding + // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - + // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. - // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], + // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf @@ -942,10 +1124,7 @@ function _encryptBlock($in) // subWord for ($i = 0; $i < $Nb; ++$i) { - $state[$i] = $sbox[$state[$i] & 0x000000FF] | - ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | - ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | - ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); + $state[$i] = $this->_subWord($state[$i]); } // shiftRows + addRoundKey @@ -965,6 +1144,7 @@ function _encryptBlock($in) $l = ($l + 1) % $Nb; } + // 100% ugly switch/case code... but ~5% faster ("smart code" below commented out) switch ($Nb) { case 8: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); @@ -977,6 +1157,13 @@ function _encryptBlock($in) default: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); } + /* + $state = $temp; + + array_unshift($state, 'N*'); + + return call_user_func_array('pack', $state); + */ } /** @@ -988,24 +1175,17 @@ function _encryptBlock($in) */ function _decryptBlock($in) { - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[] = (int)$this->dt0[$i]; - $dt1[] = (int)$this->dt1[$i]; - $dt2[] = (int)$this->dt2[$i]; - $dt3[] = (int)$this->dt3[$i]; - $isbox[] = (int)$this->isbox[$i]; - } - } - $state = array(); - $words = unpack('N*', $in); + $words = unpack('N*word', $in); - $c = $this->c; $dw = $this->dw; + $dt0 = $this->dt0; + $dt1 = $this->dt1; + $dt2 = $this->dt2; + $dt3 = $this->dt3; $Nb = $this->Nb; $Nr = $this->Nr; + $c = $this->c; // addRoundKey $i = -1; @@ -1041,15 +1221,11 @@ function _decryptBlock($in) $l = $Nb - $c[3]; while ($i < $Nb) { - $word = ($state[$i] & 0xFF000000) | - ($state[$j] & 0x00FF0000) | - ($state[$k] & 0x0000FF00) | - ($state[$l] & 0x000000FF); - - $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | - ($isbox[$word >> 8 & 0x000000FF] << 8) | - ($isbox[$word >> 16 & 0x000000FF] << 16) | - ($isbox[$word >> 24 & 0x000000FF] << 24)); + $temp[$i] = $dw[0][$i] ^ + $this->_invSubWord(($state[$i] & 0xFF000000) | + ($state[$j] & 0x00FF0000) | + ($state[$k] & 0x0000FF00) | + ($state[$l] & 0x000000FF)); ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -1068,15 +1244,24 @@ function _decryptBlock($in) default: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); } + /* + $state = $temp; + + array_unshift($state, 'N*'); + + return call_user_func_array('pack', $state); + */ } /** - * Setup the key (expansion) + * Setup Rijndael + * + * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key + * key schedule. * - * @see Crypt_Base::_setupKey() * @access private */ - function _setupKey() + function _setup() { // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse @@ -1089,15 +1274,21 @@ function _setupKey() 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ); - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); - - if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) { - // already expanded - return; + if (!$this->explicit_key_length) { + // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits + $length = strlen($this->key) >> 2; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nk = $length; + $this->key_size = $length << 2; } - $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size); - $this->Nk = $this->key_size >> 2; + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0)); + // see Rijndael-ammended.pdf#page=44 $this->Nr = max($this->Nk, $this->Nb) + 6; @@ -1118,7 +1309,9 @@ function _setupKey() $this->c = array(0, 1, 3, 4); } - $w = array_values(unpack('N*words', $this->key)); + $key = $this->key; + + $w = array_values(unpack('N*words', $key)); $length = $this->Nb * ($this->Nr + 1); for ($i = $this->Nk; $i < $length; $i++) { @@ -1138,7 +1331,7 @@ function _setupKey() // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns // and generate the inverse key schedule. more specifically, - // according to (section 5.3.3), + // according to (section 5.3.3), // "The key expansion for the Inverse Cipher is defined as follows: // 1. Apply the Key Expansion. // 2. Apply InvMixColumn to all Round Keys except the first and the last one." @@ -1153,9 +1346,9 @@ function _setupKey() $j = 0; while ($j < $this->Nb) { $dw = $this->_subWord($this->w[$row][$j]); - $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ - $this->dt1[$dw >> 16 & 0x000000FF] ^ - $this->dt2[$dw >> 8 & 0x000000FF] ^ + $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ + $this->dt1[$dw >> 16 & 0x000000FF] ^ + $this->dt2[$dw >> 8 & 0x000000FF] ^ $this->dt3[$dw & 0x000000FF]; $j++; } @@ -1183,14 +1376,17 @@ function _setupKey() } $this->w = $w; $this->dw = $dw; + + $this->inline_crypt_setup(); } + + $this->changed = false; } /** * Performs S-Box substitutions * * @access private - * @param Integer $word */ function _subWord($word) { @@ -1203,37 +1399,217 @@ function _subWord($word) } /** - * Setup the performance-optimized function for de/encrypt() + * Performs inverse S-Box substitutions * - * @see Crypt_Base::_setupInlineCrypt() * @access private */ - function _setupInlineCrypt() + function _invSubWord($word) { - // Note: _setupInlineCrypt() will be called only if $this->changed === true + $isbox = $this->isbox; + + return $isbox[$word & 0x000000FF] | + ($isbox[$word >> 8 & 0x000000FF] << 8) | + ($isbox[$word >> 16 & 0x000000FF] << 16) | + ($isbox[$word >> 24 & 0x000000FF] << 24); + } + + /** + * Pad "packets". + * + * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple + * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to + * pad the input so that it is of the proper length. + * + * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, + * 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_Rijndael::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Rijndael::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. + * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to + * chr($block_size - (strlen($text) % $block_size) + * + * 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_Rijndael::_unpad() + * @access private + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % $this->block_size == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); + $this->padding = true; + } + } + + $pad = $this->block_size - ($length % $this->block_size); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string. + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Rijndael::_pad() + * @access private + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > $this->block_size) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->encrypt(substr($plaintext, 16, 16)); + * + * + * echo $rijndael->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); + * + * + * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); + * + * + * 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_Rijndael() 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_Rijndael::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + $this->continuousBuffer = false; + $this->encryptIV = $this->iv; + $this->decryptIV = $this->iv; + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } + + /** + * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt + * + * @see Crypt_Rijndael::encrypt() + * @see Crypt_Rijndael::decrypt() + * @access private + */ + function inline_crypt_setup() + { + // Note: inline_crypt_setup() will be called only if $this->changed === true // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt(). // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible. - $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); + $lambda_functions =& Crypt_Rijndael::get_lambda_functions(); + $block_size = $this->block_size; + $mode = $this->mode; - // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. - // For memory reason we limit those ultra-optimized functions. + // The first 5 generated $lambda_functions will use the key-words hardcoded for better performance. + // For memory reason we limit those ultra-optimized function code to 5. // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. - if (count($lambda_functions) < 10) { + if (count($lambda_functions) < 5) { $w = $this->w; $dw = $this->dw; - $init_encrypt = ''; - $init_decrypt = ''; + $init_encryptBlock = ''; + $init_decryptBlock = ''; } else { for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { - $w[] = '$w[' . $i . ']'; - $dw[] = '$dw[' . $i . ']'; + $w[] = '$w_'.$i; + $dw[] = '$dw_'.$i; } - $init_encrypt = '$w = $self->w;'; - $init_decrypt = '$dw = $self->dw;'; + $init_encryptBlock = 'extract($self->w, EXTR_PREFIX_ALL, "w");'; + $init_decryptBlock = 'extract($self->dw, EXTR_PREFIX_ALL, "dw");'; } - $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); + $code_hash = md5("$mode, $block_size, " . implode(',', $w)); if (!isset($lambda_functions[$code_hash])) { $Nr = $this->Nr; @@ -1241,34 +1617,28 @@ function _setupInlineCrypt() $c = $this->c; // Generating encrypt code: - $init_encrypt.= ' - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[$i] = (int)$self->t0[$i]; - $t1[$i] = (int)$self->t1[$i]; - $t2[$i] = (int)$self->t2[$i]; - $t3[$i] = (int)$self->t3[$i]; - $sbox[$i] = (int)$self->sbox[$i]; - } - } - '; + $init_encryptBlock.= ' + $t0 = $self->t0; + $t1 = $self->t1; + $t2 = $self->t2; + $t3 = $self->t3; + $sbox = $self->sbox;'; $s = 'e'; $e = 's'; $wc = $Nb - 1; // Preround: addRoundKey - $encrypt_block = '$in = unpack("N*", $in);'."\n"; + $_encryptBlock = '$in = unpack("N*", $in);'."\n"; for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; + $_encryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; } // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey for ($round = 1; $round < $Nr; ++$round) { list($s, $e) = array($e, $s); for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= + $_encryptBlock.= '$'.$e.$i.' = $t0[($'.$s.$i .' >> 24) & 0xff] ^ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ @@ -1280,53 +1650,47 @@ function _setupInlineCrypt() // Finalround: subWord + shiftRows + addRoundKey for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= + $_encryptBlock.= '$'.$e.$i.' = $sbox[ $'.$e.$i.' & 0xff] | ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; } - $encrypt_block .= '$in = pack("N*"'."\n"; + $_encryptBlock .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= ', + $_encryptBlock.= ', ($'.$e.$i .' & 0xFF000000) ^ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ '.$w[$i]."\n"; } - $encrypt_block .= ');'; + $_encryptBlock .= ');'; // Generating decrypt code: - $init_decrypt.= ' - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[$i] = (int)$self->dt0[$i]; - $dt1[$i] = (int)$self->dt1[$i]; - $dt2[$i] = (int)$self->dt2[$i]; - $dt3[$i] = (int)$self->dt3[$i]; - $isbox[$i] = (int)$self->isbox[$i]; - } - } - '; + $init_decryptBlock.= ' + $dt0 = $self->dt0; + $dt1 = $self->dt1; + $dt2 = $self->dt2; + $dt3 = $self->dt3; + $isbox = $self->isbox;'; $s = 'e'; $e = 's'; $wc = $Nb - 1; // Preround: addRoundKey - $decrypt_block = '$in = unpack("N*", $in);'."\n"; + $_decryptBlock = '$in = unpack("N*", $in);'."\n"; for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; + $_decryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; } // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey for ($round = 1; $round < $Nr; ++$round) { list($s, $e) = array($e, $s); for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= + $_decryptBlock.= '$'.$e.$i.' = $dt0[($'.$s.$i .' >> 24) & 0xff] ^ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ @@ -1338,36 +1702,360 @@ function _setupInlineCrypt() // Finalround: subWord + shiftRows + addRoundKey for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= + $_decryptBlock.= '$'.$e.$i.' = $isbox[ $'.$e.$i.' & 0xff] | ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; } - $decrypt_block .= '$in = pack("N*"'."\n"; + $_decryptBlock .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= ', + $_decryptBlock.= ', ($'.$e.$i. ' & 0xFF000000) ^ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ '.$dw[$i]."\n"; } - $decrypt_block .= ');'; - - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => '', - 'init_encrypt' => $init_encrypt, - 'init_decrypt' => $init_decrypt, - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); + $_decryptBlock .= ');'; + + // Generating mode of operation code: + switch ($mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + $encrypt = $init_encryptBlock . ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_encryptBlock.' + $ciphertext.= $in; + } + + return $ciphertext; + '; + + $decrypt = $init_decryptBlock . ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_RIJNDAEL_MODE_CBC: + $encrypt = $init_encryptBlock . ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + $in = $self->encryptIV; + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.') ^ $in; + '.$_encryptBlock.' + $ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $ciphertext; + '; + + $decrypt = $init_decryptBlock . ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + $iv = $self->decryptIV; + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $block = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in ^ $iv; + $iv = $block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $iv; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_RIJNDAEL_MODE_CTR: + $encrypt = $init_encryptBlock . ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["encrypted"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["encrypted"])) { + $in = $self->_generate_xor('.$block_size.', $xor); + '.$_encryptBlock.' + $buffer["encrypted"].= $in; + } + $key = $self->_string_shift($buffer["encrypted"], '.$block_size.'); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor('.$block_size.', $xor); + '.$_encryptBlock.' + $key = $in; + $ciphertext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"]; + } + } + + return $ciphertext; + '; + + $decrypt = $init_encryptBlock . ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["ciphertext"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["ciphertext"])) { + $in = $self->_generate_xor('.$block_size.', $xor); + '.$_encryptBlock.' + $buffer["ciphertext"].= $in; + } + $key = $self->_string_shift($buffer["ciphertext"], '.$block_size.'); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor('.$block_size.', $xor); + '.$_encryptBlock.' + $key = $in; + $plaintext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"]; + } + } + + return $plaintext; + '; + break; + case CRYPT_RIJNDAEL_MODE_CFB: + $encrypt = $init_encryptBlock . ' + $ciphertext = ""; + $buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $iv = &$self->encryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->encryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.'; + $iv = $in ^ substr($text, $i, '.$block_size.'); + $ciphertext.= $iv; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $block = $iv ^ substr($text, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + '; + + $decrypt = $init_encryptBlock . ' + $plaintext = ""; + $buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $iv = &$self->decryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->decryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $cb = substr($text, $i, '.$block_size.'); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $plaintext.= $iv ^ substr($text, $i); + $iv = substr_replace($iv, substr($text, $i), 0, $len); + $pos = $len; + } + + return $plaintext; + '; + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $encrypt = $init_encryptBlock . ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"], '.$block_size.'); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $ciphertext; + '; + + $decrypt = $init_encryptBlock . ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"], '.$block_size.'); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $plaintext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $plaintext; + '; + break; + } + $lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }'); } $this->inline_crypt = $lambda_functions[$code_hash]; } + + /** + * Holds the lambda_functions table (classwide) + * + * @see Crypt_Rijndael::inline_crypt_setup() + * @return Array + * @access private + */ + function &get_lambda_functions() + { + static $functions = array(); + return $functions; + } } // vim: ts=4:sw=4:et: diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/TripleDES.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/TripleDES.php index 4030c6c9fb..c27c10ac10 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/TripleDES.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/TripleDES.php @@ -33,10 +33,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -80,82 +80,12 @@ * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_TripleDES + * @package Crypt_TerraDES */ class Crypt_TripleDES extends Crypt_DES { - /** - * The default password key_size used by setPassword() - * - * @see Crypt_DES::password_key_size - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 24; - - /** - * The default salt used by setPassword() - * - * @see Crypt_Base::password_default_salt - * @see Crypt_Base::setPassword() - * @var String - * @access private - */ - var $password_default_salt = 'phpseclib'; - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_DES::const_namespace - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'DES'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_DES::cipher_name_mcrypt - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'tripledes'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 750; - - /** - * max possible size of $key - * - * @see Crypt_TripleDES::setKey() - * @see Crypt_DES::setKey() - * @var String - * @access private - */ - var $key_size_max = 24; - - /** - * Internal flag whether using CRYPT_DES_MODE_3CBC or not - * - * @var Boolean - * @access private - */ - var $mode_3cbc; - /** * The Crypt_DES objects * - * Used only if $mode_3cbc === true - * * @var Array * @access private */ @@ -164,73 +94,99 @@ class Crypt_TripleDES extends Crypt_DES { /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. + * 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. * - * $mode could be: - * - * - CRYPT_DES_MODE_ECB - * - * - CRYPT_DES_MODE_CBC - * - * - CRYPT_DES_MODE_CTR - * - * - CRYPT_DES_MODE_CFB - * - * - CRYPT_DES_MODE_OFB - * - * - CRYPT_DES_MODE_3CBC - * - * If not explictly set, CRYPT_DES_MODE_CBC will be used. - * - * @see Crypt_DES::Crypt_DES() - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode + * @return Crypt_TripleDES * @access public */ function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) { - switch ($mode) { - // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC - // and additional flag us internally as 3CBC - case CRYPT_DES_MODE_3CBC: - parent::Crypt_DES(CRYPT_DES_MODE_CBC); - $this->mode_3cbc = true; - - // This three $des'es will do the 3CBC work (if $key > 64bits) + if ( !defined('CRYPT_DES_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()): + define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); + break; + default: + define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); + } + } + + if ( $mode == CRYPT_DES_MODE_3CBC ) { + $this->mode = CRYPT_DES_MODE_3CBC; + $this->des = array( + new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_DES_MODE_CBC) + ); + $this->paddable = true; + + // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects + $this->des[0]->disablePadding(); + $this->des[1]->disablePadding(); + $this->des[2]->disablePadding(); + + return; + } + + switch ( CRYPT_DES_MODE ) { + case CRYPT_DES_MODE_MCRYPT: + switch ($mode) { + case CRYPT_DES_MODE_ECB: + $this->paddable = true; + $this->mode = MCRYPT_MODE_ECB; + break; + case CRYPT_DES_MODE_CTR: + $this->mode = 'ctr'; + break; + case CRYPT_DES_MODE_CFB: + $this->mode = 'ncfb'; + $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); + break; + case CRYPT_DES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_DES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); + $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); + + break; + default: $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_DES_MODE_ECB), + new Crypt_DES(CRYPT_DES_MODE_ECB), + new Crypt_DES(CRYPT_DES_MODE_ECB) ); - + // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects $this->des[0]->disablePadding(); $this->des[1]->disablePadding(); $this->des[2]->disablePadding(); - break; - // If not 3CBC, we init as usual - default: - parent::Crypt_DES($mode); - } - } - /** - * 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. - * - * @see Crypt_Base::setIV() - * @access public - * @param String $iv - */ - function setIV($iv) - { - parent::setIV($iv); - if ($this->mode_3cbc) { - $this->des[0]->setIV($iv); - $this->des[1]->setIV($iv); - $this->des[2]->setIV($iv); + switch ($mode) { + case CRYPT_DES_MODE_ECB: + case CRYPT_DES_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_DES_MODE_CTR: + case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_DES_MODE_CBC; + } + if (function_exists('create_function') && is_callable('create_function')) { + $this->inline_crypt_setup(3); + $this->use_inline_crypt = true; + } } } @@ -242,77 +198,571 @@ function setIV($iv) * * 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 null bytes. + * If the key is not explicitly set, it'll be assumed to be all zero's. * * @access public - * @see Crypt_DES::setKey() - * @see Crypt_Base::setKey() * @param String $key */ function setKey($key) { $length = strlen($key); if ($length > 8) { - $key = str_pad(substr($key, 0, 24), 24, chr(0)); + $key = str_pad($key, 24, chr(0)); // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: // http://php.net/function.mcrypt-encrypt#47973 //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); } else { $key = str_pad($key, 8, chr(0)); } - parent::setKey($key); - - // And in case of CRYPT_DES_MODE_3CBC: - // if key <= 64bits we not need the 3 $des to work, - // because we will then act as regular DES-CBC with just a <= 64bit key. - // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des. - if ($this->mode_3cbc && $length > 8) { - $this->des[0]->setKey(substr($key, 0, 8)); - $this->des[1]->setKey(substr($key, 8, 8)); - $this->des[2]->setKey(substr($key, 16, 8)); + $this->key = $key; + switch (true) { + case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL: + case $this->mode == CRYPT_DES_MODE_3CBC: + $this->des[0]->setKey(substr($key, 0, 8)); + $this->des[1]->setKey(substr($key, 8, 8)); + $this->des[2]->setKey(substr($key, 16, 8)); + + // Merge the three DES-1-dim-key-arrays for 3DES-inline-en/decrypting + if ($this->use_inline_crypt && $this->mode != CRYPT_DES_MODE_3CBC) { + $this->keys = array( + CRYPT_DES_ENCRYPT_1DIM => array_merge( + $this->des[0]->keys[CRYPT_DES_ENCRYPT_1DIM], + $this->des[1]->keys[CRYPT_DES_DECRYPT_1DIM], + $this->des[2]->keys[CRYPT_DES_ENCRYPT_1DIM] + ), + CRYPT_DES_DECRYPT_1DIM => array_merge( + $this->des[2]->keys[CRYPT_DES_DECRYPT_1DIM], + $this->des[1]->keys[CRYPT_DES_ENCRYPT_1DIM], + $this->des[0]->keys[CRYPT_DES_DECRYPT_1DIM] + ), + ); + } + } + $this->enchanged = $this->dechanged = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $method + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < 24) { // $dkLen == 24 + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey($key); + } + + /** + * 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)); + if ($this->mode == CRYPT_DES_MODE_3CBC) { + $this->des[0]->setIV($iv); + $this->des[1]->setIV($iv); + $this->des[2]->setIV($iv); } + $this->enchanged = $this->dechanged = true; } /** * Encrypts a message. * - * @see Crypt_Base::encrypt() * @access public * @param String $plaintext - * @return String $cipertext */ function encrypt($plaintext) { - // parent::en/decrypt() is able to do all the work for all modes and keylengths, - // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } // if the key is smaller then 8, do what we'd normally do - if ($this->mode_3cbc && strlen($this->key) > 8) { - return $this->des[2]->encrypt( - $this->des[1]->decrypt( - $this->des[0]->encrypt($this->_pad($plaintext)))); + if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { + $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext))); + + return $ciphertext; + } + + if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + } + $this->enchanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= 8) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); + $iv = substr($ciphertext, -8); + $i = strlen($ciphertext); + $len%= 8; + } else { + while ($len >= 8) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); + $ciphertext.= $iv; + $len-= 8; + $i+= 8; + } + } + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if (strlen($this->key) <= 8) { + $this->des[0]->mode = $this->mode; + + return $this->des[0]->encrypt($plaintext); + } + + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + + $des = $this->des; + + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_DES_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something. + // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that + // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make + // encryption and decryption take more time, per this: + // + // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html + $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); + $ciphertext.= $block; + } + break; + case CRYPT_DES_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8) ^ $xor; + $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_DES_MODE_CTR: + $xor = $this->encryptIV; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + if (strlen($block) > strlen($buffer['encrypted'])) { + $key = $this->_generate_xor($xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $buffer['encrypted'].= $key; + } + $key = $this->_string_shift($buffer['encrypted']); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $key = $this->_generate_xor($xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (strlen($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); + $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT); + $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); + + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $ciphertext.= $iv; + } + + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor']); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $ciphertext.= substr($plaintext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } } - return parent::encrypt($plaintext); + return $ciphertext; } /** * Decrypts a message. * - * @see Crypt_Base::decrypt() * @access public * @param String $ciphertext - * @return String $plaintext */ function decrypt($ciphertext) { - if ($this->mode_3cbc && strlen($this->key) > 8) { - return $this->_unpad($this->des[0]->decrypt( - $this->des[1]->encrypt( - $this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0"))))); + if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { + $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext))); + + return $this->_unpad($plaintext); + } + + if ($this->paddable) { + // 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->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + } + $this->dechanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 8 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= 8) { + $cb = substr($ciphertext, $i, $len - $len % 8); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -8); + $len%= 8; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $cb = substr($ciphertext, -$len); + $plaintext.= $iv ^ $cb; + $iv = substr_replace($iv, $cb, 0, $len); + $pos = $len; + } + return $plaintext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if (strlen($this->key) <= 8) { + $this->des[0]->mode = $this->mode; + $plaintext = $this->des[0]->decrypt($ciphertext); + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + $des = $this->des; + + $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_DES_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); + $plaintext.= $block; + } + break; + case CRYPT_DES_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $orig = $block = substr($ciphertext, $i, 8); + $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); + $plaintext.= $block ^ $xor; + $xor = $orig; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_DES_MODE_CTR: + $xor = $this->decryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $key = $this->_generate_xor($xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $buffer['ciphertext'].= $key; + } + $key = $this->_string_shift($buffer['ciphertext']); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $key = $this->_generate_xor($xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (strlen($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) != 8) { + $block = $this->decryptIV; + } else { + $block = $buffer['ciphertext']; + $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + } else { + $plaintext = ''; + $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != 8) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == 8) { + $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['xor'].= $xor; + } + $key = $this->_string_shift($buffer['xor']); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $plaintext.= substr($ciphertext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) & 7) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } } - return parent::decrypt($ciphertext); + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } /** @@ -349,14 +799,13 @@ function decrypt($ciphertext) * 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_Base::enableContinuousBuffer() * @see Crypt_TripleDES::disableContinuousBuffer() * @access public */ function enableContinuousBuffer() { - parent::enableContinuousBuffer(); - if ($this->mode_3cbc) { + $this->continuousBuffer = true; + if ($this->mode == CRYPT_DES_MODE_3CBC) { $this->des[0]->enableContinuousBuffer(); $this->des[1]->enableContinuousBuffer(); $this->des[2]->enableContinuousBuffer(); @@ -368,54 +817,25 @@ function enableContinuousBuffer() * * The default behavior. * - * @see Crypt_Base::disableContinuousBuffer() * @see Crypt_TripleDES::enableContinuousBuffer() * @access public */ function disableContinuousBuffer() { - parent::disableContinuousBuffer(); - if ($this->mode_3cbc) { + $this->continuousBuffer = false; + $this->encryptIV = $this->iv; + $this->decryptIV = $this->iv; + $this->enchanged = true; + $this->dechanged = true; + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + if ($this->mode == CRYPT_DES_MODE_3CBC) { $this->des[0]->disableContinuousBuffer(); $this->des[1]->disableContinuousBuffer(); $this->des[2]->disableContinuousBuffer(); } } - - /** - * Creates the key schedule - * - * @see Crypt_DES::_setupKey() - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - switch (true) { - // if $key <= 64bits we configure our internal pure-php cipher engine - // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same. - case strlen($this->key) <= 8: - $this->des_rounds = 1; - break; - - // otherwise, if $key > 64bits, we configure our engine to work as 3DES. - default: - $this->des_rounds = 3; - - // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately. - if ($this->mode_3cbc) { - $this->des[0]->_setupKey(); - $this->des[1]->_setupKey(); - $this->des[2]->_setupKey(); - - // because $des[0-2] will, now, do all the work we can return here - // not need unnecessary stress parent::_setupKey() with our, now unused, $key. - return; - } - } - // setup our key - parent::_setupKey(); - } } // vim: ts=4:sw=4:et: diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Twofish.php b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Twofish.php index 3e55e5d35c..c6153a9a14 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Twofish.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Crypt/Twofish.php @@ -17,13 +17,13 @@ * setKey('12345678901234567890123456789012'); + * $Twofish->setKey('12345678901234567890123456789012'); * * $plaintext = str_repeat('a', 1024); * - * echo $twofish->decrypt($twofish->encrypt($plaintext)); + * echo $Twofish->decrypt($Twofish->encrypt($plaintext)); * ?> * * @@ -55,15 +55,6 @@ * @link http://phpseclib.sourceforge.net */ -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - require_once 'Base.php'; -} - /**#@+ * @access public * @see Crypt_Twofish::encrypt() @@ -76,31 +67,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR); +define('CRYPT_TWOFISH_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_TWOFISH_MODE_ECB', CRYPT_MODE_ECB); +define('CRYPT_TWOFISH_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_TWOFISH_MODE_CBC', CRYPT_MODE_CBC); +define('CRYPT_TWOFISH_MODE_CBC', 2); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB); +define('CRYPT_TWOFISH_MODE_CFB', 3); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); +define('CRYPT_TWOFISH_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -110,11 +101,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +define('CRYPT_TWOFISH_MODE_INTERNAL', 1); /** * Toggles the mcrypt implementation */ -define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +define('CRYPT_TWOFISH_MODE_MCRYPT', 2); /**#@-*/ /** @@ -126,33 +117,158 @@ * @access public * @package Crypt_Twofish */ -class Crypt_Twofish extends Crypt_Base { +class Crypt_Twofish { + /** + * The Key as String + * + * @see Crypt_Twofish::setKey() + * @var Array + * @access private + */ + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + /** + * The Encryption Mode + * + * @see Crypt_Twofish::Crypt_Twofish() + * @var Integer + * @access private + */ + var $mode; + + /** + * Continuous Buffer status + * + * @see Crypt_Twofish::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Padding status + * + * @see Crypt_Twofish::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + /** - * The namespace used by the cipher for its constants. + * The Initialization Vector * - * @see Crypt_Base::const_namespace + * @see Crypt_Twofish::setIV() * @var String * @access private */ - var $const_namespace = 'TWOFISH'; + var $iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /** - * The mcrypt specific name of the cipher + * A "sliding" Initialization Vector * - * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_Twofish::enableContinuousBuffer() * @var String * @access private */ - var $cipher_name_mcrypt = 'twofish'; + var $encryptIV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /** - * Optimizing value while CFB-encrypting + * A "sliding" Initialization Vector * - * @see Crypt_Base::cfb_init_len - * @var Integer + * @see Crypt_Twofish::enableContinuousBuffer() + * @var String * @access private */ - var $cfb_init_len = 800; + var $decryptIV = "\0\0\0\0\0\0\0\0\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_Twofish::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_Twofish::decrypt() + * @var String + * @access private + */ + var $demcrypt; + + /** + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Twofish::Crypt_Twofish() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Twofish::encrypt() + * @var Array + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Twofish::decrypt() + * @var Array + * @access private + */ + var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_Twofish::encrypt() + * @see Crypt_Twofish::decrypt() + * @var String + * @access private + */ + var $ecb; + + /** + * Performance-optimized callback function for en/decrypt() + * + * @var Callback + * @access private + */ + var $inline_crypt; /** * Q-Table @@ -440,40 +556,71 @@ class Crypt_Twofish extends Crypt_Base { */ var $S3 = array(); - /** - * Holds the last used key - * - * @var Array - * @access private - */ - var $kl; - /** * Default Constructor. * * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_TWOFISH_MODE_ECB - * - * - CRYPT_TWOFISH_MODE_CBC - * - * - CRYPT_TWOFISH_MODE_CTR - * - * - CRYPT_TWOFISH_MODE_CFB - * - * - CRYPT_TWOFISH_MODE_OFB - * * If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used. * - * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode * @access public */ function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC) { - parent::Crypt_Base($mode); + if ( !defined('CRYPT_TWOFISH_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('twofish', mcrypt_list_algorithms()): + define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_MCRYPT); + break; + default: + define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_INTERNAL); + } + } + + switch ( CRYPT_TWOFISH_MODE ) { + case CRYPT_TWOFISH_MODE_MCRYPT: + switch ($mode) { + case CRYPT_TWOFISH_MODE_ECB: + $this->paddable = true; + $this->mode = MCRYPT_MODE_ECB; + break; + case CRYPT_TWOFISH_MODE_CTR: + $this->mode = 'ctr'; + break; + case CRYPT_TWOFISH_MODE_CFB: + $this->mode = 'ncfb'; + $this->ecb = mcrypt_module_open(MCRYPT_TWOFISH, '', MCRYPT_MODE_ECB, ''); + break; + case CRYPT_TWOFISH_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_TWOFISH_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + $this->enmcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, ''); + $this->demcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, ''); + + break; + default: + switch ($mode) { + case CRYPT_TWOFISH_MODE_ECB: + case CRYPT_TWOFISH_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_TWOFISH_MODE_CTR: + case CRYPT_TWOFISH_MODE_CFB: + case CRYPT_TWOFISH_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_TWOFISH_MODE_CBC; + } + $this->inline_crypt_setup(); + } } /** @@ -486,7 +633,6 @@ function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC) * If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes. * * @access public - * @see Crypt_Base::setKey() * @param String $key */ function setKey($key) @@ -494,37 +640,29 @@ function setKey($key) $keylength = strlen($key); switch (true) { case $keylength <= 16: - $key = str_pad($key, 16, "\0"); + $key.= str_repeat("\0", 16 - $keylength); break; case $keylength <= 24: - $key = str_pad($key, 24, "\0"); + $key.= str_repeat("\0", 24 - $keylength); break; - case $keylength < 32: - $key = str_pad($key, 32, "\0"); + case $keylength <= 32: + $key.= str_repeat("\0", 32 - $keylength); break; - case $keylength > 32: + default: $key = substr($key, 0, 32); } - parent::setKey($key); - } + $this->key = $key; - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - if (isset($this->kl['key']) && $this->key === $this->kl['key']) { - // already expanded + $this->enchanged = true; + $this->dechanged = true; + + if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) { return; } - $this->kl = array('key' => $this->key); /* Key expanding and generating the key-depended s-boxes */ - $le_longs = unpack('V*', $this->key); - $key = unpack('C*', $this->key); + $le_longs = unpack('V*', $key); + $key = unpack('C*', $key); $m0 = $this->m0; $m1 = $this->m1; $m2 = $this->m2; @@ -536,8 +674,8 @@ function _setupKey() switch (strlen($this->key)) { case 16: - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]); + list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[1], $le_longs[2]); + list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[3], $le_longs[4]); for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) { $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^ @@ -559,9 +697,9 @@ function _setupKey() } break; case 24: - list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]); + list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[1], $le_longs[2]); + list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[3], $le_longs[4]); + list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[5], $le_longs[6]); for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ @@ -583,10 +721,10 @@ function _setupKey() } break; default: // 32 - list ($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]); - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]); + list ($sf, $se, $sd, $sc) = $this->mds_rem($le_longs[1], $le_longs[2]); + list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[3], $le_longs[4]); + list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[5], $le_longs[6]); + list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[7], $le_longs[8]); for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ @@ -616,14 +754,425 @@ function _setupKey() } /** - * _mdsrem function using by the twofish cipher algorithm + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA2 use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib/salt'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < 32) { + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; ++$j) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey($key); + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_TWOFISH_MODE_ECB is being used. If not explictly set, it'll be assumed + * to be all null bytes. + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 16), 16, chr(0)); + $this->enchanged = true; + $this->dechanged = true; + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with up to 16 additional bytes. Other Twofish 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_Twofish::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) { + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + $this->enchanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 16 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= 16) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16)); + $iv = substr($ciphertext, -16); + $len%= 16; + } else { + while ($len >= 16) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16); + $ciphertext.= $iv; + $len-= 16; + $i+= 16; + } + } + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if (empty($this->K)) { + $this->setKey($this->key); + } + + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $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_Twofish::encrypt() + * @access public + * @param String $ciphertext + */ + function decrypt($ciphertext) + { + if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) { + if ($this->paddable) { + // 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) + (16 - strlen($ciphertext) % 16) % 16, chr(0)); + } + + if ($this->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + if ($this->mode == 'ncfb') { + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + $this->dechanged = false; + } + + if ($this->mode != 'ncfb' || !$this->continuousBuffer) { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = 16 - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= 16) { + $cb = substr($ciphertext, $i, $len - $len % 16); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -16); + $len%= 16; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + return $plaintext; + } + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if (empty($this->K)) { + $this->setKey($this->key); + } + + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * @see Crypt_Twofish::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_Twofish::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + $this->continuousBuffer = false; + $this->encryptIV = $this->iv; + $this->decryptIV = $this->iv; + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); + mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); + } + } + + /** + * Pad "packets". + * + * Twofish works by encrypting 16 bytes at a time. If you ever need to encrypt or decrypt something that's not + * a multiple of 16, 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_Twofish::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Twofish::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 (16). + * + * 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_Twofish::_unpad() + * @access private + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % 16 == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size (16)"); + $this->padding = true; + } + } + + $pad = 16 - ($length % 16); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Twofish::_pad() + * @access private + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > 16) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @return String + * @access private + */ + function _string_shift(&$string) + { + $substr = substr($string, 0, 16); + $string = substr($string, 16); + return $substr; + } + + /** + * 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_Twofish::decrypt() + * @see Crypt_Twofish::encrypt() + * @access public + * @param String $iv + */ + function _generate_xor(&$iv) + { + $xor = $iv; + for ($j = 4; $j <= 16; $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; + } + + /** + * mds_rem function using by the twofish cipher algorithm * * @access private * @param String $A * @param String $B * @return Array */ - function _mdsrem($A, $B) + function mds_rem($A, $B) { // No gain by unrolling this loop. for ($i = 0; $i < 8; ++$i) { @@ -662,176 +1211,36 @@ function _mdsrem($A, $B) } /** - * Encrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $S0 = $this->S0; - $S1 = $this->S1; - $S2 = $this->S2; - $S3 = $this->S3; - $K = $this->K; - - $in = unpack("V4", $in); - $R0 = $K[0] ^ $in[1]; - $R1 = $K[1] ^ $in[2]; - $R2 = $K[2] ^ $in[3]; - $R3 = $K[3] ^ $in[4]; - - $ki = 7; - while ($ki < 39) { - $t0 = $S0[ $R0 & 0xff] ^ - $S1[($R0 >> 8) & 0xff] ^ - $S2[($R0 >> 16) & 0xff] ^ - $S3[($R0 >> 24) & 0xff]; - $t1 = $S0[($R1 >> 24) & 0xff] ^ - $S1[ $R1 & 0xff] ^ - $S2[($R1 >> 8) & 0xff] ^ - $S3[($R1 >> 16) & 0xff]; - $R2^= $t0 + $t1 + $K[++$ki]; - $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); - $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); - - $t0 = $S0[ $R2 & 0xff] ^ - $S1[($R2 >> 8) & 0xff] ^ - $S2[($R2 >> 16) & 0xff] ^ - $S3[($R2 >> 24) & 0xff]; - $t1 = $S0[($R3 >> 24) & 0xff] ^ - $S1[ $R3 & 0xff] ^ - $S2[($R3 >> 8) & 0xff] ^ - $S3[($R3 >> 16) & 0xff]; - $R0^= ($t0 + $t1 + $K[++$ki]); - $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); - $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); - } - - return pack("V4", $K[4] ^ $R2, - $K[5] ^ $R3, - $K[6] ^ $R0, - $K[7] ^ $R1); - } - - /** - * Decrypts a block + * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt * * @access private - * @param String $in - * @return String */ - function _decryptBlock($in) + function inline_crypt_setup() { - $S0 = $this->S0; - $S1 = $this->S1; - $S2 = $this->S2; - $S3 = $this->S3; - $K = $this->K; - - $in = unpack("V4", $in); - $R0 = $K[4] ^ $in[1]; - $R1 = $K[5] ^ $in[2]; - $R2 = $K[6] ^ $in[3]; - $R3 = $K[7] ^ $in[4]; - - $ki = 40; - while ($ki > 8) { - $t0 = $S0[$R0 & 0xff] ^ - $S1[$R0 >> 8 & 0xff] ^ - $S2[$R0 >> 16 & 0xff] ^ - $S3[$R0 >> 24 & 0xff]; - $t1 = $S0[$R1 >> 24 & 0xff] ^ - $S1[$R1 & 0xff] ^ - $S2[$R1 >> 8 & 0xff] ^ - $S3[$R1 >> 16 & 0xff]; - $R3^= $t0 + ($t1 << 1) + $K[--$ki]; - $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; - $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]); - - $t0 = $S0[$R2 & 0xff] ^ - $S1[$R2 >> 8 & 0xff] ^ - $S2[$R2 >> 16 & 0xff] ^ - $S3[$R2 >> 24 & 0xff]; - $t1 = $S0[$R3 >> 24 & 0xff] ^ - $S1[$R3 & 0xff] ^ - $S2[$R3 >> 8 & 0xff] ^ - $S3[$R3 >> 16 & 0xff]; - $R1^= $t0 + ($t1 << 1) + $K[--$ki]; - $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; - $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]); - } - - return pack("V4", $K[0] ^ $R2, - $K[1] ^ $R3, - $K[2] ^ $R0, - $K[3] ^ $R1); - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - $lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); - - // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Twofish, {$this->mode}"; - } + $lambda_functions =& Crypt_Twofish::get_lambda_functions(); + $block_size = 16; + $mode = $this->mode; + $code_hash = "$mode"; if (!isset($lambda_functions[$code_hash])) { - switch (true) { - case $gen_hi_opt_code: - $K = $this->K; - - $init_crypt = ' - static $S0, $S1, $S2, $S3; - if (!$S0) { - for ($i = 0; $i < 256; ++$i) { - $S0[] = (int)$self->S0[$i]; - $S1[] = (int)$self->S1[$i]; - $S2[] = (int)$self->S2[$i]; - $S3[] = (int)$self->S3[$i]; - } - } - '; - break; - default: - $K = array(); - for ($i = 0; $i < 40; ++$i) { - $K[] = '$K_' . $i; - } - - $init_crypt = ' - $S0 = $self->S0; - $S1 = $self->S1; - $S2 = $self->S2; - $S3 = $self->S3; - list(' . implode(',', $K) . ') = $self->K; - '; - } + $init_cryptBlock = ' + $S0 = $self->S0; + $S1 = $self->S1; + $S2 = $self->S2; + $S3 = $self->S3; + extract($self->K, EXTR_PREFIX_ALL, "K"); + '; // Generating encrypt code: - $encrypt_block = ' + $_encryptBlock = ' $in = unpack("V4", $in); - $R0 = '.$K[0].' ^ $in[1]; - $R1 = '.$K[1].' ^ $in[2]; - $R2 = '.$K[2].' ^ $in[3]; - $R3 = '.$K[3].' ^ $in[4]; + $R0 = $K_0 ^ $in[1]; + $R1 = $K_1 ^ $in[2]; + $R2 = $K_2 ^ $in[3]; + $R3 = $K_3 ^ $in[4]; '; for ($ki = 7, $i = 0; $i < 8; ++$i) { - $encrypt_block.= ' + $_encryptBlock.= ' $t0 = $S0[ $R0 & 0xff] ^ $S1[($R0 >> 8) & 0xff] ^ $S2[($R0 >> 16) & 0xff] ^ @@ -840,9 +1249,9 @@ function _setupInlineCrypt() $S1[ $R1 & 0xff] ^ $S2[($R1 >> 8) & 0xff] ^ $S3[($R1 >> 16) & 0xff]; - $R2^= ($t0 + $t1 + '.$K[++$ki].'); + $R2^= ($t0 + $t1 + $K_'.(++$ki).'); $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); - $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); + $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).'); $t0 = $S0[ $R2 & 0xff] ^ $S1[($R2 >> 8) & 0xff] ^ @@ -852,28 +1261,28 @@ function _setupInlineCrypt() $S1[ $R3 & 0xff] ^ $S2[($R3 >> 8) & 0xff] ^ $S3[($R3 >> 16) & 0xff]; - $R0^= ($t0 + $t1 + '.$K[++$ki].'); + $R0^= ($t0 + $t1 + $K_'.(++$ki).'); $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); - $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); + $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).'); '; } - $encrypt_block.= ' - $in = pack("V4", '.$K[4].' ^ $R2, - '.$K[5].' ^ $R3, - '.$K[6].' ^ $R0, - '.$K[7].' ^ $R1); + $_encryptBlock.= ' + $in = pack("V4", $K_4 ^ $R2, + $K_5 ^ $R3, + $K_6 ^ $R0, + $K_7 ^ $R1); '; // Generating decrypt code: - $decrypt_block = ' + $_decryptBlock = ' $in = unpack("V4", $in); - $R0 = '.$K[4].' ^ $in[1]; - $R1 = '.$K[5].' ^ $in[2]; - $R2 = '.$K[6].' ^ $in[3]; - $R3 = '.$K[7].' ^ $in[4]; + $R0 = $K_4 ^ $in[1]; + $R1 = $K_5 ^ $in[2]; + $R2 = $K_6 ^ $in[3]; + $R3 = $K_7 ^ $in[4]; '; for ($ki = 40, $i = 0; $i < 8; ++$i) { - $decrypt_block.= ' + $_decryptBlock.= ' $t0 = $S0[$R0 & 0xff] ^ $S1[$R0 >> 8 & 0xff] ^ $S2[$R0 >> 16 & 0xff] ^ @@ -882,9 +1291,9 @@ function _setupInlineCrypt() $S1[$R1 & 0xff] ^ $S2[$R1 >> 8 & 0xff] ^ $S3[$R1 >> 16 & 0xff]; - $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].'; + $R3^= $t0 + ($t1 << 1) + $K_'.(--$ki).'; $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; - $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); + $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).'); $t0 = $S0[$R2 & 0xff] ^ $S1[$R2 >> 8 & 0xff] ^ @@ -894,30 +1303,361 @@ function _setupInlineCrypt() $S1[$R3 & 0xff] ^ $S2[$R3 >> 8 & 0xff] ^ $S3[$R3 >> 16 & 0xff]; - $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].'; + $R1^= $t0 + ($t1 << 1) + $K_'.(--$ki).'; $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; - $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); + $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).'); '; } - $decrypt_block.= ' - $in = pack("V4", '.$K[0].' ^ $R2, - '.$K[1].' ^ $R3, - '.$K[2].' ^ $R0, - '.$K[3].' ^ $R1); + $_decryptBlock.= ' + $in = pack("V4", $K_0 ^ $R2, + $K_1 ^ $R3, + $K_2 ^ $R0, + $K_3 ^ $R1); '; - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => '', - 'init_decrypt' => '', - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); + // Generating mode of operation code: + switch ($mode) { + case CRYPT_TWOFISH_MODE_ECB: + $encrypt = ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_encryptBlock.' + $ciphertext.= $in; + } + + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_TWOFISH_MODE_CBC: + $encrypt = ' + $ciphertext = ""; + $text = $self->_pad($text); + $plaintext_len = strlen($text); + + $in = $self->encryptIV; + + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = substr($text, $i, '.$block_size.') ^ $in; + '.$_encryptBlock.' + $ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0)); + $ciphertext_len = strlen($text); + + $iv = $self->decryptIV; + + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $block = substr($text, $i, '.$block_size.'); + '.$_decryptBlock.' + $plaintext.= $in ^ $iv; + $iv = $block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $iv; + } + + return $self->_unpad($plaintext); + '; + break; + case CRYPT_TWOFISH_MODE_CTR: + $encrypt = ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["encrypted"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["encrypted"])) { + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $buffer["encrypted"].= $in; + } + $key = $self->_string_shift($buffer["encrypted"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $key = $in; + $ciphertext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"]; + } + } + + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["ciphertext"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["ciphertext"])) { + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $buffer["ciphertext"].= $in; + } + $key = $self->_string_shift($buffer["ciphertext"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + $in = $self->_generate_xor($xor); + '.$_encryptBlock.' + $key = $in; + $plaintext.= $block ^ $key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"]; + } + } + + return $plaintext; + '; + break; + case CRYPT_TWOFISH_MODE_CFB: + $encrypt = ' + $ciphertext = ""; + $buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $iv = &$self->encryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->encryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.'; + $iv = $in ^ substr($text, $i, '.$block_size.'); + $ciphertext.= $iv; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $block = $iv ^ substr($text, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $iv = &$self->decryptIV; + $pos = &$buffer["pos"]; + } else { + $iv = $self->decryptIV; + $pos = 0; + } + $len = strlen($text); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = '.$block_size.' - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $plaintext = substr($iv, $orig_pos) ^ $text; + $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i); + } + while ($len >= '.$block_size.') { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $cb = substr($text, $i, '.$block_size.'); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= '.$block_size.'; + $i+= '.$block_size.'; + } + if ($len) { + $in = $iv; + '.$_encryptBlock.' + $iv = $in; + $plaintext.= $iv ^ substr($text, $i); + $iv = substr_replace($iv, substr($text, $i), 0, $len); + $pos = $len; + } + + return $plaintext; + '; + break; + case CRYPT_TWOFISH_MODE_OFB: + $encrypt = ' + $ciphertext = ""; + $plaintext_len = strlen($text); + $xor = $self->encryptIV; + $buffer = &$self->enbuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $xor; + if ($start = $plaintext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $ciphertext; + '; + + $decrypt = ' + $plaintext = ""; + $ciphertext_len = strlen($text); + $xor = $self->decryptIV; + $buffer = &$self->debuffer; + + if (strlen($buffer["xor"])) { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $block = substr($text, $i, '.$block_size.'); + if (strlen($block) > strlen($buffer["xor"])) { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $buffer["xor"].= $xor; + } + $key = $self->_string_shift($buffer["xor"]); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') { + $in = $xor; + '.$_encryptBlock.' + $xor = $in; + $plaintext.= substr($text, $i, '.$block_size.') ^ $xor; + } + $key = $xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $xor; + if ($start = $ciphertext_len % '.$block_size.') { + $buffer["xor"] = substr($key, $start) . $buffer["xor"]; + } + } + return $plaintext; + '; + break; + } + $fnc_head = '$action, &$self, $text'; + $fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'; + + if (function_exists('create_function') && is_callable('create_function')) { + $lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body); + } else { + eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }'); + } } $this->inline_crypt = $lambda_functions[$code_hash]; } + + /** + * Holds the lambda_functions table (classwide) + * + * @see inline_crypt_setup() + * @return Array + * @access private + */ + function &get_lambda_functions() + { + static $functions = array(); + return $functions; + } } // vim: ts=4:sw=4:et: diff --git a/core/src/plugins/access.sftp_psl/phpseclib/Math/BigInteger.php b/core/src/plugins/access.sftp_psl/phpseclib/Math/BigInteger.php index ddbfb65e2c..3837e8b786 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/Math/BigInteger.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/Math/BigInteger.php @@ -3147,7 +3147,6 @@ function randomPrime($min = false, $max = false, $timeout = false) // gmp_nextprime() requires PHP 5 >= 5.2.0 per . if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { - $p = new Math_BigInteger(); $p->value = gmp_nextprime($x->value); if ($p->compare($max) <= 0) { diff --git a/core/src/plugins/access.sftp_psl/phpseclib/SFTP.php b/core/src/plugins/access.sftp_psl/phpseclib/SFTP.php index cd5ce96b0b..0b99225f01 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/SFTP.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/SFTP.php @@ -97,20 +97,16 @@ /** * Reads data from a local file. */ -define('NET_SFTP_LOCAL_FILE', 1); +define('NET_SFTP_LOCAL_FILE', 1); /** * Reads data from a string. */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons -define('NET_SFTP_STRING', 2); +define('NET_SFTP_STRING', 2); /** * Resumes an upload */ -define('NET_SFTP_RESUME', 4); -/** - * Append a local file to an already existing remote file - */ -define('NET_SFTP_RESUME_START', 8); +define('NET_SFTP_RESUME', 4); /**#@-*/ /** @@ -653,7 +649,19 @@ function chdir($dir) return false; } - if (!$this->_close_handle($handle)) { + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); return false; } @@ -785,7 +793,21 @@ function _list($dir, $raw = true, $realpath = true) } } - if (!$this->_close_handle($handle)) { + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + // "The client MUST release all resources associated with the handle regardless of the status." + // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); return false; } @@ -1065,7 +1087,25 @@ function touch($filename, $time = NULL, $atime = NULL) $response = $this->_get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: - return $this->_close_handle(substr($response, 4)); + $handle = substr($response, 4); + + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + return true; case NET_SFTP_STATUS: $this->_logError($response); break; @@ -1414,33 +1454,19 @@ function rmdir($dir) * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * - * $mode can take an additional two parameters - NET_SFTP_RESUME and NET_SFTP_RESUME_START. These are bitwise AND'd with - * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following: - * - * NET_SFTP_LOCAL_FILE | NET_SFTP_RESUME - * - * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace - * NET_SFTP_RESUME with NET_SFTP_RESUME start. - * - * If $mode & (NET_SFTP_RESUME | NET_SFTP_RESUME_START) then NET_SFTP_RESUME_START will be assumed. - * - * $start and $local_start give you more fine grained control over this process and take precident over NET_SFTP_RESUME* - * when they're non-negative. ie. $start could let you write at the end of a file (like NET_SFTP_RESUME) or in the middle - * of one. $local_start could let you start your reading from the end of a file (like NET_SFTP_RESUME_START) or in the - * middle of one. - * - * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. + * As for $start... if it's negative (which it is by default) a new file will be created or an existing + * file truncated depending on $mode | NET_SFTP_RESUME. If it's zero or positive it'll be updated at that + * spot. * * @param String $remote_file * @param String $data * @param optional Integer $mode * @param optional Integer $start - * @param optional Integer $local_start * @return Boolean * @access public * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). */ - function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1) + function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1456,16 +1482,19 @@ function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_s // in practice, it doesn't seem to do that. //$flags|= ($mode & NET_SFTP_RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE; - if ($start >= 0) { - $offset = $start; - } elseif ($mode & NET_SFTP_RESUME) { - // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called - $size = $this->_size($remote_file); - $offset = $size !== false ? $size : 0; + // if NET_SFTP_OPEN_APPEND worked as it should the following (up until the -----------) wouldn't be necessary + $offset = 0; + if (($mode & NET_SFTP_RESUME) || $start >= 0) { + if ($start >= 0) { + $offset = $start; + } else { + $size = $this->_size($remote_file); + $offset = $size !== false ? $size : 0; + } } else { - $offset = 0; $flags|= NET_SFTP_OPEN_TRUNCATE; } + // -------------- $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0); if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { @@ -1498,14 +1527,6 @@ function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_s return false; } $size = filesize($data); - - if ($local_start >= 0) { - fseek($fp, $local_start); - } elseif ($mode & NET_SFTP_RESUME_START) { - // do nothing - } else { - fseek($fp, $offset); - } } else { $size = strlen($data); } @@ -1537,10 +1558,6 @@ function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_s } if (!$this->_read_put_responses($i)) { - if ($mode & NET_SFTP_LOCAL_FILE) { - fclose($fp); - } - $this->_close_handle($handle); return false; } @@ -1548,7 +1565,23 @@ function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_s fclose($fp); } - return $this->_close_handle($handle); + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + return true; } /** @@ -1580,36 +1613,6 @@ function _read_put_responses($i) return $i < 0; } - /** - * Close handle - * - * @param String $handle - * @return Boolean - * @access private - */ - function _close_handle($handle) - { - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - // "The client MUST release all resources associated with the handle regardless of the status." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; - } - /** * Downloads a file from the SFTP server. * @@ -1714,7 +1717,28 @@ function get($remote_file, $local_file = false, $offset = 0, $length = -1) fclose($fp); } - return $this->_close_handle($handle); + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + // if $content isn't set that means a file was written to + if (isset($content)) { + return $content; + } + + return true; } /** diff --git a/core/src/plugins/access.sftp_psl/phpseclib/SSH2.php b/core/src/plugins/access.sftp_psl/phpseclib/SSH2.php index f2bde0e571..c82d4d81b7 100644 --- a/core/src/plugins/access.sftp_psl/phpseclib/SSH2.php +++ b/core/src/plugins/access.sftp_psl/phpseclib/SSH2.php @@ -2694,13 +2694,6 @@ function _get_channel_packet($client_channel, $skip_extended = false) if ($length) { $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); } - - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; - - break; case 'exit-status': extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); $this->exit_status = $exit_status; @@ -2710,8 +2703,6 @@ function _get_channel_packet($client_channel, $skip_extended = false) $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; - - break; default: // "Some systems may not implement signals, in which case they SHOULD ignore this message." // -- http://tools.ietf.org/html/rfc4254#section-6.9